Compare commits
1 Commits
1.9-dev
...
amxmodx-0.
Author | SHA1 | Date | |
---|---|---|---|
a59c659d47 |
24
.gitattributes
vendored
24
.gitattributes
vendored
@ -1,24 +0,0 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
# Tell GitHub that these files are SourcePawn
|
|
||||||
*.inc text linguist-language=sourcepawn
|
|
||||||
*.sma text linguist-language=sourcepawn
|
|
||||||
|
|
||||||
# Custom for Visual Studio
|
|
||||||
*.cs diff=csharp
|
|
||||||
|
|
||||||
# Sources
|
|
||||||
*.C text
|
|
||||||
*.cc text
|
|
||||||
*.cxx text
|
|
||||||
*.cpp text
|
|
||||||
*.c++ text
|
|
||||||
*.hpp text
|
|
||||||
*.h text
|
|
||||||
*.h++ text
|
|
||||||
*.hh text
|
|
||||||
|
|
||||||
# Compiled Object files
|
|
||||||
*.o binary
|
|
||||||
*.obj binary
|
|
74
.github/CONTRIBUTING.md
vendored
74
.github/CONTRIBUTING.md
vendored
@ -1,74 +0,0 @@
|
|||||||
# Contributing to AMX Mod X
|
|
||||||
|
|
||||||
## 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 AMX Mod X, or for issues with specific, third-party AMX Mod X plugins or extensions.
|
|
||||||
|
|
||||||
For help with AMX Mod X, please consult the [AlliedModders forums](https://forums.alliedmods.net/forumdisplay.php?f=3). Similarly, for assistance with, or to report issues with, third-party AMX Mod X 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=3).
|
|
||||||
|
|
||||||
#### 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 versions (full x.y.z.a version number) of Metamod and AMX Mod X 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.
|
|
25
.github/ISSUE_TEMPLATE.md
vendored
25
.github/ISSUE_TEMPLATE.md
vendored
@ -1,25 +0,0 @@
|
|||||||
# Help us help you
|
|
||||||
- [ ] I have checked that my issue [doesn't exist yet](https://github.com/alliedmodders/amxmodx/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 AMX Mod X version:
|
|
||||||
* Current Metamod version:
|
|
||||||
- [ ] I have updated AMX Mod X to the [latest version](https://www.amxmodx.org/downloads.php) and it still happens.
|
|
||||||
- [ ] I have updated AMX Mod X to the [latest snapshot](https://www.amxmodx.org/snapshots.php) and it still happens.
|
|
||||||
- [ ] I have updated Metamod to the [latest version](https://www.amxmodx.org/downloads.php) and it still happens.
|
|
||||||
|
|
||||||
# Description
|
|
||||||
|
|
||||||
|
|
||||||
# Problematic Code (or Steps to Reproduce)
|
|
||||||
```PAWN
|
|
||||||
// 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.
|
|
90
.gitignore
vendored
90
.gitignore
vendored
@ -1,90 +0,0 @@
|
|||||||
# Binaries
|
|
||||||
*.dll
|
|
||||||
*.exe
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
|
||||||
[Rr]elease/
|
|
||||||
JITDebug/
|
|
||||||
JITRelease/
|
|
||||||
JITDebugBinLog/
|
|
||||||
JITReleaseBinLog/
|
|
||||||
x64/
|
|
||||||
build/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
build/
|
|
||||||
obj-*/
|
|
||||||
|
|
||||||
# Visual Studio 2015 cache/options directory
|
|
||||||
.vs/
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*.log
|
|
||||||
*.vspscc
|
|
||||||
*.vssscc
|
|
||||||
.builds
|
|
||||||
*.pidb
|
|
||||||
*.log
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file to a newer
|
|
||||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
|
|
||||||
# Files generated by Mac OS X Finder
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Files generated by Windows Explorer
|
|
||||||
Desktop.ini
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# AMXX plugin build related files
|
|
||||||
plugins/compile.dat
|
|
||||||
plugins/compiled/
|
|
||||||
*.amx
|
|
||||||
*.amxx
|
|
||||||
|
|
||||||
build_deps/
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "public/amtl"]
|
|
||||||
path = public/amtl
|
|
||||||
url = https://github.com/alliedmodders/amtl
|
|
27
.travis.yml
27
.travis.yml
@ -1,27 +0,0 @@
|
|||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- clang-3.7
|
|
||||||
- lib32stdc++6
|
|
||||||
- lib32z1-dev
|
|
||||||
- libc6-dev-i386
|
|
||||||
- linux-libc-dev
|
|
||||||
- gcc-multilib
|
|
||||||
- g++-multilib
|
|
||||||
- nasm
|
|
||||||
sources:
|
|
||||||
- llvm-toolchain-precise-3.7
|
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
language: cpp
|
|
||||||
sudo: false
|
|
||||||
compiler:
|
|
||||||
- clang
|
|
||||||
before_script:
|
|
||||||
- CHECKOUT_DIR=$PWD && cd ..
|
|
||||||
- chmod a+x $CHECKOUT_DIR/support/checkout-deps.sh
|
|
||||||
- $CHECKOUT_DIR/support/checkout-deps.sh && cd $CHECKOUT_DIR
|
|
||||||
script:
|
|
||||||
- mkdir build && cd build
|
|
||||||
- PATH="~/.local/bin:$PATH"
|
|
||||||
- CC=clang-3.7 CXX=clang-3.7 python ../configure.py --enable-optimize
|
|
||||||
- ambuild
|
|
508
AMBuildScript
508
AMBuildScript
@ -1,508 +0,0 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python :
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import locale
|
|
||||||
|
|
||||||
class AMXXConfig(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.binaries = []
|
|
||||||
self.modules = []
|
|
||||||
self.plugins = {}
|
|
||||||
self.libpc300 = None
|
|
||||||
self.amxxpc = None
|
|
||||||
self.metamod_path = None
|
|
||||||
self.hlsdk_path = None
|
|
||||||
self.mysql_path = None
|
|
||||||
self.generated_headers = []
|
|
||||||
self.versionlib = None
|
|
||||||
self.zlib = None
|
|
||||||
self.hashing = None
|
|
||||||
self.utf8rewind = None
|
|
||||||
self.csx_app = None
|
|
||||||
self.stdcxx_path = None
|
|
||||||
self.nasm_path = None
|
|
||||||
|
|
||||||
def use_auto_versioning(self):
|
|
||||||
if builder.backend != 'amb2':
|
|
||||||
return False
|
|
||||||
return not getattr(builder.options, 'disable_auto_versioning', False)
|
|
||||||
|
|
||||||
def detectProductVersion(self):
|
|
||||||
builder.AddConfigureFile('product.version')
|
|
||||||
|
|
||||||
# For OS X dylib versioning
|
|
||||||
import re
|
|
||||||
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
|
|
||||||
productContents = fp.read()
|
|
||||||
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
|
|
||||||
if m == None:
|
|
||||||
self.productVersion = '1.0.0'
|
|
||||||
else:
|
|
||||||
major, minor, release = m.groups()
|
|
||||||
self.productVersion = '{0}.{1}.{2}'.format(major, minor, release)
|
|
||||||
|
|
||||||
def detectMetamod(self):
|
|
||||||
metamod_path = builder.options.metamod_path
|
|
||||||
if not len(metamod_path):
|
|
||||||
metamod_path = os.getenv('METAMOD', '')
|
|
||||||
|
|
||||||
if len(metamod_path):
|
|
||||||
self.metamod_path = os.path.join(builder.originalCwd, metamod_path)
|
|
||||||
if not os.path.exists(os.path.join(self.metamod_path, 'metamod')):
|
|
||||||
raise Exception('Metamod path does not exist: {0}'.format(metamod_path))
|
|
||||||
else:
|
|
||||||
try_paths = [
|
|
||||||
os.path.join(builder.sourcePath, '..', 'metamod'),
|
|
||||||
os.path.join(builder.sourcePath, '..', 'metamod-am'),
|
|
||||||
os.path.join(builder.sourcePath, '..', 'metamod-hl1'),
|
|
||||||
]
|
|
||||||
for try_path in try_paths:
|
|
||||||
if os.path.exists(os.path.join(try_path, 'metamod')):
|
|
||||||
self.metamod_path = os.path.normpath(try_path)
|
|
||||||
break
|
|
||||||
if not self.metamod_path:
|
|
||||||
raise Exception('Could not find the source code to Metamod! Try passing --metamod to configure.py.')
|
|
||||||
|
|
||||||
def detectHlsdk(self):
|
|
||||||
hlsdk_path = builder.options.hlsdk_path
|
|
||||||
if not len(hlsdk_path):
|
|
||||||
hlsdk_path = os.getenv('HLSDK', '')
|
|
||||||
|
|
||||||
if len(hlsdk_path):
|
|
||||||
self.hlsdk_path = os.path.join(builder.originalCwd, hlsdk_path)
|
|
||||||
if not os.path.exists(self.hlsdk_path):
|
|
||||||
raise Exception('HLSDK path does not exist: {0}'.format(hlsdk_path))
|
|
||||||
else:
|
|
||||||
try_paths = [
|
|
||||||
os.path.join(builder.sourcePath, '..', 'hlsdk'),
|
|
||||||
]
|
|
||||||
for try_path in try_paths:
|
|
||||||
if os.path.exists(try_path):
|
|
||||||
self.hlsdk_path = os.path.normpath(try_path)
|
|
||||||
break
|
|
||||||
if not self.hlsdk_path:
|
|
||||||
raise Exception('Could not find the HLSDK! Try passing --hlsdk to configure.py.')
|
|
||||||
|
|
||||||
def detectMysql(self):
|
|
||||||
if builder.options.disable_mysql:
|
|
||||||
return
|
|
||||||
|
|
||||||
mysql_path = builder.options.mysql_path
|
|
||||||
if not len(mysql_path):
|
|
||||||
mysql_path = os.getenv('MYSQL55', '')
|
|
||||||
|
|
||||||
if len(mysql_path):
|
|
||||||
self.mysql_path = os.path.join(builder.originalCwd, mysql_path)
|
|
||||||
if not os.path.exists(self.mysql_path):
|
|
||||||
raise Exception('MySQL path does not exist: {0}'.format(mysql_path))
|
|
||||||
else:
|
|
||||||
try_paths = [
|
|
||||||
os.path.join(builder.sourcePath, '..', 'mysql-5.5'),
|
|
||||||
]
|
|
||||||
for try_path in try_paths:
|
|
||||||
if os.path.exists(try_path):
|
|
||||||
self.mysql_path = os.path.normpath(try_path)
|
|
||||||
break
|
|
||||||
if not self.mysql_path:
|
|
||||||
raise Exception('Could not find MySQL! Try passing --mysql to configure.py.')
|
|
||||||
|
|
||||||
def detectNASM(self):
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
nasm_paths = [
|
|
||||||
getattr(builder.options, 'nasm_path', 'nasm'),
|
|
||||||
]
|
|
||||||
if builder.target_platform == 'windows':
|
|
||||||
nasm_paths += [os.path.join(
|
|
||||||
builder.sourcePath,
|
|
||||||
'build_deps',
|
|
||||||
'nasm',
|
|
||||||
'nasm.exe')
|
|
||||||
]
|
|
||||||
|
|
||||||
for nasm_path in nasm_paths:
|
|
||||||
try:
|
|
||||||
subprocess.check_output([nasm_path, '-v'])
|
|
||||||
self.nasm_path = nasm_path
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if self.nasm_path is None:
|
|
||||||
raise Exception('Could not find a suitable path for nasm')
|
|
||||||
|
|
||||||
# Returns list of lines of output from the compiler
|
|
||||||
@staticmethod
|
|
||||||
def invokeCompiler(args):
|
|
||||||
if builder.compiler:
|
|
||||||
p = subprocess.Popen(builder.compiler.argv + args, stdout=subprocess.PIPE)
|
|
||||||
output = p.communicate()[0]
|
|
||||||
if hasattr(output,'encoding') and output.encoding is not None:
|
|
||||||
encoding = output.encoding
|
|
||||||
else:
|
|
||||||
encoding = locale.getpreferredencoding()
|
|
||||||
return output.decode(encoding, 'replace').split('\n')
|
|
||||||
return None
|
|
||||||
|
|
||||||
def configure(self):
|
|
||||||
builder.AddConfigureFile('pushbuild.txt')
|
|
||||||
|
|
||||||
cxx = builder.DetectCompilers()
|
|
||||||
|
|
||||||
if cxx.like('gcc'):
|
|
||||||
self.configure_gcc(cxx)
|
|
||||||
elif cxx.like('msvc'):
|
|
||||||
self.configure_msvc(cxx)
|
|
||||||
|
|
||||||
# Optimization
|
|
||||||
if builder.options.opt == '1':
|
|
||||||
cxx.defines += ['NDEBUG']
|
|
||||||
|
|
||||||
# Debugging
|
|
||||||
if builder.options.debug == '1':
|
|
||||||
cxx.defines += ['DEBUG', '_DEBUG']
|
|
||||||
|
|
||||||
# Platform-specifics
|
|
||||||
if builder.target_platform == 'linux':
|
|
||||||
self.configure_linux(cxx)
|
|
||||||
elif builder.target_platform == 'mac':
|
|
||||||
self.configure_mac(cxx)
|
|
||||||
elif builder.target_platform == 'windows':
|
|
||||||
self.configure_windows(cxx)
|
|
||||||
|
|
||||||
# Finish up.
|
|
||||||
cxx.defines += [
|
|
||||||
'AMX_NOPROPLIST',
|
|
||||||
'PAWN_CELL_SIZE=32',
|
|
||||||
'AMXMODX_BUILD',
|
|
||||||
'AMXX_USE_VERSIONLIB',
|
|
||||||
]
|
|
||||||
|
|
||||||
if self.use_auto_versioning():
|
|
||||||
cxx.defines += ['AMXX_GENERATED_BUILD']
|
|
||||||
cxx.includes += [os.path.join(builder.buildPath, 'includes')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'support', 'versionlib')]
|
|
||||||
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'public')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'public', 'sdk')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'public', 'amtl')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'public', 'amtl', 'amtl')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'public', 'memtools')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'third_party')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'third_party', 'hashing')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'third_party', 'zlib')]
|
|
||||||
cxx.includes += [os.path.join(builder.sourcePath, 'third_party', 'utf8rewind')]
|
|
||||||
|
|
||||||
def configure_gcc(self, cxx):
|
|
||||||
cxx.cflags += [
|
|
||||||
'-pipe',
|
|
||||||
'-fno-strict-aliasing',
|
|
||||||
'-Wall',
|
|
||||||
'-Werror',
|
|
||||||
'-Wno-uninitialized',
|
|
||||||
'-Wno-unused',
|
|
||||||
'-Wno-switch',
|
|
||||||
'-Wno-format',
|
|
||||||
'-Wno-format-security',
|
|
||||||
'-m32',
|
|
||||||
]
|
|
||||||
cxx.cxxflags += [
|
|
||||||
'-Wno-invalid-offsetof',
|
|
||||||
'-std=c++11',
|
|
||||||
]
|
|
||||||
|
|
||||||
cxx.linkflags += ['-m32']
|
|
||||||
|
|
||||||
have_gcc = cxx.vendor == 'gcc'
|
|
||||||
have_clang = cxx.vendor == 'clang'
|
|
||||||
|
|
||||||
if have_clang or (have_gcc and cxx.version >= '4'):
|
|
||||||
cxx.cflags += ['-fvisibility=hidden']
|
|
||||||
cxx.cxxflags += ['-fvisibility-inlines-hidden']
|
|
||||||
if have_clang or (have_gcc and cxx.version >= '4.6'):
|
|
||||||
cxx.cflags += ['-Wno-narrowing']
|
|
||||||
if (have_gcc and cxx.version >= '4.7') or (have_clang and cxx.version >= '3'):
|
|
||||||
cxx.cxxflags += ['-Wno-delete-non-virtual-dtor']
|
|
||||||
if have_gcc and cxx.version >= '4.8':
|
|
||||||
cxx.cflags += ['-Wno-unused-result', '-Wno-error=sign-compare']
|
|
||||||
if have_clang:
|
|
||||||
cxx.cxxflags += ['-Wno-implicit-exception-spec-mismatch']
|
|
||||||
if cxx.version >= 'apple-clang-10.0':
|
|
||||||
cxx.cxxflags += [
|
|
||||||
'-Wno-inconsistent-missing-override',
|
|
||||||
'-Wno-varargs',
|
|
||||||
]
|
|
||||||
if cxx.version >= 'apple-clang-5.1' or cxx.version >= 'clang-3.4':
|
|
||||||
cxx.cxxflags += ['-Wno-deprecated-register']
|
|
||||||
else:
|
|
||||||
cxx.cxxflags += ['-Wno-deprecated']
|
|
||||||
cxx.cflags += ['-Wno-sometimes-uninitialized']
|
|
||||||
if builder.target_platform == 'linux' and cxx.version >= '3.6':
|
|
||||||
cxx.cxxflags += ['-Wno-inconsistent-missing-override']
|
|
||||||
if builder.target_platform == 'linux' and cxx.version >= '3.9':
|
|
||||||
cxx.cxxflags += ['-Wno-varargs']
|
|
||||||
if builder.target_platform == 'linux' and cxx.version >= '4.0':
|
|
||||||
cxx.cxxflags += ['-Wno-address-of-packed-member']
|
|
||||||
|
|
||||||
if have_gcc:
|
|
||||||
cxx.cflags += ['-Wno-parentheses']
|
|
||||||
cxx.c_only_flags += ['-std=c99']
|
|
||||||
elif have_clang:
|
|
||||||
cxx.cflags += ['-Wno-logical-op-parentheses']
|
|
||||||
|
|
||||||
cxx.cxxflags += [
|
|
||||||
'-fno-exceptions',
|
|
||||||
'-fno-rtti',
|
|
||||||
]
|
|
||||||
|
|
||||||
if builder.options.opt == '1':
|
|
||||||
cxx.cflags += ['-O2']
|
|
||||||
|
|
||||||
def configure_msvc(self, cxx):
|
|
||||||
if builder.options.debug == '1':
|
|
||||||
cxx.cflags += ['/MTd']
|
|
||||||
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
|
|
||||||
else:
|
|
||||||
cxx.cflags += ['/MT']
|
|
||||||
|
|
||||||
cxx.defines += [
|
|
||||||
'_CRT_SECURE_NO_DEPRECATE',
|
|
||||||
'_CRT_SECURE_NO_WARNINGS',
|
|
||||||
'_CRT_NONSTDC_NO_DEPRECATE',
|
|
||||||
'_ITERATOR_DEBUG_LEVEL=0',
|
|
||||||
]
|
|
||||||
cxx.cflags += [
|
|
||||||
'/W3',
|
|
||||||
]
|
|
||||||
cxx.cxxflags += [
|
|
||||||
'/EHsc',
|
|
||||||
'/GR-',
|
|
||||||
'/TP',
|
|
||||||
]
|
|
||||||
cxx.linkflags += [
|
|
||||||
'/MACHINE:X86',
|
|
||||||
'/SUBSYSTEM:WINDOWS',
|
|
||||||
'kernel32.lib',
|
|
||||||
'user32.lib',
|
|
||||||
'gdi32.lib',
|
|
||||||
'winspool.lib',
|
|
||||||
'comdlg32.lib',
|
|
||||||
'advapi32.lib',
|
|
||||||
'shell32.lib',
|
|
||||||
'ole32.lib',
|
|
||||||
'oleaut32.lib',
|
|
||||||
'uuid.lib',
|
|
||||||
'odbc32.lib',
|
|
||||||
'odbccp32.lib',
|
|
||||||
]
|
|
||||||
|
|
||||||
if cxx.version >= 1900:
|
|
||||||
cxx.linkflags += ['legacy_stdio_definitions.lib', 'legacy_stdio_wide_specifiers.lib']
|
|
||||||
|
|
||||||
if builder.options.opt == '1':
|
|
||||||
cxx.cflags += ['/Ox']
|
|
||||||
cxx.linkflags += ['/OPT:ICF', '/OPT:REF']
|
|
||||||
|
|
||||||
if builder.options.debug == '1':
|
|
||||||
cxx.cflags += ['/Od', '/RTC1']
|
|
||||||
|
|
||||||
# This needs to be after our optimization flags which could otherwise disable it.
|
|
||||||
# Don't omit the frame pointer.
|
|
||||||
cxx.cflags += ['/Oy-']
|
|
||||||
|
|
||||||
def configure_linux(self, cxx):
|
|
||||||
cxx.defines += ['_LINUX', 'POSIX', 'LINUX']
|
|
||||||
cxx.linkflags += ['-ldl', '-lm']
|
|
||||||
if cxx.vendor == 'gcc':
|
|
||||||
cxx.linkflags += ['-static-libgcc']
|
|
||||||
elif cxx.vendor == 'clang':
|
|
||||||
cxx.linkflags += ['-lgcc_eh']
|
|
||||||
if cxx.like('gcc'):
|
|
||||||
self.stdcxx_path = self.invokeCompiler(['-m32', '-print-file-name=' + 'libstdc++.a'])[0]
|
|
||||||
|
|
||||||
def configure_mac(self, cxx):
|
|
||||||
cxx.defines += ['OSX', '_OSX', 'POSIX']
|
|
||||||
cxx.cflags += [
|
|
||||||
'-mmacosx-version-min=10.7',
|
|
||||||
'-Wno-address-of-packed-member',
|
|
||||||
]
|
|
||||||
cxx.linkflags += [
|
|
||||||
'-mmacosx-version-min=10.7',
|
|
||||||
'-arch', 'i386',
|
|
||||||
'-lstdc++',
|
|
||||||
'-stdlib=libc++',
|
|
||||||
'-framework', 'CoreServices',
|
|
||||||
]
|
|
||||||
cxx.cxxflags += ['-stdlib=libc++']
|
|
||||||
|
|
||||||
def configure_windows(self, cxx):
|
|
||||||
cxx.defines += ['WIN32', '_WINDOWS']
|
|
||||||
|
|
||||||
#
|
|
||||||
# Low-level compiler and binary construction.
|
|
||||||
#
|
|
||||||
|
|
||||||
def ConfigureForModule(self, context, compiler):
|
|
||||||
compiler.cxxincludes += [
|
|
||||||
os.path.join(context.currentSourcePath),
|
|
||||||
os.path.join(context.currentSourcePath, 'sdk'),
|
|
||||||
os.path.join(self.metamod_path, 'metamod'),
|
|
||||||
os.path.join(self.hlsdk_path, 'common'),
|
|
||||||
os.path.join(self.hlsdk_path, 'dlls'),
|
|
||||||
os.path.join(self.hlsdk_path, 'engine'),
|
|
||||||
os.path.join(self.hlsdk_path, 'game_shared'),
|
|
||||||
os.path.join(self.hlsdk_path, 'public'),
|
|
||||||
os.path.join(self.hlsdk_path, 'pm_shared'),
|
|
||||||
]
|
|
||||||
return compiler
|
|
||||||
|
|
||||||
def AddVersioning(self, binary):
|
|
||||||
if builder.target_platform == 'windows':
|
|
||||||
binary.compiler.rcdefines += [
|
|
||||||
'BINARY_NAME="{0}"'.format(binary.outputFile),
|
|
||||||
'RC_COMPILE',
|
|
||||||
]
|
|
||||||
if self.use_auto_versioning():
|
|
||||||
binary.compiler.rcdefines += ['AMXX_GENERATED_BUILD']
|
|
||||||
elif builder.target_platform == 'mac':
|
|
||||||
if binary.type == 'library':
|
|
||||||
binary.compiler.postlink += [
|
|
||||||
'-compatibility_version', '1.0.0',
|
|
||||||
'-current_version', self.productVersion
|
|
||||||
]
|
|
||||||
if self.use_auto_versioning():
|
|
||||||
binary.compiler.linkflags += [self.versionlib]
|
|
||||||
binary.compiler.sourcedeps += AMXX.generated_headers
|
|
||||||
return binary
|
|
||||||
|
|
||||||
#
|
|
||||||
# High level job construction for libraries, metamod plugins, modules, and
|
|
||||||
# executables.
|
|
||||||
#
|
|
||||||
|
|
||||||
def Library(self, context, name):
|
|
||||||
binary = context.compiler.Library(name)
|
|
||||||
return self.AddVersioning(binary)
|
|
||||||
|
|
||||||
def MetaPlugin(self, context, name):
|
|
||||||
if builder.target_platform == 'mac' or builder.target_platform == 'windows':
|
|
||||||
name = name + '_mm'
|
|
||||||
elif builder.target_platform == 'linux':
|
|
||||||
name = name + '_mm_i386'
|
|
||||||
binary = context.compiler.Library(name)
|
|
||||||
self.ConfigureForModule(context, binary.compiler)
|
|
||||||
return self.AddVersioning(binary)
|
|
||||||
|
|
||||||
def MetaModule(self, context, name):
|
|
||||||
if builder.target_platform == 'mac' or builder.target_platform == 'windows':
|
|
||||||
name = name + '_amxx'
|
|
||||||
elif builder.target_platform == 'linux':
|
|
||||||
name = name + '_amxx_i386'
|
|
||||||
binary = context.compiler.Library(name)
|
|
||||||
self.ConfigureForModule(context, binary.compiler)
|
|
||||||
return self.AddVersioning(binary)
|
|
||||||
|
|
||||||
def Program(self, context, name):
|
|
||||||
binary = context.compiler.Program(name)
|
|
||||||
return self.AddVersioning(binary)
|
|
||||||
|
|
||||||
def AddAssembly(self, context, binary, input_file, output_file, includes=[], extra_argv=[]):
|
|
||||||
if builder.target_platform == 'windows':
|
|
||||||
obj_type = 'win32'
|
|
||||||
elif builder.target_platform == 'linux':
|
|
||||||
obj_type = 'elf32'
|
|
||||||
elif builder.target_platform == 'mac':
|
|
||||||
obj_type = 'macho32'
|
|
||||||
|
|
||||||
input_path = os.path.join(context.currentSourcePath, input_file)
|
|
||||||
output_path = output_file
|
|
||||||
|
|
||||||
argv = [
|
|
||||||
self.nasm_path,
|
|
||||||
'-I{0}{1}'.format(context.currentSourcePath, os.sep),
|
|
||||||
input_path,
|
|
||||||
'-f', obj_type,
|
|
||||||
'-o', output_path,
|
|
||||||
] + extra_argv
|
|
||||||
|
|
||||||
extra_includes = []
|
|
||||||
for include_file in includes:
|
|
||||||
extra_includes.append(os.path.join(context.currentSourcePath, include_file))
|
|
||||||
|
|
||||||
cmd_node, output_nodes = context.AddCommand(
|
|
||||||
inputs = [input_path] + extra_includes,
|
|
||||||
argv = argv,
|
|
||||||
outputs = [output_path])
|
|
||||||
|
|
||||||
binary.compiler.linkflags += [output_nodes[0]]
|
|
||||||
|
|
||||||
AMXX = AMXXConfig()
|
|
||||||
AMXX.detectProductVersion()
|
|
||||||
AMXX.detectMetamod()
|
|
||||||
AMXX.detectHlsdk()
|
|
||||||
AMXX.detectMysql()
|
|
||||||
AMXX.detectNASM()
|
|
||||||
AMXX.configure()
|
|
||||||
|
|
||||||
if AMXX.use_auto_versioning():
|
|
||||||
AMXX.generated_headers = builder.RunScript(
|
|
||||||
'support/Versioning',
|
|
||||||
{ 'AMXX': AMXX }
|
|
||||||
)
|
|
||||||
AMXX.versionlib = builder.RunScript(
|
|
||||||
'support/versionlib/AMBuilder',
|
|
||||||
{ 'AMXX': AMXX }
|
|
||||||
)
|
|
||||||
|
|
||||||
AMXX.zlib = builder.RunScript(
|
|
||||||
'third_party/zlib/AMBuilder'
|
|
||||||
)
|
|
||||||
|
|
||||||
AMXX.hashing = builder.RunScript(
|
|
||||||
'third_party/hashing/AMBuilder'
|
|
||||||
)
|
|
||||||
|
|
||||||
AMXX.utf8rewind = builder.RunScript(
|
|
||||||
'third_party/utf8rewind/AMBuilder'
|
|
||||||
)
|
|
||||||
|
|
||||||
builder.RunBuildScripts(
|
|
||||||
[
|
|
||||||
'amxmodx/AMBuilder',
|
|
||||||
'compiler/amxxpc/AMBuilder',
|
|
||||||
'compiler/libpc300/AMBuilder',
|
|
||||||
'modules/cstrike/cstrike/AMBuilder',
|
|
||||||
'modules/cstrike/csx/AMBuilder',
|
|
||||||
'modules/dod/dodfun/AMBuilder',
|
|
||||||
'modules/dod/dodx/AMBuilder',
|
|
||||||
'modules/engine/AMBuilder',
|
|
||||||
'modules/fakemeta/AMBuilder',
|
|
||||||
'modules/fun/AMBuilder',
|
|
||||||
'modules/geoip/AMBuilder',
|
|
||||||
'modules/hamsandwich/AMBuilder',
|
|
||||||
'modules/json/AMBuilder',
|
|
||||||
'modules/mysqlx/AMBuilder',
|
|
||||||
'modules/ns/AMBuilder',
|
|
||||||
'modules/nvault/AMBuilder',
|
|
||||||
'modules/regex/AMBuilder',
|
|
||||||
'modules/sockets/AMBuilder',
|
|
||||||
'modules/sqlite/AMBuilder',
|
|
||||||
'modules/tfcx/AMBuilder',
|
|
||||||
'modules/ts/tsfun/AMBuilder',
|
|
||||||
'modules/ts/tsx/AMBuilder',
|
|
||||||
],
|
|
||||||
{ 'AMXX': AMXX }
|
|
||||||
)
|
|
||||||
|
|
||||||
# The csstats.dat reader is Windows-only.
|
|
||||||
if builder.target_platform == 'windows':
|
|
||||||
builder.RunScript('modules/cstrike/csx/WinCSX/AMBuilder', { 'AMXX': AMXX })
|
|
||||||
|
|
||||||
if builder.backend == 'amb2':
|
|
||||||
builder.RunBuildScripts([
|
|
||||||
'plugins/AMBuilder',
|
|
||||||
'support/PackageScript',
|
|
||||||
],
|
|
||||||
{ 'AMXX': AMXX }
|
|
||||||
)
|
|
||||||
|
|
22
README.md
22
README.md
@ -1,22 +0,0 @@
|
|||||||
|
|
||||||
<p align="center">
|
|
||||||
<img src="https://github.com/alliedmodders/amxmodx/blob/master/editor/studio/AMXXLarge.bmp"/>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
**AMX Mod X** is a [Metamod](https://github.com/jkivilin/metamod-p) plugin for [Half-Life 1](https://github.com/ValveSoftware/halflife). It provides comprehensive scripting for the game engine and its mods. Scripts can intercept network messages, log events, commands, client commands, set cvars, modify entities, and more. AMX Mod X also has a system for extending native scripting through modules, leading to outside support for things like MySQL and Sockets.
|
|
||||||
|
|
||||||
General
|
|
||||||
-------
|
|
||||||
- [AMXX website](https://amxmodx.org/)
|
|
||||||
- [Forum](https://forums.alliedmods.net/forumdisplay.php?f=3): Discussion forum including plugin/extension development
|
|
||||||
- [General documentation](https://wiki.alliedmods.net/Category:Documentation_%28AMX_Mod_X%29): Miscellaneous information about AMXX
|
|
||||||
- [Latest release](https://amxmodx.org/downloads.php): The latest stable AMXX release
|
|
||||||
- [Build snapshots](https://www.amxmodx.org/downloads-new.php): Builds of recent development versions
|
|
||||||
|
|
||||||
Development
|
|
||||||
-----------
|
|
||||||
- [Issue tracker](https://github.com/alliedmodders/amxmodx/issues): Issues that require back and forth communication
|
|
||||||
- [Issue archive](https://bugs.alliedmods.net/describecomponents.cgi?product=AMX%20Mod%20X): Old issue tracker (read-only)
|
|
||||||
- [Building AMXX](https://wiki.alliedmods.net/Building_AMX_Mod_X): Instructions on how to build AMXX itself using [AMBuild](https://github.com/alliedmodders/ambuild)
|
|
||||||
- [AMX Mod X API](https://amxmodx.org/api/): AMX Mod X API reference generated from include files
|
|
||||||
- [AMXX scripting](https://wiki.alliedmods.net/Category:Scripting_(AMX_Mod_X)): Pawn examples and introduction to the language
|
|
@ -1,97 +0,0 @@
|
|||||||
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
binary = AMXX.MetaPlugin(builder, 'amxmodx')
|
|
||||||
|
|
||||||
binary.compiler.defines += [
|
|
||||||
'JIT',
|
|
||||||
'ASM32',
|
|
||||||
'HAVE_STDINT_H',
|
|
||||||
]
|
|
||||||
|
|
||||||
AMXX.AddAssembly(builder, binary, 'helpers-x86.asm', 'helpers-asm.obj')
|
|
||||||
AMXX.AddAssembly(builder, binary, 'natives-x86.asm', 'natives-asm.obj')
|
|
||||||
AMXX.AddAssembly(builder, binary, 'amxexecn.asm', 'amxexecn-asm.obj',
|
|
||||||
includes=['amxdefn.asm'])
|
|
||||||
AMXX.AddAssembly(builder, binary, 'amxjitsn.asm', 'amxjitsn-asm.obj',
|
|
||||||
includes=['amxdefn.asm'],
|
|
||||||
# Opcode sizes must be maximum width for patching to work.
|
|
||||||
extra_argv=['-O0'])
|
|
||||||
|
|
||||||
if builder.target_platform == 'mac':
|
|
||||||
binary.compiler.postlink += [
|
|
||||||
'-Wl,-read_only_relocs,suppress'
|
|
||||||
]
|
|
||||||
elif builder.target_platform == 'windows':
|
|
||||||
binary.compiler.linkflags += [
|
|
||||||
'/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1',
|
|
||||||
'/SECTION:.data,RW',
|
|
||||||
]
|
|
||||||
|
|
||||||
binary.compiler.linkflags += [AMXX.zlib.binary, AMXX.hashing.binary, AMXX.utf8rewind.binary]
|
|
||||||
|
|
||||||
binary.sources = [
|
|
||||||
'meta_api.cpp',
|
|
||||||
'CVault.cpp',
|
|
||||||
'vault.cpp',
|
|
||||||
'float.cpp',
|
|
||||||
'file.cpp',
|
|
||||||
'modules.cpp',
|
|
||||||
'CMisc.cpp',
|
|
||||||
'CTask.cpp',
|
|
||||||
'string.cpp',
|
|
||||||
'amxmodx.cpp',
|
|
||||||
'CEvent.cpp',
|
|
||||||
'CCmd.cpp',
|
|
||||||
'CLogEvent.cpp',
|
|
||||||
'srvcmd.cpp',
|
|
||||||
'strptime.cpp',
|
|
||||||
'amxcore.cpp',
|
|
||||||
'amxtime.cpp',
|
|
||||||
'power.cpp',
|
|
||||||
'amxxlog.cpp',
|
|
||||||
'fakemeta.cpp',
|
|
||||||
'amxxfile.cpp',
|
|
||||||
'CLang.cpp',
|
|
||||||
'emsg.cpp',
|
|
||||||
'CForward.cpp',
|
|
||||||
'CPlugin.cpp',
|
|
||||||
'CModule.cpp',
|
|
||||||
'CMenu.cpp',
|
|
||||||
'util.cpp',
|
|
||||||
'amx.cpp',
|
|
||||||
'amxdbg.cpp',
|
|
||||||
'natives.cpp',
|
|
||||||
'newmenus.cpp',
|
|
||||||
'debugger.cpp',
|
|
||||||
'optimizer.cpp',
|
|
||||||
'format.cpp',
|
|
||||||
'messages.cpp',
|
|
||||||
'libraries.cpp',
|
|
||||||
'vector.cpp',
|
|
||||||
'sorting.cpp',
|
|
||||||
'nongpl_matches.cpp',
|
|
||||||
'CFlagManager.cpp',
|
|
||||||
'datastructs.cpp',
|
|
||||||
'trie_natives.cpp',
|
|
||||||
'CDataPack.cpp',
|
|
||||||
'datapacks.cpp',
|
|
||||||
'stackstructs.cpp',
|
|
||||||
'CTextParsers.cpp',
|
|
||||||
'textparse.cpp',
|
|
||||||
'CvarManager.cpp',
|
|
||||||
'cvars.cpp',
|
|
||||||
'../public/memtools/MemoryUtils.cpp',
|
|
||||||
'../public/memtools/CDetour/detours.cpp',
|
|
||||||
'../public/memtools/CDetour/asm/asm.c',
|
|
||||||
'../public/resdk/mod_rehlds_api.cpp',
|
|
||||||
'CLibrarySys.cpp',
|
|
||||||
'CGameConfigs.cpp',
|
|
||||||
'gameconfigs.cpp',
|
|
||||||
'CoreConfig.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
if builder.target_platform == 'windows':
|
|
||||||
binary.sources += ['version.rc']
|
|
||||||
|
|
||||||
AMXX.binaries += [builder.Add(binary)]
|
|
147
amxmodx/CCmd.cpp
147
amxmodx/CCmd.cpp
@ -1,21 +1,43 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include <extdll.h>
|
||||||
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
#include "CCmd.h"
|
#include "CCmd.h"
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class CmdMngr
|
// class CmdMngr
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
CmdMngr::CmdMngr() {
|
||||||
CmdMngr::CmdMngr()
|
|
||||||
{
|
|
||||||
memset(sortedlists,0,sizeof(sortedlists));
|
memset(sortedlists,0,sizeof(sortedlists));
|
||||||
srvcmdlist = 0;
|
srvcmdlist = 0;
|
||||||
clcmdlist = 0;
|
clcmdlist = 0;
|
||||||
@ -29,21 +51,21 @@ CmdMngr::CmdMngr()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CmdMngr::Command::Command(CPluginMngr::CPlugin* pplugin, const char* pcmd, const char* pinfo, int pflags,
|
CmdMngr::Command::Command( CPluginMngr::CPlugin* pplugin,const char* pcmd,
|
||||||
int pfunc, bool pviewable, bool pinfo_ml, CmdMngr* pparent) : commandline(pcmd), info(pinfo)
|
const char* pinfo , int pflags , int pfunc,
|
||||||
{
|
bool pviewable, CmdMngr* pparent ) : commandline(pcmd) , info(pinfo) {
|
||||||
|
|
||||||
char szCmd[64], szArg[64];
|
char szCmd[64], szArg[64];
|
||||||
*szCmd = 0; *szArg=0;
|
*szCmd = 0; *szArg=0;
|
||||||
sscanf(pcmd,"%s %s",szCmd,szArg);
|
sscanf(pcmd,"%s %s",szCmd,szArg);
|
||||||
command = szCmd;
|
command.set(szCmd);
|
||||||
argument = szArg;
|
argument.set(szArg);
|
||||||
plugin = pplugin;
|
plugin = pplugin;
|
||||||
flags = pflags;
|
flags = pflags;
|
||||||
cmdtype = 0;
|
cmdtype = 0;
|
||||||
prefix = 0;
|
prefix = 0;
|
||||||
function = pfunc;
|
function = pfunc;
|
||||||
listable = pviewable;
|
listable = pviewable;
|
||||||
info_ml = pinfo_ml;
|
|
||||||
parent = pparent;
|
parent = pparent;
|
||||||
id = --uniqueid;
|
id = --uniqueid;
|
||||||
}
|
}
|
||||||
@ -53,26 +75,22 @@ CmdMngr::Command::~Command()
|
|||||||
++uniqueid;
|
++uniqueid;
|
||||||
}
|
}
|
||||||
|
|
||||||
CmdMngr::Command* CmdMngr::registerCommand(CPluginMngr::CPlugin* plugin, int func, const char* cmd, const char* info, int level, bool listable, bool info_ml)
|
CmdMngr::Command* CmdMngr::registerCommand( CPluginMngr::CPlugin* plugin , int func , char* cmd , char* info , int level , bool listable )
|
||||||
{
|
{
|
||||||
Command* b = new Command(plugin, cmd, info, level, func, listable, info_ml, this);
|
Command* b = new Command( plugin , cmd , info , level , func , listable, this );
|
||||||
if ( b == 0 ) return 0;
|
if ( b == 0 ) return 0;
|
||||||
setCmdLink( &sortedlists[0] , b );
|
setCmdLink( &sortedlists[0] , b );
|
||||||
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
CmdMngr::Command* CmdMngr::getCmd( long int id ,int type, int access )
|
CmdMngr::Command* CmdMngr::getCmd( long int id ,int type, int access )
|
||||||
{
|
{
|
||||||
//if ( id >= 1024 || id < 0 ) return (Command*)id;
|
//if ( id >= 1024 || id < 0 ) return (Command*)id;
|
||||||
if (id < 0)
|
if ( id < 0 ){
|
||||||
{
|
for (CmdMngr::iterator a = begin( type ); a ; ++a){
|
||||||
for (CmdMngr::iterator a = begin(type); a ; ++a)
|
|
||||||
{
|
|
||||||
if ( (*a).id == id )
|
if ( (*a).id == id )
|
||||||
return &(*a);
|
return &(*a);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +100,9 @@ CmdMngr::Command* CmdMngr::getCmd(long int id, int type, int access)
|
|||||||
buf_cmdaccess = access;
|
buf_cmdaccess = access;
|
||||||
buf_cmdtype = type;
|
buf_cmdtype = type;
|
||||||
buf_cmdid = id;
|
buf_cmdid = id;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
int a = id;
|
int a = id;
|
||||||
id -= buf_cmdid;
|
id -= buf_cmdid;
|
||||||
buf_cmdid = a;
|
buf_cmdid = a;
|
||||||
@ -90,11 +110,17 @@ CmdMngr::Command* CmdMngr::getCmd(long int id, int type, int access)
|
|||||||
|
|
||||||
while ( buf_cmdptr )
|
while ( buf_cmdptr )
|
||||||
{
|
{
|
||||||
if ((*buf_cmdptr).gotAccess(access) && (*buf_cmdptr).getPlugin()->isExecutable((*buf_cmdptr).getFunction()) && (*buf_cmdptr).isViewable())
|
|
||||||
|
if ( (*buf_cmdptr).gotAccess( access ) &&
|
||||||
|
(*buf_cmdptr).getPlugin()->isExecutable( (*buf_cmdptr).getFunction() )
|
||||||
|
&& (*buf_cmdptr).isViewable() )
|
||||||
{
|
{
|
||||||
|
|
||||||
if ( id-- == 0 )
|
if ( id-- == 0 )
|
||||||
return &(*buf_cmdptr);
|
return &(*buf_cmdptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
++buf_cmdptr;
|
++buf_cmdptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +129,8 @@ CmdMngr::Command* CmdMngr::getCmd(long int id, int type, int access)
|
|||||||
|
|
||||||
int CmdMngr::getCmdNum( int type, int access )
|
int CmdMngr::getCmdNum( int type, int access )
|
||||||
{
|
{
|
||||||
|
if ( (access == buf_access) && (type == buf_type) )
|
||||||
|
return buf_num; // once calculated don't have to be done again
|
||||||
|
|
||||||
buf_access = access;
|
buf_access = access;
|
||||||
buf_type = type;
|
buf_type = type;
|
||||||
@ -112,7 +140,10 @@ int CmdMngr::getCmdNum(int type, int access)
|
|||||||
|
|
||||||
while ( a )
|
while ( a )
|
||||||
{
|
{
|
||||||
if ((*a).gotAccess(access) && (*a).getPlugin()->isExecutable((*a).getFunction()) && (*a).isViewable())
|
|
||||||
|
if ( (*a).gotAccess( access ) &&
|
||||||
|
(*a).getPlugin()->isExecutable( (*a).getFunction() )
|
||||||
|
&& (*a).isViewable() )
|
||||||
++buf_num;
|
++buf_num;
|
||||||
++a;
|
++a;
|
||||||
}
|
}
|
||||||
@ -132,7 +163,7 @@ void CmdMngr::setCmdLink(CmdLink** a, Command* c, bool sorted)
|
|||||||
{
|
{
|
||||||
int i = strcmp(c->getCommand(),(*a)->cmd->getCommand() );
|
int i = strcmp(c->getCommand(),(*a)->cmd->getCommand() );
|
||||||
|
|
||||||
if ((i < 0) || ((i == 0) && (strcmp(c->getArgument(), (*a)->cmd->getArgument()) < 0)))
|
if ( (i<0) || (i==0) && ( strcmp( c->getArgument() , (*a)->cmd->getArgument() ) < 0 ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
a = &(*a)->next;
|
a = &(*a)->next;
|
||||||
@ -140,18 +171,20 @@ void CmdMngr::setCmdLink(CmdLink** a, Command* c, bool sorted)
|
|||||||
|
|
||||||
np->next = *a;
|
np->next = *a;
|
||||||
*a = np;
|
*a = np;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
while ( *a ) a = &(*a)->next;
|
while ( *a ) a = &(*a)->next;
|
||||||
*a = np;
|
*a = np;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmdMngr::clearCmdLink( CmdLink** phead, bool pclear )
|
void CmdMngr::clearCmdLink( CmdLink** phead, bool pclear )
|
||||||
{
|
{
|
||||||
while (*phead)
|
while( *phead ){
|
||||||
{
|
|
||||||
CmdLink* pp = (*phead)->next;
|
CmdLink* pp = (*phead)->next;
|
||||||
|
|
||||||
if ( pclear ) delete (*phead)->cmd;
|
if ( pclear ) delete (*phead)->cmd;
|
||||||
delete *phead;
|
delete *phead;
|
||||||
*phead = pp;
|
*phead = pp;
|
||||||
@ -160,51 +193,39 @@ void CmdMngr::clearCmdLink(CmdLink** phead, bool pclear)
|
|||||||
|
|
||||||
void CmdMngr::Command::setCmdType( int a )
|
void CmdMngr::Command::setCmdType( int a )
|
||||||
{
|
{
|
||||||
switch (a)
|
switch(a){
|
||||||
{
|
|
||||||
case CMD_ConsoleCommand: cmdtype |= 3; break;
|
case CMD_ConsoleCommand: cmdtype |= 3; break;
|
||||||
case CMD_ClientCommand: cmdtype |= 1; break;
|
case CMD_ClientCommand: cmdtype |= 1; break;
|
||||||
case CMD_ServerCommand: cmdtype |= 2; break;
|
case CMD_ServerCommand: cmdtype |= 2; break;
|
||||||
}
|
}
|
||||||
|
if ( cmdtype & 1 ) { // ClientCommand
|
||||||
if (cmdtype & 1) // ClientCommand
|
|
||||||
{
|
|
||||||
parent->setCmdLink( &parent->sortedlists[1] , this );
|
parent->setCmdLink( &parent->sortedlists[1] , this );
|
||||||
|
|
||||||
if ( !parent->registerCmdPrefix( this ) )
|
if ( !parent->registerCmdPrefix( this ) )
|
||||||
parent->setCmdLink( &parent->clcmdlist , this , false );
|
parent->setCmdLink( &parent->clcmdlist , this , false );
|
||||||
}
|
}
|
||||||
|
if ( cmdtype & 2 ) { // ServerCommand
|
||||||
if (cmdtype & 2) // ServerCommand
|
|
||||||
{
|
|
||||||
parent->setCmdLink( &parent->sortedlists[2] , this );
|
parent->setCmdLink( &parent->sortedlists[2] , this );
|
||||||
parent->setCmdLink( &parent->srvcmdlist , this , false );
|
parent->setCmdLink( &parent->srvcmdlist , this , false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* CmdMngr::Command::getCmdType() const
|
const char* CmdMngr::Command::getCmdType() const {
|
||||||
{
|
switch( cmdtype ){
|
||||||
switch (cmdtype)
|
|
||||||
{
|
|
||||||
case 1: return"client";
|
case 1: return"client";
|
||||||
case 2: return "server";
|
case 2: return "server";
|
||||||
case 3: return "console";
|
case 3: return "console";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CmdMngr::registerCmdPrefix( Command* cc )
|
bool CmdMngr::registerCmdPrefix( Command* cc )
|
||||||
{
|
{
|
||||||
CmdPrefix** b = findPrefix( cc->getCommand() );
|
CmdPrefix** b = findPrefix( cc->getCommand() );
|
||||||
|
if (*b){
|
||||||
if (*b)
|
|
||||||
{
|
|
||||||
setCmdLink( &(*b)->list , cc , false );
|
setCmdLink( &(*b)->list , cc , false );
|
||||||
cc->prefix = (*b)->name.length();
|
cc->prefix = (*b)->name.size();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,29 +233,22 @@ void CmdMngr::registerPrefix(const char* nn)
|
|||||||
{
|
{
|
||||||
if ( *nn == 0 ) return;
|
if ( *nn == 0 ) return;
|
||||||
CmdPrefix** b = findPrefix( nn );
|
CmdPrefix** b = findPrefix( nn );
|
||||||
|
|
||||||
if (*b) return;
|
if (*b) return;
|
||||||
*b = new CmdPrefix( nn , this );
|
*b = new CmdPrefix( nn , this );
|
||||||
}
|
}
|
||||||
|
|
||||||
CmdMngr::CmdPrefix** CmdMngr::findPrefix(const char* nn)
|
CmdMngr::CmdPrefix** CmdMngr::findPrefix( const char* nn ){
|
||||||
{
|
|
||||||
CmdPrefix** aa = &prefixHead;
|
CmdPrefix** aa = &prefixHead;
|
||||||
|
while(*aa){
|
||||||
while (*aa)
|
if ( !strncmp( (*aa)->name.str(), nn, (*aa)->name.size() ) )
|
||||||
{
|
|
||||||
if (!strncmp((*aa)->name.chars(), nn, (*aa)->name.length()))
|
|
||||||
break;
|
break;
|
||||||
aa=&(*aa)->next;
|
aa=&(*aa)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return aa;
|
return aa;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmdMngr::clearPrefix()
|
void CmdMngr::clearPrefix(){
|
||||||
{
|
while(prefixHead){
|
||||||
while (prefixHead)
|
|
||||||
{
|
|
||||||
CmdPrefix* a = prefixHead->next;
|
CmdPrefix* a = prefixHead->next;
|
||||||
delete prefixHead;
|
delete prefixHead;
|
||||||
prefixHead = a;
|
prefixHead = a;
|
||||||
@ -252,8 +266,7 @@ void CmdMngr::clear()
|
|||||||
clearBufforedInfo();
|
clearBufforedInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmdMngr::clearBufforedInfo()
|
void CmdMngr::clearBufforedInfo() {
|
||||||
{
|
|
||||||
buf_type = -1;
|
buf_type = -1;
|
||||||
buf_access = 0;
|
buf_access = 0;
|
||||||
buf_id = -1;
|
buf_id = -1;
|
||||||
|
102
amxmodx/CCmd.h
102
amxmodx/CCmd.h
@ -1,11 +1,33 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef COMMANDS_H
|
#ifndef COMMANDS_H
|
||||||
#define COMMANDS_H
|
#define COMMANDS_H
|
||||||
@ -14,8 +36,7 @@
|
|||||||
// class CmdMngr
|
// class CmdMngr
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
CMD_ConsoleCommand,
|
CMD_ConsoleCommand,
|
||||||
CMD_ClientCommand,
|
CMD_ClientCommand,
|
||||||
CMD_ServerCommand
|
CMD_ServerCommand
|
||||||
@ -27,18 +48,14 @@ public:
|
|||||||
class Command;
|
class Command;
|
||||||
friend class Command;
|
friend class Command;
|
||||||
|
|
||||||
class Command
|
class Command {
|
||||||
{
|
|
||||||
friend class CmdMngr;
|
friend class CmdMngr;
|
||||||
|
|
||||||
CPluginMngr::CPlugin* plugin;
|
CPluginMngr::CPlugin* plugin;
|
||||||
CmdMngr* parent;
|
CmdMngr* parent;
|
||||||
ke::AString command;
|
String command;
|
||||||
ke::AString argument;
|
String argument;
|
||||||
ke::AString commandline;
|
String commandline;
|
||||||
ke::AString info;
|
String info;
|
||||||
|
|
||||||
bool info_ml;
|
|
||||||
bool listable;
|
bool listable;
|
||||||
int function;
|
int function;
|
||||||
int flags;
|
int flags;
|
||||||
@ -46,34 +63,33 @@ public:
|
|||||||
int cmdtype;
|
int cmdtype;
|
||||||
int prefix;
|
int prefix;
|
||||||
static int uniqueid;
|
static int uniqueid;
|
||||||
|
Command( CPluginMngr::CPlugin* pplugin,const char* pcmd, const char* pinfo , int pflags , int pfunc, bool pviewable, CmdMngr* pparent );
|
||||||
Command(CPluginMngr::CPlugin* pplugin, const char* pcmd, const char* pinfo, int pflags, int pfunc, bool pviewable, bool pinfo_ml, CmdMngr* pparent);
|
|
||||||
~Command();
|
~Command();
|
||||||
public:
|
public:
|
||||||
inline const char* getCommand() { return command.chars(); }
|
|
||||||
inline const char* getArgument() { return argument.chars(); }
|
inline const char* getCommand() const{ return command.str(); }
|
||||||
inline const char* getCmdInfo() { return info.chars(); }
|
inline const char* getArgument() const{ return argument.str(); }
|
||||||
inline const char* getCmdLine() { return commandline.chars(); }
|
inline const char* getCmdInfo() const{ return info.str(); }
|
||||||
inline bool matchCommandLine(const char* cmd, const char* arg) {return (!stricmp(command.chars() + prefix, cmd + prefix) && (!argument.length() || !stricmp(argument.chars(), arg)));}
|
inline const char* getCmdLine() const{ return commandline.str(); }
|
||||||
inline bool matchCommand(const char* cmd) { return (!stricmp(command.chars(), cmd)); }
|
inline bool matchCommandLine(const char* cmd, const char* arg) { return (!stricmp(command.str()+prefix, cmd+prefix ) && (argument.empty() || !stricmp(argument.str() , arg ))); }
|
||||||
|
inline bool matchCommand(const char* cmd) { return (!strcmp(command.str(), cmd )); }
|
||||||
inline int getFunction() const { return function; }
|
inline int getFunction() const { return function; }
|
||||||
inline bool gotAccess(int f) const { return (!flags || ((flags & f) != 0)); }
|
inline bool gotAccess(int f) const { return (!flags||((flags & f)==flags)); }
|
||||||
inline CPluginMngr::CPlugin* getPlugin() { return plugin; }
|
inline CPluginMngr::CPlugin* getPlugin() { return plugin; }
|
||||||
inline bool isViewable() const { return listable; }
|
inline bool isViewable() const { return listable; }
|
||||||
inline bool isInfoML() const { return info_ml; }
|
|
||||||
inline int getFlags() const { return flags; }
|
inline int getFlags() const { return flags; }
|
||||||
inline long int getId() const { return (long int)id; }
|
inline long int getId() const { return (long int)id; }
|
||||||
|
|
||||||
const char* getCmdType() const;
|
const char* getCmdType() const;
|
||||||
void setCmdType( int a );
|
void setCmdType( int a );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct CmdPrefix;
|
struct CmdPrefix;
|
||||||
friend struct CmdPrefix;
|
friend struct CmdPrefix;
|
||||||
|
|
||||||
struct CmdLink
|
struct CmdLink {
|
||||||
{
|
|
||||||
Command* cmd;
|
Command* cmd;
|
||||||
CmdLink* next;
|
CmdLink* next;
|
||||||
CmdLink(Command* c): cmd(c), next(0) {}
|
CmdLink(Command* c): cmd(c), next(0) {}
|
||||||
@ -83,10 +99,9 @@ private:
|
|||||||
CmdLink* srvcmdlist;
|
CmdLink* srvcmdlist;
|
||||||
CmdLink* clcmdlist;
|
CmdLink* clcmdlist;
|
||||||
|
|
||||||
struct CmdPrefix
|
struct CmdPrefix {
|
||||||
{
|
|
||||||
ke::AString name;
|
|
||||||
CmdMngr* parent;
|
CmdMngr* parent;
|
||||||
|
String name;
|
||||||
CmdLink* list;
|
CmdLink* list;
|
||||||
CmdPrefix* next;
|
CmdPrefix* next;
|
||||||
CmdPrefix( const char* nn , CmdMngr* pp) : name(nn),parent(pp),list(0),next(0){}
|
CmdPrefix( const char* nn , CmdMngr* pp) : name(nn),parent(pp),list(0),next(0){}
|
||||||
@ -107,16 +122,13 @@ public:
|
|||||||
// Interface
|
// Interface
|
||||||
|
|
||||||
void registerPrefix( const char* nn );
|
void registerPrefix( const char* nn );
|
||||||
|
Command* registerCommand( CPluginMngr::CPlugin* plugin , int func , char* cmd , char* info , int level , bool listable );
|
||||||
Command* registerCommand(CPluginMngr::CPlugin* plugin, int func, const char* cmd, const char* info, int level, bool listable, bool info_ml);
|
|
||||||
Command* getCmd( long int id ,int type, int access);
|
Command* getCmd( long int id ,int type, int access);
|
||||||
int getCmdNum( int type, int access );
|
int getCmdNum( int type, int access );
|
||||||
|
|
||||||
void clearBufforedInfo();
|
void clearBufforedInfo();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
class iterator
|
class iterator {
|
||||||
{
|
|
||||||
CmdLink *a;
|
CmdLink *a;
|
||||||
public:
|
public:
|
||||||
iterator(CmdLink*aa = 0) : a(aa) {}
|
iterator(CmdLink*aa = 0) : a(aa) {}
|
||||||
@ -126,30 +138,28 @@ public:
|
|||||||
operator bool () const { return a ? true : false; }
|
operator bool () const { return a ? true : false; }
|
||||||
Command& operator*() { return *a->cmd; }
|
Command& operator*() { return *a->cmd; }
|
||||||
};
|
};
|
||||||
|
inline iterator clcmdprefixbegin(const char* nn){
|
||||||
inline iterator clcmdprefixbegin(const char* nn)
|
|
||||||
{
|
|
||||||
CmdPrefix* a = *findPrefix(nn);
|
CmdPrefix* a = *findPrefix(nn);
|
||||||
return iterator( a ? a->list : 0 );
|
return iterator( a ? a->list : 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline iterator clcmdbegin() const {return iterator(clcmdlist);}
|
inline iterator clcmdbegin() const {return iterator(clcmdlist);}
|
||||||
inline iterator srvcmdbegin() const {return iterator(srvcmdlist);}
|
inline iterator srvcmdbegin() const {return iterator(srvcmdlist);}
|
||||||
inline iterator begin( int type ) const { return iterator(sortedlists[type]); }
|
inline iterator begin( int type ) const { return iterator(sortedlists[type]); }
|
||||||
inline iterator end() const { return iterator(0); }
|
inline iterator end() const { return iterator(0); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int buf_cmdid;
|
int buf_cmdid;
|
||||||
int buf_cmdtype;
|
int buf_cmdtype;
|
||||||
int buf_cmdaccess;
|
int buf_cmdaccess;
|
||||||
|
|
||||||
iterator buf_cmdptr;
|
iterator buf_cmdptr;
|
||||||
|
|
||||||
int buf_id;
|
int buf_id;
|
||||||
int buf_type;
|
int buf_type;
|
||||||
int buf_access;
|
int buf_access;
|
||||||
int buf_num;
|
int buf_num;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //COMMANDS_H
|
#endif
|
||||||
|
|
||||||
|
@ -1,340 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "CDataPack.h"
|
|
||||||
|
|
||||||
#define DATAPACK_INITIAL_SIZE 64
|
|
||||||
|
|
||||||
CDataPack::CDataPack()
|
|
||||||
{
|
|
||||||
m_pBase = (char *)malloc(DATAPACK_INITIAL_SIZE);
|
|
||||||
m_capacity = DATAPACK_INITIAL_SIZE;
|
|
||||||
Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
CDataPack::~CDataPack()
|
|
||||||
{
|
|
||||||
free(m_pBase);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDataPack::Initialize()
|
|
||||||
{
|
|
||||||
m_curptr = m_pBase;
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDataPack::CheckSize(size_t typesize)
|
|
||||||
{
|
|
||||||
if (m_curptr - m_pBase + typesize <= m_capacity)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t pos = m_curptr - m_pBase;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
m_capacity *= 2;
|
|
||||||
} while (pos + typesize > m_capacity);
|
|
||||||
|
|
||||||
m_pBase = (char *)realloc(m_pBase, m_capacity);
|
|
||||||
m_curptr = m_pBase + pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDataPack::ResetSize()
|
|
||||||
{
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CDataPack::CreateMemory(size_t size, void **addr)
|
|
||||||
{
|
|
||||||
CheckSize(sizeof(char) + sizeof(size_t) + size);
|
|
||||||
size_t pos = m_curptr - m_pBase;
|
|
||||||
|
|
||||||
*(char *)m_curptr = Raw;
|
|
||||||
m_curptr += sizeof(char);
|
|
||||||
|
|
||||||
*(size_t *)m_curptr = size;
|
|
||||||
m_curptr += sizeof(size_t);
|
|
||||||
|
|
||||||
if (addr)
|
|
||||||
{
|
|
||||||
*addr = m_curptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_curptr += size;
|
|
||||||
m_size += sizeof(char) + sizeof(size_t) + size;
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDataPack::PackCell(cell cells)
|
|
||||||
{
|
|
||||||
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell));
|
|
||||||
|
|
||||||
*(char *)m_curptr = DataPackType::Cell;
|
|
||||||
m_curptr += sizeof(char);
|
|
||||||
|
|
||||||
*(size_t *)m_curptr = sizeof(cell);
|
|
||||||
m_curptr += sizeof(size_t);
|
|
||||||
|
|
||||||
*(cell *)m_curptr = cells;
|
|
||||||
m_curptr += sizeof(cell);
|
|
||||||
|
|
||||||
m_size += sizeof(char) + sizeof(size_t) + sizeof(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDataPack::PackFloat(float val)
|
|
||||||
{
|
|
||||||
CheckSize(sizeof(char) + sizeof(size_t) + sizeof(float));
|
|
||||||
|
|
||||||
*(char *)m_curptr = DataPackType::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::PackString(const char *string)
|
|
||||||
{
|
|
||||||
size_t len = strlen(string);
|
|
||||||
size_t maxsize = sizeof(char) + sizeof(size_t) + len + 1;
|
|
||||||
CheckSize(maxsize);
|
|
||||||
|
|
||||||
*(char *)m_curptr = DataPackType::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDataPack::Reset() const
|
|
||||||
{
|
|
||||||
m_curptr = m_pBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CDataPack::GetPosition() const
|
|
||||||
{
|
|
||||||
return static_cast<size_t>(m_curptr - m_pBase);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDataPack::SetPosition(size_t pos) const
|
|
||||||
{
|
|
||||||
if (pos > m_size-1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
m_curptr = m_pBase + pos;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDataPack::CanReadCell() const
|
|
||||||
{
|
|
||||||
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (*reinterpret_cast<char *>(m_curptr) != DataPackType::Cell)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (*reinterpret_cast<size_t *>(m_curptr + sizeof(char)) != sizeof(cell))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell CDataPack::ReadCell() const
|
|
||||||
{
|
|
||||||
if (!CanReadCell())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_curptr += sizeof(char);
|
|
||||||
m_curptr += sizeof(size_t);
|
|
||||||
|
|
||||||
cell val = *reinterpret_cast<cell *>(m_curptr);
|
|
||||||
m_curptr += sizeof(cell);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDataPack::CanReadFloat() const
|
|
||||||
{
|
|
||||||
if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(float)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (*reinterpret_cast<char *>(m_curptr) != DataPackType::Float)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (*reinterpret_cast<size_t *>(m_curptr + sizeof(char)) != sizeof(float))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
float CDataPack::ReadFloat() const
|
|
||||||
{
|
|
||||||
if (!CanReadFloat())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_curptr += sizeof(char);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDataPack::CanReadString(size_t *len) const
|
|
||||||
{
|
|
||||||
if (!IsReadable(sizeof(char) + sizeof(size_t)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (*reinterpret_cast<char *>(m_curptr) != DataPackType::String)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t real_len = *(size_t *)(m_curptr + sizeof(char));
|
|
||||||
char *str = (char *)(m_curptr + sizeof(char) + sizeof(size_t));
|
|
||||||
|
|
||||||
if ((strlen(str) != real_len) || !(IsReadable(sizeof(char) + sizeof(size_t) + real_len + 1)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
{
|
|
||||||
*len = real_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *CDataPack::ReadString(size_t *len) const
|
|
||||||
{
|
|
||||||
size_t real_len;
|
|
||||||
if (!CanReadString(&real_len))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_curptr += sizeof(char);
|
|
||||||
m_curptr += sizeof(size_t);
|
|
||||||
|
|
||||||
char *str = (char *)m_curptr;
|
|
||||||
m_curptr += real_len + 1;
|
|
||||||
|
|
||||||
if (len)
|
|
||||||
{
|
|
||||||
*len = real_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDataPack::GetMemory() const
|
|
||||||
{
|
|
||||||
return m_curptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDataPack::CanReadMemory(size_t *size) const
|
|
||||||
{
|
|
||||||
if (!IsReadable(sizeof(char) + sizeof(size_t)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (*reinterpret_cast<char *>(m_curptr) != DataPackType::Raw)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t bytecount = *(size_t *)(m_curptr + sizeof(char));
|
|
||||||
if (!IsReadable(sizeof(char) + sizeof(size_t) + bytecount))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size)
|
|
||||||
{
|
|
||||||
*size = bytecount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDataPack::ReadMemory(size_t *size) const
|
|
||||||
{
|
|
||||||
size_t bytecount;
|
|
||||||
if (!CanReadMemory(&bytecount))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_curptr += sizeof(char);
|
|
||||||
m_curptr += sizeof(size_t);
|
|
||||||
|
|
||||||
void *ptr = m_curptr;
|
|
||||||
m_curptr += bytecount;
|
|
||||||
|
|
||||||
if (size)
|
|
||||||
{
|
|
||||||
*size = bytecount;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
@ -1,181 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_CDATAPACK_H_
|
|
||||||
#define _INCLUDE_SOURCEMOD_CDATAPACK_H_
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "natives_handles.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Contains functions for packing data abstractly to/from plugins.
|
|
||||||
*/
|
|
||||||
class CDataPack
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CDataPack();
|
|
||||||
~CDataPack();
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @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 ReadCell() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reads one float from the data stream.
|
|
||||||
*
|
|
||||||
* @return A float read from the current position.
|
|
||||||
*/
|
|
||||||
float ReadFloat() 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) 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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reads the current position as a generic address.
|
|
||||||
*
|
|
||||||
* @return Pointer to the memory.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
bool CanReadCell() const;
|
|
||||||
bool CanReadFloat() const;
|
|
||||||
bool CanReadString(size_t *len) const;
|
|
||||||
bool CanReadMemory(size_t *size) const;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @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 cells);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void Initialize();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void CheckSize(size_t sizetype);
|
|
||||||
|
|
||||||
private:
|
|
||||||
char *m_pBase;
|
|
||||||
mutable char *m_curptr;
|
|
||||||
size_t m_capacity;
|
|
||||||
size_t m_size;
|
|
||||||
|
|
||||||
enum DataPackType {
|
|
||||||
Raw,
|
|
||||||
Cell,
|
|
||||||
Float,
|
|
||||||
String,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
extern NativeHandle<CDataPack> DataPackHandles;
|
|
||||||
extern AMX_NATIVE_INFO g_DatapackNatives[];
|
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_
|
|
@ -1,21 +1,43 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include <extdll.h>
|
||||||
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
#include "CEvent.h"
|
#include "CEvent.h"
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class ClEvent
|
// class ClEvent
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
NativeHandle<EventHook> EventHandles;
|
|
||||||
|
|
||||||
EventsMngr::ClEvent::ClEvent(CPluginMngr::CPlugin* plugin, int func, int flags)
|
EventsMngr::ClEvent::ClEvent(CPluginMngr::CPlugin* plugin, int func, int flags)
|
||||||
{
|
{
|
||||||
m_Plugin = plugin;
|
m_Plugin = plugin;
|
||||||
@ -26,30 +48,16 @@ EventsMngr::ClEvent::ClEvent(CPluginMngr::CPlugin* plugin, int func, int flags)
|
|||||||
m_FlagDead = true;
|
m_FlagDead = true;
|
||||||
|
|
||||||
m_FlagWorld = (flags & 1) ? true : false; // flag a
|
m_FlagWorld = (flags & 1) ? true : false; // flag a
|
||||||
m_FlagClient = (flags & 2) ? true : false; // flag b
|
m_FlagPlayer = (flags & 2) ? true : false; // flag b
|
||||||
m_FlagOnce = (flags & 4) ? true : false; // flag c
|
m_FlagOnce = (flags & 4) ? true : false; // flag c
|
||||||
|
|
||||||
if (flags & 24)
|
if (flags & 24)
|
||||||
{
|
{
|
||||||
m_FlagAlive = (flags & 16) ? true : false; // flag e
|
m_FlagAlive = (flags & 16) ? true : false; // flag e
|
||||||
m_FlagDead = (flags & 8) ? true : false; // flag d
|
m_FlagDead = (flags & 8) ? true : false; // flag d
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_FlagClient)
|
|
||||||
{
|
|
||||||
m_FlagPlayer = true;
|
|
||||||
m_FlagBot = true;
|
|
||||||
|
|
||||||
if (flags & 96)
|
|
||||||
{
|
|
||||||
m_FlagPlayer = (flags & 32) ? true : false; // flag f
|
|
||||||
m_FlagBot = (flags & 64) ? true : false; // flag g
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Stamp = 0.0f;
|
m_Stamp = 0.0f;
|
||||||
m_Done = false;
|
m_Done = false;
|
||||||
m_State = FSTATE_ACTIVE;
|
|
||||||
|
|
||||||
m_Conditions = NULL;
|
m_Conditions = NULL;
|
||||||
}
|
}
|
||||||
@ -58,14 +66,12 @@ EventsMngr::ClEvent::~ClEvent()
|
|||||||
{
|
{
|
||||||
cond_t *tmp1 = m_Conditions;
|
cond_t *tmp1 = m_Conditions;
|
||||||
cond_t *tmp2 = NULL;
|
cond_t *tmp2 = NULL;
|
||||||
|
|
||||||
while (tmp1)
|
while (tmp1)
|
||||||
{
|
{
|
||||||
tmp2 = tmp1->next;
|
tmp2 = tmp1->next;
|
||||||
delete tmp1;
|
delete tmp1;
|
||||||
tmp1 = tmp2;
|
tmp1 = tmp2;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Conditions = NULL;
|
m_Conditions = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,17 +84,10 @@ void EventsMngr::NextParam()
|
|||||||
|
|
||||||
MsgDataEntry *tmp = NULL;
|
MsgDataEntry *tmp = NULL;
|
||||||
int tmpSize = 0;
|
int tmpSize = 0;
|
||||||
|
|
||||||
if (m_ParseVault)
|
if (m_ParseVault)
|
||||||
{
|
{
|
||||||
// copy to tmp
|
// copy to tmp
|
||||||
tmp = new MsgDataEntry[m_ParseVaultSize];
|
tmp = new MsgDataEntry[m_ParseVaultSize];
|
||||||
|
|
||||||
if (!tmp)
|
|
||||||
{
|
|
||||||
return; // :TODO: Error report !!
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(tmp, m_ParseVault, m_ParseVaultSize * sizeof(MsgDataEntry));
|
memcpy(tmp, m_ParseVault, m_ParseVaultSize * sizeof(MsgDataEntry));
|
||||||
tmpSize = m_ParseVaultSize;
|
tmpSize = m_ParseVaultSize;
|
||||||
delete [] m_ParseVault;
|
delete [] m_ParseVault;
|
||||||
@ -101,7 +100,6 @@ void EventsMngr::NextParam()
|
|||||||
m_ParseVaultSize = INITIAL_PARSEVAULT_SIZE;
|
m_ParseVaultSize = INITIAL_PARSEVAULT_SIZE;
|
||||||
|
|
||||||
m_ParseVault = new MsgDataEntry[m_ParseVaultSize];
|
m_ParseVault = new MsgDataEntry[m_ParseVaultSize];
|
||||||
|
|
||||||
if (tmp)
|
if (tmp)
|
||||||
{
|
{
|
||||||
memcpy(m_ParseVault, tmp, tmpSize * sizeof(MsgDataEntry));
|
memcpy(m_ParseVault, tmp, tmpSize * sizeof(MsgDataEntry));
|
||||||
@ -119,18 +117,20 @@ EventsMngr::EventsMngr()
|
|||||||
{
|
{
|
||||||
m_ParseVault = NULL;
|
m_ParseVault = NULL;
|
||||||
m_ParseVaultSize = 0;
|
m_ParseVaultSize = 0;
|
||||||
m_ParseMsgType = -1;
|
|
||||||
m_ReadVault = NULL;
|
|
||||||
m_ReadVaultSize = 0;
|
|
||||||
m_ReadPos = -1;
|
|
||||||
m_ReadMsgType = -1;
|
|
||||||
clearEvents();
|
clearEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
EventsMngr::~EventsMngr()
|
EventsMngr::~EventsMngr()
|
||||||
{
|
{
|
||||||
clearEvents();
|
clearEvents();
|
||||||
|
// delete parsevault
|
||||||
|
if (m_ParseVault)
|
||||||
|
{
|
||||||
|
delete [] m_ParseVault;
|
||||||
|
m_ParseVault = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CPluginMngr::CPlugin * EventsMngr::ClEvent::getPlugin()
|
CPluginMngr::CPlugin * EventsMngr::ClEvent::getPlugin()
|
||||||
{
|
{
|
||||||
@ -172,8 +172,8 @@ void EventsMngr::ClEvent::registerFilter(char *filter)
|
|||||||
tmpCond->paramId = atoi(filter);
|
tmpCond->paramId = atoi(filter);
|
||||||
|
|
||||||
// rest of line
|
// rest of line
|
||||||
tmpCond->sValue = value;
|
tmpCond->sValue.set(value);
|
||||||
tmpCond->fValue = static_cast<float>(atof(value));
|
tmpCond->fValue = atof(value);
|
||||||
tmpCond->iValue = atoi(value);
|
tmpCond->iValue = atoi(value);
|
||||||
|
|
||||||
tmpCond->next = NULL;
|
tmpCond->next = NULL;
|
||||||
@ -181,41 +181,28 @@ void EventsMngr::ClEvent::registerFilter(char *filter)
|
|||||||
if (m_Conditions)
|
if (m_Conditions)
|
||||||
{
|
{
|
||||||
cond_t *tmp = m_Conditions;
|
cond_t *tmp = m_Conditions;
|
||||||
|
|
||||||
while (tmp->next)
|
while (tmp->next)
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
|
|
||||||
tmp->next = tmpCond;
|
tmp->next = tmpCond;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_Conditions = tmpCond;
|
m_Conditions = tmpCond;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventsMngr::ClEvent::setForwardState(ForwardState state)
|
EventsMngr::ClEvent* EventsMngr::registerEvent(CPluginMngr::CPlugin* plugin, int func, int flags, int msgid)
|
||||||
{
|
|
||||||
m_State = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int EventsMngr::registerEvent(CPluginMngr::CPlugin* plugin, int func, int flags, int msgid)
|
|
||||||
{
|
{
|
||||||
|
// validate parameter
|
||||||
if (msgid < 0 || msgid >= MAX_AMX_REG_MSG)
|
if (msgid < 0 || msgid >= MAX_AMX_REG_MSG)
|
||||||
{
|
return NULL;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto event = ke::AutoPtr<ClEvent>(new ClEvent(plugin, func, flags));
|
ClEvent *event = new ClEvent(plugin, func, flags);
|
||||||
|
if (!event)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
int handle = EventHandles.create(event.get());
|
m_Events[msgid].put(event);
|
||||||
|
|
||||||
if (!handle)
|
return event;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Events[msgid].append(ke::Move(event));
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventsMngr::parserInit(int msg_type, float* timer, CPlayer* pPlayer, int index)
|
void EventsMngr::parserInit(int msg_type, float* timer, CPlayer* pPlayer, int index)
|
||||||
@ -224,45 +211,43 @@ void EventsMngr::parserInit(int msg_type, float* timer, CPlayer* pPlayer, int in
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_ParseNotDone = false;
|
m_ParseNotDone = false;
|
||||||
|
|
||||||
// don't parse if nothing to do
|
|
||||||
if (!m_Events[msg_type].length())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_ParseMsgType = msg_type;
|
|
||||||
m_Timer = timer;
|
m_Timer = timer;
|
||||||
|
|
||||||
for (auto &event : m_Events[msg_type])
|
// don't parse if nothing to do
|
||||||
|
if (!m_Events[msg_type].size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(ClEventVecIter iter = m_Events[msg_type].begin(); iter; ++iter)
|
||||||
{
|
{
|
||||||
if (event->m_Done)
|
if ((*iter).m_Done)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!event->m_Plugin->isExecutable(event->m_Func))
|
|
||||||
|
if (!(*iter).m_Plugin->isExecutable((*iter).m_Func))
|
||||||
{
|
{
|
||||||
event->m_Done = true;
|
(*iter).m_Done = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pPlayer)
|
if (pPlayer)
|
||||||
{
|
{
|
||||||
if (!event->m_FlagClient || (pPlayer->IsBot() ? !event->m_FlagBot : !event->m_FlagPlayer) || (pPlayer->IsAlive() ? !event->m_FlagAlive : !event->m_FlagDead))
|
if (!(*iter).m_FlagPlayer || (pPlayer->IsAlive() ? !(*iter).m_FlagAlive : !(*iter).m_FlagDead ) )
|
||||||
{
|
{
|
||||||
event->m_Done = true;
|
(*iter).m_Done = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!event->m_FlagWorld)
|
else if (!(*iter).m_FlagWorld)
|
||||||
{
|
{
|
||||||
event->m_Done = true;
|
(*iter).m_Done = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event->m_FlagOnce && event->m_Stamp == *timer)
|
if ((*iter).m_FlagOnce && (*iter).m_Stamp == (float)(*timer))
|
||||||
{
|
{
|
||||||
event->m_Done = true;
|
(*iter).m_Done = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ParseNotDone = true;
|
m_ParseNotDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,10 +255,9 @@ void EventsMngr::parserInit(int msg_type, float* timer, CPlayer* pPlayer, int in
|
|||||||
{
|
{
|
||||||
m_ParsePos = 0;
|
m_ParsePos = 0;
|
||||||
NextParam();
|
NextParam();
|
||||||
m_ParseVault[0].type = MSG_INTEGER;
|
m_ParseVault[m_ParsePos].type = MSG_INTEGER;
|
||||||
m_ParseVault[0].iValue = index;
|
m_ParseVault[m_ParsePos].iValue = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ParseFun = &m_Events[msg_type];
|
m_ParseFun = &m_Events[msg_type];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,6 +267,7 @@ void EventsMngr::parseValue(int iValue)
|
|||||||
if (!m_ParseNotDone || !m_ParseFun)
|
if (!m_ParseNotDone || !m_ParseFun)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
// grow if needed
|
// grow if needed
|
||||||
++m_ParsePos;
|
++m_ParsePos;
|
||||||
NextParam();
|
NextParam();
|
||||||
@ -292,20 +277,18 @@ void EventsMngr::parseValue(int iValue)
|
|||||||
|
|
||||||
// loop through the registered funcs, and decide whether they have to be called or not
|
// loop through the registered funcs, and decide whether they have to be called or not
|
||||||
// if they shouldnt, their m_Done is set to true
|
// if they shouldnt, their m_Done is set to true
|
||||||
for (auto &event : *m_ParseFun)
|
for (ClEventVecIter iter = m_ParseFun->begin(); iter; ++iter)
|
||||||
{
|
{
|
||||||
if (event->m_Done)
|
if ((*iter).m_Done)
|
||||||
continue; // already skipped; don't bother with parsing
|
continue; // already skipped; don't bother with parsing
|
||||||
|
|
||||||
// loop through conditions
|
// loop through conditions
|
||||||
bool execute = false;
|
bool execute;
|
||||||
bool anyConditions = false;
|
for (ClEvent::cond_t *condIter = (*iter).m_Conditions; condIter; condIter = condIter->next)
|
||||||
|
|
||||||
for (auto condIter = event->m_Conditions; condIter; condIter = condIter->next)
|
|
||||||
{
|
{
|
||||||
if (condIter->paramId == m_ParsePos)
|
if (condIter->paramId == m_ParsePos)
|
||||||
{
|
{
|
||||||
anyConditions = true;
|
execute = false;
|
||||||
switch(condIter->type)
|
switch(condIter->type)
|
||||||
{
|
{
|
||||||
case '=': if (condIter->iValue == iValue) execute=true; break;
|
case '=': if (condIter->iValue == iValue) execute=true; break;
|
||||||
@ -315,12 +298,11 @@ void EventsMngr::parseValue(int iValue)
|
|||||||
case '>': if (iValue > condIter->iValue) execute=true; break;
|
case '>': if (iValue > condIter->iValue) execute=true; break;
|
||||||
}
|
}
|
||||||
if (execute)
|
if (execute)
|
||||||
|
continue;
|
||||||
|
(*iter).m_Done = true; // don't execute
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anyConditions && !execute)
|
|
||||||
event->m_Done = true; // don't execute
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,6 +312,7 @@ void EventsMngr::parseValue(float fValue)
|
|||||||
if (!m_ParseNotDone || !m_ParseFun)
|
if (!m_ParseNotDone || !m_ParseFun)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
// grow if needed
|
// grow if needed
|
||||||
++m_ParsePos;
|
++m_ParsePos;
|
||||||
NextParam();
|
NextParam();
|
||||||
@ -339,20 +322,17 @@ void EventsMngr::parseValue(float fValue)
|
|||||||
|
|
||||||
// loop through the registered funcs, and decide whether they have to be called or not
|
// loop through the registered funcs, and decide whether they have to be called or not
|
||||||
// if they shouldnt, their m_Done is set to true
|
// if they shouldnt, their m_Done is set to true
|
||||||
for (auto &event : *m_ParseFun)
|
for (ClEventVecIter iter = m_ParseFun->begin(); iter; ++iter)
|
||||||
{
|
{
|
||||||
if (event->m_Done)
|
if ((*iter).m_Done)
|
||||||
continue; // already skipped; don't bother with parsing
|
continue; // already skipped; don't bother with parsing
|
||||||
|
|
||||||
// loop through conditions
|
// loop through conditions
|
||||||
bool execute = false;
|
for (ClEvent::cond_t *condIter = (*iter).m_Conditions; condIter; condIter = condIter->next)
|
||||||
bool anyConditions = false;
|
|
||||||
|
|
||||||
for (auto condIter = event->m_Conditions; condIter; condIter = condIter->next)
|
|
||||||
{
|
{
|
||||||
if (condIter->paramId == m_ParsePos)
|
if (condIter->paramId == m_ParsePos)
|
||||||
{
|
{
|
||||||
anyConditions = true;
|
bool execute = false;
|
||||||
switch(condIter->type)
|
switch(condIter->type)
|
||||||
{
|
{
|
||||||
case '=': if (condIter->fValue == fValue) execute=true; break;
|
case '=': if (condIter->fValue == fValue) execute=true; break;
|
||||||
@ -360,14 +340,12 @@ void EventsMngr::parseValue(float fValue)
|
|||||||
case '<': if (fValue < condIter->fValue) execute=true; break;
|
case '<': if (fValue < condIter->fValue) execute=true; break;
|
||||||
case '>': if (fValue > condIter->fValue) execute=true; break;
|
case '>': if (fValue > condIter->fValue) execute=true; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (execute)
|
if (execute)
|
||||||
|
continue;
|
||||||
|
(*iter).m_Done = true; // don't execute
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anyConditions && !execute)
|
|
||||||
event->m_Done = true; // don't execute
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,161 +364,127 @@ void EventsMngr::parseValue(const char *sz)
|
|||||||
|
|
||||||
// loop through the registered funcs, and decide whether they have to be called or not
|
// loop through the registered funcs, and decide whether they have to be called or not
|
||||||
// if they shouldnt, their m_Done is set to true
|
// if they shouldnt, their m_Done is set to true
|
||||||
for (auto &event : *m_ParseFun)
|
for (ClEventVecIter iter = m_ParseFun->begin(); iter; ++iter)
|
||||||
{
|
{
|
||||||
if (event->m_Done)
|
if ((*iter).m_Done)
|
||||||
continue; // already skipped; don't bother with parsing
|
continue; // already skipped; don't bother with parsing
|
||||||
|
|
||||||
// loop through conditions
|
// loop through conditions
|
||||||
bool execute = false;
|
for (ClEvent::cond_t *condIter = (*iter).m_Conditions; condIter; condIter = condIter->next)
|
||||||
bool anyConditions = false;
|
|
||||||
|
|
||||||
for (auto condIter = event->m_Conditions; condIter; condIter = condIter->next)
|
|
||||||
{
|
{
|
||||||
if (condIter->paramId == m_ParsePos)
|
if (condIter->paramId == m_ParsePos)
|
||||||
{
|
{
|
||||||
anyConditions = true;
|
bool execute = false;
|
||||||
switch(condIter->type)
|
switch(condIter->type)
|
||||||
{
|
{
|
||||||
case '=': if (!strcmp(sz, condIter->sValue.chars())) execute = true; break;
|
case '=': if (!strcmp(sz, condIter->sValue.str())) execute=true; break;
|
||||||
case '!': if (strcmp(sz, condIter->sValue.chars())) execute = true; break;
|
case '!': if (strcmp(sz, condIter->sValue.str())) execute=true; break;
|
||||||
case '&': if (strstr(sz, condIter->sValue.chars())) execute = true; break;
|
case '&': if (strstr(sz, condIter->sValue.str())) execute=true; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (execute)
|
if (execute)
|
||||||
|
continue;
|
||||||
|
(*iter).m_Done = true; // don't execute
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anyConditions && !execute)
|
|
||||||
event->m_Done = true; // don't execute
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventsMngr::executeEvents()
|
void EventsMngr::executeEvents()
|
||||||
{
|
{
|
||||||
static unsigned int reentrant = 0;
|
int err;
|
||||||
|
|
||||||
if (!m_ParseFun)
|
if (!m_ParseFun)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store old read data, which are either default values or previous event data
|
#ifdef ENABLEEXEPTIONS
|
||||||
int oldMsgType = m_ReadMsgType, oldReadPos = m_ReadPos;
|
try
|
||||||
MsgDataEntry *oldReadVault = m_ReadVault, *readVault = NULL;
|
|
||||||
|
|
||||||
// We have a re-entrant call
|
|
||||||
if (reentrant++)
|
|
||||||
{
|
{
|
||||||
// Create temporary read vault
|
#endif // #ifdef ENABLEEXEPTIONS
|
||||||
readVault = new MsgDataEntry[m_ParsePos + 1];
|
for (ClEventVecIter iter = m_ParseFun->begin(); iter; ++iter)
|
||||||
m_ReadVault = readVault;
|
|
||||||
} else if (m_ReadVaultSize != m_ParseVaultSize) {
|
|
||||||
// Extend read vault size if necessary
|
|
||||||
delete [] m_ReadVault;
|
|
||||||
m_ReadVault = new MsgDataEntry[m_ParseVaultSize];
|
|
||||||
m_ReadVaultSize = m_ParseVaultSize;
|
|
||||||
|
|
||||||
// Update old read vault so we don't restore to a wrong pointer
|
|
||||||
oldReadVault = m_ReadVault;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy data over to readvault
|
|
||||||
m_ReadPos = m_ParsePos;
|
|
||||||
m_ReadMsgType = m_ParseMsgType;
|
|
||||||
|
|
||||||
if (m_ParseVault)
|
|
||||||
{
|
{
|
||||||
memcpy(m_ReadVault, m_ParseVault, (m_ParsePos + 1) * sizeof(MsgDataEntry));
|
if ( (*iter).m_Done )
|
||||||
}
|
|
||||||
|
|
||||||
// Reset this here so we don't trigger re-entrancy for unregistered messages
|
|
||||||
auto parseFun = m_ParseFun;
|
|
||||||
m_ParseFun = nullptr;
|
|
||||||
|
|
||||||
auto lastSize = parseFun->length();
|
|
||||||
for(auto i = 0u; i < lastSize; i++)
|
|
||||||
{
|
{
|
||||||
auto &event = parseFun->at(i);
|
(*iter).m_Done = false;
|
||||||
|
|
||||||
if (event->m_Done)
|
|
||||||
{
|
|
||||||
event->m_Done = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
event->m_Stamp = *m_Timer;
|
(*iter).m_Stamp = (float)*m_Timer;
|
||||||
|
|
||||||
if (event->m_State == FSTATE_ACTIVE)
|
if ((err = amx_Exec((*iter).m_Plugin->getAMX(), NULL, (*iter).m_Func, 1, m_ParseVaultSize ? m_ParseVault[0].iValue : 0)) != AMX_ERR_NONE)
|
||||||
{
|
{
|
||||||
executeForwards(event->m_Func, static_cast<cell>(m_ReadVault ? m_ReadVault[0].iValue : 0));
|
UTIL_Log("[AMXX] Run time error %d on line %ld (plugin \"%s\")", err,
|
||||||
|
(*iter).m_Plugin->getAMX()->curline, (*iter).m_Plugin->getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore old read data, either resetting to default or to previous event data
|
#ifdef ENABLEEXEPTIONS
|
||||||
m_ReadMsgType = oldMsgType;
|
|
||||||
m_ReadPos = oldReadPos;
|
|
||||||
m_ReadVault = oldReadVault;
|
|
||||||
|
|
||||||
delete [] readVault;
|
|
||||||
|
|
||||||
--reentrant;
|
|
||||||
}
|
}
|
||||||
|
catch( ... )
|
||||||
int EventsMngr::getArgNum() const
|
|
||||||
{
|
{
|
||||||
return m_ReadPos + 1;
|
UTIL_Log( "[AMXX] fatal error at event execution");
|
||||||
|
}
|
||||||
|
#endif // #ifdef ENABLEEXEPTIONS
|
||||||
|
|
||||||
|
m_ParseFun = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* EventsMngr::getArgString(int a) const
|
int EventsMngr::getArgNum()
|
||||||
{
|
{
|
||||||
if (a < 0 || a > m_ReadPos)
|
return m_ParsePos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* EventsMngr::getArgString(int a)
|
||||||
|
{
|
||||||
|
if ( a < 0 || a > m_ParsePos )
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
static char var[32];
|
static char var[32];
|
||||||
|
|
||||||
switch (m_ReadVault[a].type)
|
switch(m_ParseVault[a].type)
|
||||||
{
|
{
|
||||||
case MSG_INTEGER:
|
case MSG_INTEGER:
|
||||||
sprintf(var, "%d", m_ReadVault[a].iValue);
|
sprintf( var, "%d", m_ParseVault[a].iValue );
|
||||||
return var;
|
return var;
|
||||||
case MSG_STRING:
|
case MSG_STRING:
|
||||||
return m_ReadVault[a].sValue;
|
return m_ParseVault[a].sValue;
|
||||||
default:
|
default:
|
||||||
sprintf(var, "%g", m_ReadVault[a].fValue);
|
sprintf( var, "%g", m_ParseVault[a].fValue );
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int EventsMngr::getArgInteger(int a) const
|
int EventsMngr::getArgInteger(int a)
|
||||||
{
|
{
|
||||||
if (a < 0 || a > m_ReadPos)
|
if ( a < 0 || a > m_ParsePos )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (m_ReadVault[a].type)
|
switch(m_ParseVault[a].type)
|
||||||
{
|
{
|
||||||
case MSG_INTEGER:
|
case MSG_INTEGER:
|
||||||
return m_ReadVault[a].iValue;
|
return m_ParseVault[a].iValue;
|
||||||
case MSG_STRING:
|
case MSG_STRING:
|
||||||
return atoi(m_ReadVault[a].sValue);
|
return atoi(m_ParseVault[a].sValue);
|
||||||
default:
|
default:
|
||||||
return (int)m_ReadVault[a].fValue;
|
return (int)m_ParseVault[a].fValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float EventsMngr::getArgFloat(int a) const
|
float EventsMngr::getArgFloat(int a)
|
||||||
{
|
{
|
||||||
if (a < 0 || a > m_ReadPos)
|
if ( a < 0 || a > m_ParsePos )
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
switch (m_ReadVault[a].type)
|
switch(m_ParseVault[a].type)
|
||||||
{
|
{
|
||||||
case MSG_INTEGER:
|
case MSG_INTEGER:
|
||||||
return static_cast<float>(m_ReadVault[a].iValue);
|
return m_ParseVault[a].iValue;
|
||||||
case MSG_STRING:
|
case MSG_STRING:
|
||||||
return static_cast<float>(atof(m_ReadVault[a].sValue));
|
return atof(m_ParseVault[a].sValue);
|
||||||
default:
|
default:
|
||||||
return m_ReadVault[a].fValue;
|
return m_ParseVault[a].fValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,24 +494,6 @@ void EventsMngr::clearEvents(void)
|
|||||||
{
|
{
|
||||||
m_Events[i].clear();
|
m_Events[i].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
EventHandles.clear();
|
|
||||||
|
|
||||||
// delete parsevault
|
|
||||||
if (m_ParseVault)
|
|
||||||
{
|
|
||||||
delete [] m_ParseVault;
|
|
||||||
m_ParseVault = NULL;
|
|
||||||
m_ParseVaultSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_ReadVault)
|
|
||||||
{
|
|
||||||
delete [] m_ReadVault;
|
|
||||||
m_ReadVault = NULL;
|
|
||||||
m_ReadVaultSize = 0;
|
|
||||||
m_ReadPos = -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int EventsMngr::getEventId(const char* msg)
|
int EventsMngr::getEventId(const char* msg)
|
||||||
@ -588,7 +514,6 @@ int EventsMngr::getEventId(const char* msg)
|
|||||||
|
|
||||||
// if msg is a number, return it
|
// if msg is a number, return it
|
||||||
int pos = atoi(msg);
|
int pos = atoi(msg);
|
||||||
|
|
||||||
if (pos != 0)
|
if (pos != 0)
|
||||||
return pos;
|
return pos;
|
||||||
|
|
||||||
@ -600,8 +525,3 @@ int EventsMngr::getEventId(const char* msg)
|
|||||||
// find the id of the message
|
// find the id of the message
|
||||||
return pos = GET_USER_MSG_ID(PLID, msg , 0 );
|
return pos = GET_USER_MSG_ID(PLID, msg , 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
int EventsMngr::getCurrentMsgType()
|
|
||||||
{
|
|
||||||
return m_ReadMsgType;
|
|
||||||
}
|
|
||||||
|
@ -1,21 +1,40 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef __CEVENTS_H__
|
#ifndef __CEVENTS_H__
|
||||||
#define __CEVENTS_H__
|
#define __CEVENTS_H__
|
||||||
|
|
||||||
#include "natives_handles.h"
|
|
||||||
|
|
||||||
#define MAX_AMX_REG_MSG MAX_REG_MSGS+16
|
#define MAX_AMX_REG_MSG MAX_REG_MSGS+16
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
CS_DEATHMSG = MAX_REG_MSGS,
|
CS_DEATHMSG = MAX_REG_MSGS,
|
||||||
// CS_ROUNDEND,
|
// CS_ROUNDEND,
|
||||||
// CS_ROUNDSTART,
|
// CS_ROUNDSTART,
|
||||||
@ -54,25 +73,22 @@ public:
|
|||||||
CPluginMngr::CPlugin *m_Plugin; // the plugin this ClEvent class is assigned to
|
CPluginMngr::CPlugin *m_Plugin; // the plugin this ClEvent class is assigned to
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
bool m_FlagClient;
|
bool m_FlagPlayer;
|
||||||
bool m_FlagWorld;
|
bool m_FlagWorld;
|
||||||
bool m_FlagOnce;
|
bool m_FlagOnce;
|
||||||
bool m_FlagDead;
|
bool m_FlagDead;
|
||||||
bool m_FlagAlive;
|
bool m_FlagAlive;
|
||||||
bool m_FlagPlayer;
|
|
||||||
bool m_FlagBot;
|
|
||||||
|
|
||||||
float m_Stamp; // for 'once' flag
|
float m_Stamp; // for 'once' flag
|
||||||
|
|
||||||
bool m_Done;
|
bool m_Done;
|
||||||
ForwardState m_State;
|
|
||||||
|
|
||||||
// conditions
|
// conditions
|
||||||
struct cond_t
|
struct cond_t
|
||||||
{
|
{
|
||||||
int paramId; // the message parameter id
|
int paramId; // the message parameter id
|
||||||
|
|
||||||
ke::AString sValue; // value (string)
|
String sValue; // value (string)
|
||||||
float fValue; // value (float)
|
float fValue; // value (float)
|
||||||
int iValue; // value (int)
|
int iValue; // value (int)
|
||||||
int type; // type (can be int, float, string)
|
int type; // type (can be int, float, string)
|
||||||
@ -90,7 +106,6 @@ public:
|
|||||||
inline CPluginMngr::CPlugin* getPlugin();
|
inline CPluginMngr::CPlugin* getPlugin();
|
||||||
inline int getFunction();
|
inline int getFunction();
|
||||||
void registerFilter(char* filter); // add a condition
|
void registerFilter(char* filter); // add a condition
|
||||||
void setForwardState(ForwardState value);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -101,54 +116,40 @@ private:
|
|||||||
const char* sValue;
|
const char* sValue;
|
||||||
MsgParamType type;
|
MsgParamType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
MsgDataEntry *m_ParseVault;
|
MsgDataEntry *m_ParseVault;
|
||||||
MsgDataEntry *m_ReadVault;
|
|
||||||
int m_ParseVaultSize;
|
int m_ParseVaultSize;
|
||||||
int m_ReadVaultSize;
|
|
||||||
void NextParam(); // make sure a new parameter can be added
|
void NextParam(); // make sure a new parameter can be added
|
||||||
|
|
||||||
ke::Vector<ke::AutoPtr<ClEvent>> m_Events[MAX_AMX_REG_MSG];
|
typedef CList<ClEvent> ClEventVec;
|
||||||
ke::Vector<ke::AutoPtr<ClEvent>> *m_ParseFun; // current Event vector
|
typedef ClEventVec::iterator ClEventVecIter;
|
||||||
|
|
||||||
|
ClEventVec m_Events[MAX_AMX_REG_MSG];
|
||||||
|
ClEventVec *m_ParseFun; // current Event vector
|
||||||
|
|
||||||
bool m_ParseNotDone;
|
bool m_ParseNotDone;
|
||||||
int m_ParsePos; // is args. num. - 1
|
int m_ParsePos; // is args. num. - 1
|
||||||
int m_ReadPos;
|
|
||||||
float* m_Timer;
|
float* m_Timer;
|
||||||
|
|
||||||
ClEvent* getValidEvent(ClEvent* a );
|
ClEvent* getValidEvent(ClEvent* a );
|
||||||
|
|
||||||
int m_ParseMsgType;
|
|
||||||
int m_ReadMsgType;
|
|
||||||
public:
|
public:
|
||||||
EventsMngr();
|
EventsMngr();
|
||||||
~EventsMngr();
|
~EventsMngr();
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
|
|
||||||
int registerEvent(CPluginMngr::CPlugin* plugin, int func, int flags, int msgid);
|
ClEvent* registerEvent(CPluginMngr::CPlugin* plugin, int func, int flags, int msgid);
|
||||||
|
|
||||||
void parserInit(int msg_type, float* timer, CPlayer* pPlayer, int index);
|
void parserInit(int msg_type, float* timer, CPlayer* pPlayer, int index);
|
||||||
void parseValue(int iValue);
|
void parseValue(int iValue);
|
||||||
void parseValue(float fValue);
|
void parseValue(float fValue);
|
||||||
void parseValue(const char *sz);
|
void parseValue(const char *sz);
|
||||||
void executeEvents();
|
void executeEvents();
|
||||||
|
int getArgNum(); //{ return (parsePos+1); }
|
||||||
int getArgNum() const; //{ return (parsePos + 1); }
|
const char* getArgString(int a);
|
||||||
const char* getArgString(int a) const;
|
int getArgInteger(int a);
|
||||||
int getArgInteger(int a) const;
|
float getArgFloat(int a);
|
||||||
float getArgFloat(int a) const;
|
|
||||||
void clearEvents(void);
|
void clearEvents(void);
|
||||||
static int getEventId( const char* msg );
|
static int getEventId( const char* msg );
|
||||||
int getCurrentMsgType();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EventHook
|
#endif // #ifdef __CEVENTS_H__
|
||||||
{
|
|
||||||
explicit EventHook(EventsMngr::ClEvent *event) : m_event(event) {}
|
|
||||||
EventsMngr::ClEvent *m_event;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern NativeHandle<EventHook> EventHandles;
|
|
||||||
|
|
||||||
#endif //__CEVENTS_H__
|
|
115
amxmodx/CFile.cpp
Executable file
115
amxmodx/CFile.cpp
Executable file
@ -0,0 +1,115 @@
|
|||||||
|
/* AMX Mod X
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
* originally developed by OLO
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CFile.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// class File
|
||||||
|
// *****************************************************
|
||||||
|
File::File( const char* n, const char* m )
|
||||||
|
{
|
||||||
|
fp = fopen( n , m );
|
||||||
|
}
|
||||||
|
|
||||||
|
File::~File( )
|
||||||
|
{
|
||||||
|
if ( fp )
|
||||||
|
fclose( fp );
|
||||||
|
}
|
||||||
|
|
||||||
|
File::operator bool ( ) const
|
||||||
|
{
|
||||||
|
return fp && !feof(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
File& operator<<( File& f, const String& n )
|
||||||
|
{
|
||||||
|
if ( f ) fputs( n.str() , f.fp ) ;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
File& operator<<( File& f, const char* n )
|
||||||
|
{
|
||||||
|
if ( f ) fputs( n , f.fp ) ;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
File& operator<<( File& f, int n )
|
||||||
|
{
|
||||||
|
if ( f ) fprintf( f.fp , "%d" , n ) ;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File& operator<<( File& f, const char& c )
|
||||||
|
{
|
||||||
|
if ( f ) fputc( c , f.fp ) ;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
File& operator>>( File& f, String& n )
|
||||||
|
{
|
||||||
|
if ( !f ) return f;
|
||||||
|
char temp[1024];
|
||||||
|
fscanf( f.fp , "%s", temp );
|
||||||
|
n.set(temp);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
File& operator>>( File& f, char* n )
|
||||||
|
{
|
||||||
|
if ( f ) fscanf( f.fp , "%s", n );
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int File::getline( char* buf, int sz )
|
||||||
|
{
|
||||||
|
int a = sz;
|
||||||
|
if ( *this )
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
while ( sz-- && (c = getc( (*this).fp)) && c != EOF && c != '\n' )
|
||||||
|
*buf++ = c;
|
||||||
|
*buf = 0;
|
||||||
|
}
|
||||||
|
return a - sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
File& File::skipWs( )
|
||||||
|
{
|
||||||
|
if ( !*this ) return *this;
|
||||||
|
int c;
|
||||||
|
while( isspace( c = getc( fp ) ) ){};
|
||||||
|
ungetc( c , fp );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
58
amxmodx/CFile.h
Executable file
58
amxmodx/CFile.h
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
/* AMX Mod X
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
* originally developed by OLO
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "CString.h"
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// class File
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
class File
|
||||||
|
{
|
||||||
|
FILE* fp;
|
||||||
|
|
||||||
|
public:
|
||||||
|
File( const char* n, const char* m );
|
||||||
|
~File( );
|
||||||
|
operator bool ( ) const;
|
||||||
|
friend File& operator<<( File& f, const String& n );
|
||||||
|
friend File& operator<<( File& f, const char* n );
|
||||||
|
friend File& operator<<( File& f, const char& c );
|
||||||
|
friend File& operator<<( File& f, int n );
|
||||||
|
friend File& operator>>( File& f, String& n );
|
||||||
|
friend File& operator>>( File& f, char* n );
|
||||||
|
int getline( char* buf, int sz );
|
||||||
|
File& skipWs( );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,255 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_CFILESYSTEM_H_
|
|
||||||
#define _INCLUDE_CFILESYSTEM_H_
|
|
||||||
|
|
||||||
#include <FileSystem.h> // IFileSystem, FileSystemSeek_t, FileHandle_t (HLSDK)
|
|
||||||
#include <stdio.h> // FILE*
|
|
||||||
|
|
||||||
extern IFileSystem* g_FileSystem;
|
|
||||||
|
|
||||||
class ValveFile;
|
|
||||||
class SystemFile;
|
|
||||||
|
|
||||||
class FileObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual ~FileObject() {};
|
|
||||||
|
|
||||||
virtual size_t Read(void* pOut, size_t size) = 0;
|
|
||||||
virtual char* ReadLine(char* pOut, size_t size) = 0;
|
|
||||||
virtual size_t Write(const void* pData, size_t size) = 0;
|
|
||||||
|
|
||||||
virtual bool Seek(int pos, int seek_type) = 0;
|
|
||||||
virtual int Tell() = 0;
|
|
||||||
virtual int Flush() = 0;
|
|
||||||
|
|
||||||
virtual bool HasError() = 0;
|
|
||||||
|
|
||||||
virtual bool EndOfFile() = 0;
|
|
||||||
virtual void Close() = 0;
|
|
||||||
|
|
||||||
virtual ValveFile *AsValveFile()
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual SystemFile *AsSystemFile()
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ValveFile : public FileObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
ValveFile(FileHandle_t handle) : handle_(handle) {}
|
|
||||||
|
|
||||||
~ValveFile()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool Exists(const char* file)
|
|
||||||
{
|
|
||||||
return g_FileSystem->FileExists(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ValveFile* Open(const char* filename, const char* mode, const char* pathID)
|
|
||||||
{
|
|
||||||
FileHandle_t handle = g_FileSystem->OpenFromCacheForRead(filename, mode, pathID);
|
|
||||||
|
|
||||||
if (!handle)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ValveFile(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool Delete(const char* filename, const char* pathID)
|
|
||||||
{
|
|
||||||
if (!Exists(filename))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_FileSystem->RemoveFile(filename, pathID);
|
|
||||||
|
|
||||||
if (Exists(filename))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Read(void* pOut, size_t size) override
|
|
||||||
{
|
|
||||||
return static_cast<size_t>(g_FileSystem->Read(pOut, size, handle_));
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ReadLine(char* pOut, size_t size) override
|
|
||||||
{
|
|
||||||
return g_FileSystem->ReadLine(pOut, size, handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Write(const void* pData, size_t size) override
|
|
||||||
{
|
|
||||||
return static_cast<size_t>(g_FileSystem->Write(pData, size, handle_));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Seek(int pos, int seek_type) override
|
|
||||||
{
|
|
||||||
g_FileSystem->Seek(handle_, pos, static_cast<FileSystemSeek_t>(seek_type));
|
|
||||||
return !HasError();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Tell() override
|
|
||||||
{
|
|
||||||
return g_FileSystem->Tell(handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasError() override
|
|
||||||
{
|
|
||||||
return !handle_ || !g_FileSystem->IsOk(handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
int Flush() override
|
|
||||||
{
|
|
||||||
g_FileSystem->Flush(handle_);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EndOfFile() override
|
|
||||||
{
|
|
||||||
return g_FileSystem->EndOfFile(handle_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close() override
|
|
||||||
{
|
|
||||||
if (handle_)
|
|
||||||
{
|
|
||||||
g_FileSystem->Close(handle_);
|
|
||||||
handle_ = nullptr;;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ValveFile* AsValveFile()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileHandle_t handle() const
|
|
||||||
{
|
|
||||||
return handle_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
FileHandle_t handle_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class SystemFile : public FileObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
SystemFile(FILE* fp) : fp_(fp) {}
|
|
||||||
|
|
||||||
~SystemFile()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
static SystemFile* Open(const char* path, const char* mode)
|
|
||||||
{
|
|
||||||
FILE* fp = fopen(path, mode);
|
|
||||||
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new SystemFile(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool Delete(const char* path)
|
|
||||||
{
|
|
||||||
return unlink(path) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Read(void* pOut, size_t size) override
|
|
||||||
{
|
|
||||||
return fread(pOut, 1, size, fp_);
|
|
||||||
}
|
|
||||||
|
|
||||||
char* ReadLine(char* pOut, size_t size) override
|
|
||||||
{
|
|
||||||
return fgets(pOut, size, fp_);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Write(const void* pData, size_t size) override
|
|
||||||
{
|
|
||||||
return fwrite(pData, 1, size, fp_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Seek(int pos, int seek_type) override
|
|
||||||
{
|
|
||||||
return fseek(fp_, pos, seek_type) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Tell() override
|
|
||||||
{
|
|
||||||
return ftell(fp_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasError() override
|
|
||||||
{
|
|
||||||
return ferror(fp_) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Flush() override
|
|
||||||
{
|
|
||||||
return fflush(fp_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EndOfFile() override
|
|
||||||
{
|
|
||||||
return feof(fp_) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Close() override
|
|
||||||
{
|
|
||||||
if (fp_)
|
|
||||||
{
|
|
||||||
fclose(fp_);
|
|
||||||
fp_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual SystemFile* AsSystemFile()
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE* handle() const
|
|
||||||
{
|
|
||||||
return fp_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
FILE* fp_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // _INCLUDE_CFILESYSTEM_H_
|
|
@ -1,410 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "sh_list.h"
|
|
||||||
#include "amxmodx.h"
|
|
||||||
|
|
||||||
#include "CFlagManager.h"
|
|
||||||
|
|
||||||
void CFlagManager::SetFile(const char *Filename)
|
|
||||||
{
|
|
||||||
m_strConfigFile = build_pathname("%s/%s", get_localinfo("amxx_configsdir", "addons/amxmodx/configs"), Filename);
|
|
||||||
|
|
||||||
CreateIfNotExist();
|
|
||||||
}
|
|
||||||
|
|
||||||
const int CFlagManager::LoadFile(const int force)
|
|
||||||
{
|
|
||||||
CheckIfDisabled();
|
|
||||||
// If we're disabled get the hell out. now.
|
|
||||||
if (m_iDisabled)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// if we're not forcing this, and NeedToLoad says we dont have to
|
|
||||||
// then just stop
|
|
||||||
if (!force && !NeedToLoad())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->Clear();
|
|
||||||
|
|
||||||
|
|
||||||
// We need to load the file
|
|
||||||
|
|
||||||
FILE *File;
|
|
||||||
|
|
||||||
File=fopen(GetFile(),"r");
|
|
||||||
|
|
||||||
if (!File)
|
|
||||||
{
|
|
||||||
AMXXLOG_Log("[AMXX] FlagManager: Cannot open file \"%s\" (FILE pointer null!)", GetFile());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trying to copy this almost exactly as other configs are read...
|
|
||||||
char Line[512];
|
|
||||||
char TempLine[512];
|
|
||||||
|
|
||||||
char Command[256];
|
|
||||||
char Flags[256];
|
|
||||||
|
|
||||||
|
|
||||||
while (!feof(File) && fgets(Line, sizeof(Line), File))
|
|
||||||
{
|
|
||||||
char *nonconst= Line;
|
|
||||||
|
|
||||||
// Strip out comments
|
|
||||||
while (*nonconst)
|
|
||||||
{
|
|
||||||
if (*nonconst==';') // End the line at comments
|
|
||||||
{
|
|
||||||
*nonconst='\0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nonconst++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Command[0]='\0';
|
|
||||||
Flags[0]='\0';
|
|
||||||
|
|
||||||
// Extract the command
|
|
||||||
strncopy(TempLine, Line, sizeof(TempLine));
|
|
||||||
|
|
||||||
nonconst = TempLine;
|
|
||||||
|
|
||||||
char *start=NULL;
|
|
||||||
char *end=NULL;
|
|
||||||
|
|
||||||
// move up line until the first ", mark this down as the start
|
|
||||||
// then find the second " and mark it down as the end
|
|
||||||
while (*nonconst!='\0')
|
|
||||||
{
|
|
||||||
if (*nonconst=='"')
|
|
||||||
{
|
|
||||||
if (start==NULL)
|
|
||||||
{
|
|
||||||
start=nonconst+1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end=nonconst;
|
|
||||||
goto done_with_command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nonconst++;
|
|
||||||
}
|
|
||||||
done_with_command:
|
|
||||||
|
|
||||||
// invalid line?
|
|
||||||
if (start==NULL || end==NULL)
|
|
||||||
{
|
|
||||||
// TODO: maybe warn for an invalid non-commented line?
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*end='\0';
|
|
||||||
|
|
||||||
strncpy(Command,start,sizeof(Command)-1);
|
|
||||||
|
|
||||||
// Now do the same thing for the flags
|
|
||||||
nonconst=++end;
|
|
||||||
|
|
||||||
start=NULL;
|
|
||||||
end=NULL;
|
|
||||||
|
|
||||||
// move up line until the first ", mark this down as the start
|
|
||||||
// then find the second " and mark it down as the end
|
|
||||||
while (*nonconst!='\0')
|
|
||||||
{
|
|
||||||
if (*nonconst=='"')
|
|
||||||
{
|
|
||||||
if (start==NULL)
|
|
||||||
{
|
|
||||||
start=nonconst+1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
end=nonconst;
|
|
||||||
goto done_with_flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nonconst++;
|
|
||||||
}
|
|
||||||
done_with_flags:
|
|
||||||
// invalid line?
|
|
||||||
if (start==NULL || end==NULL)
|
|
||||||
{
|
|
||||||
// TODO: maybe warn for an invalid non-commented line?
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
*end='\0';
|
|
||||||
|
|
||||||
strncpy(Flags,start,sizeof(Flags)-1);
|
|
||||||
|
|
||||||
//if (!isalnum(*Command))
|
|
||||||
if (*Command == '"' || *Command == '\0')
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Done sucking the command and flags out of the line
|
|
||||||
// now insert this command into the linked list
|
|
||||||
|
|
||||||
AddFromFile(const_cast<const char*>(&Command[0]),&Flags[0]);
|
|
||||||
|
|
||||||
nonconst = Line;
|
|
||||||
*nonconst = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(File);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This gets called from LoadFile
|
|
||||||
* Do NOT flag the entries as NeedToWrite
|
|
||||||
* No comment is passed from the file because
|
|
||||||
* this should never get written
|
|
||||||
*/
|
|
||||||
void CFlagManager::AddFromFile(const char *Command, const char *Flags)
|
|
||||||
{
|
|
||||||
CFlagEntry *Entry=new CFlagEntry;
|
|
||||||
|
|
||||||
Entry->SetName(Command);
|
|
||||||
Entry->SetFlags(Flags);
|
|
||||||
|
|
||||||
// Link it
|
|
||||||
m_FlagList.push_back(Entry);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CFlagManager::LookupOrAdd(const char *Command, int &Flags, AMX *Plugin)
|
|
||||||
{
|
|
||||||
if (m_iDisabled) // if disabled in core.ini stop
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TempFlags=Flags;
|
|
||||||
if (TempFlags==-1)
|
|
||||||
{
|
|
||||||
TempFlags=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<CFlagEntry *>::iterator iter;
|
|
||||||
List<CFlagEntry *>::iterator end;
|
|
||||||
|
|
||||||
iter=m_FlagList.begin();
|
|
||||||
end=m_FlagList.end();
|
|
||||||
|
|
||||||
while (iter!=end)
|
|
||||||
{
|
|
||||||
if (strcmp((*iter)->GetName()->chars(),Command)==0)
|
|
||||||
{
|
|
||||||
CFlagEntry *Entry=(*iter);
|
|
||||||
|
|
||||||
if (Entry->IsHidden()) // "!" flag, exclude this function
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Found, byref the new flags
|
|
||||||
Flags=Entry->Flags();
|
|
||||||
|
|
||||||
// Move it to the back of the list for faster lookup for the rest
|
|
||||||
m_FlagList.erase(iter);
|
|
||||||
|
|
||||||
m_FlagList.push_back(Entry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// was not found, add it
|
|
||||||
|
|
||||||
CFlagEntry *Entry=new CFlagEntry;
|
|
||||||
|
|
||||||
Entry->SetName(Command);
|
|
||||||
Entry->SetFlags(TempFlags);
|
|
||||||
|
|
||||||
if (Plugin)
|
|
||||||
{
|
|
||||||
CPluginMngr::CPlugin* a = g_plugins.findPluginFast(Plugin);
|
|
||||||
|
|
||||||
if (a)
|
|
||||||
{
|
|
||||||
Entry->SetComment(a->getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This entry was added from a register_* native
|
|
||||||
// it needs to be written during map change
|
|
||||||
Entry->SetNeedWritten(1);
|
|
||||||
|
|
||||||
// Link it
|
|
||||||
m_FlagList.push_back(Entry);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void CFlagManager::WriteCommands(void)
|
|
||||||
{
|
|
||||||
if (m_iDisabled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<CFlagEntry *>::iterator iter;
|
|
||||||
List<CFlagEntry *>::iterator end;
|
|
||||||
FILE *File;
|
|
||||||
int NeedToRead=0;
|
|
||||||
|
|
||||||
// First off check the modified time of this file
|
|
||||||
// if it matches the stored modified time, then update
|
|
||||||
// after we write so we do not re-read next map
|
|
||||||
struct stat TempStat;
|
|
||||||
|
|
||||||
stat(GetFile(), &TempStat);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (TempStat.st_mtime != m_Stat.st_mtime)
|
|
||||||
{
|
|
||||||
NeedToRead=1;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
File = fopen(GetFile(), "a");
|
|
||||||
|
|
||||||
if (!File)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
iter=m_FlagList.begin();
|
|
||||||
end=m_FlagList.end();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while (iter!=end)
|
|
||||||
{
|
|
||||||
if ((*iter)->NeedWritten())
|
|
||||||
{
|
|
||||||
if ((*iter)->GetComment()->length())
|
|
||||||
{
|
|
||||||
fprintf(File,"\"%s\" \t\"%s\" ; %s\n",(*iter)->GetName()->chars(),(*iter)->GetFlags()->chars(),(*iter)->GetComment()->chars());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(File,"\"%s\" \t\"%s\"\n",(*iter)->GetName()->chars(),(*iter)->GetFlags()->chars());
|
|
||||||
}
|
|
||||||
(*iter)->SetNeedWritten(0);
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(File);
|
|
||||||
|
|
||||||
|
|
||||||
// If NeedToRead was 0, then update the timestamp
|
|
||||||
// that was saved so we do not re-read this file
|
|
||||||
// next map
|
|
||||||
if (!NeedToRead)
|
|
||||||
{
|
|
||||||
stat(GetFile(), &TempStat);
|
|
||||||
|
|
||||||
m_Stat.st_mtime=TempStat.st_mtime;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int CFlagManager::ShouldIAddThisCommand(const AMX *amx, const cell *params, const char *cmdname) const
|
|
||||||
{
|
|
||||||
// If flagmanager is disabled then ignore this
|
|
||||||
if (m_iDisabled)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// If 5th param exists it was compiled after this change was made
|
|
||||||
// if it does not exist, try our logic at the end of this function
|
|
||||||
// 5th param being > 0 means explicit yes
|
|
||||||
// < 0 means auto detect (default is -1), treat it like there was no 5th param
|
|
||||||
// 0 means explicit no
|
|
||||||
|
|
||||||
if ((params[0] / sizeof(cell)) >= 5)
|
|
||||||
{
|
|
||||||
if (params[5]>0) // This command was explicitly told to be included
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if (params[5]==0) // this command was explicitly told to NOT be used
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// auto detect if we should use this command
|
|
||||||
|
|
||||||
// if command access is -1 (default, not set to ADMIN_ALL or any other access), then no
|
|
||||||
if (params[3]==-1)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// if command is (or starts with) "say", then no
|
|
||||||
if (strncmp(cmdname,"say",3)==0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// else use it
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CFlagManager::Clear(void)
|
|
||||||
{
|
|
||||||
List<CFlagEntry *>::iterator iter;
|
|
||||||
List<CFlagEntry *>::iterator end;
|
|
||||||
|
|
||||||
iter=m_FlagList.begin();
|
|
||||||
end=m_FlagList.end();
|
|
||||||
|
|
||||||
while (iter!=end)
|
|
||||||
{
|
|
||||||
delete (*iter);
|
|
||||||
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_FlagList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CFlagManager::CheckIfDisabled(void)
|
|
||||||
{
|
|
||||||
if (atoi(get_localinfo("disableflagman","0"))==0)
|
|
||||||
{
|
|
||||||
m_iDisabled=0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_iDisabled=1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,231 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef CFLAGMANAGER_H
|
|
||||||
#define CFLAGMANAGER_H
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include "sh_list.h"
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "CLibrarySys.h"
|
|
||||||
|
|
||||||
class CFlagEntry
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
ke::AString m_strName; // command name ("amx_slap")
|
|
||||||
ke::AString m_strFlags; // string flags ("a","b")
|
|
||||||
ke::AString m_strComment; // comment to write ("; admincmd.amxx")
|
|
||||||
int m_iFlags; // bitmask flags
|
|
||||||
int m_iNeedWritten; // write this command on map change?
|
|
||||||
int m_iHidden; // set to 1 when the command is set to "!" access in
|
|
||||||
// the .ini file: this means do not process this command
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
CFlagEntry()
|
|
||||||
{
|
|
||||||
m_iNeedWritten=0;
|
|
||||||
m_iFlags=0;
|
|
||||||
m_iHidden=0;
|
|
||||||
};
|
|
||||||
const int NeedWritten(void) const
|
|
||||||
{
|
|
||||||
return m_iNeedWritten;
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetNeedWritten(const int i=1)
|
|
||||||
{
|
|
||||||
m_iNeedWritten=i;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ke::AString *GetName(void) const
|
|
||||||
{
|
|
||||||
return &m_strName;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ke::AString *GetFlags(void) const
|
|
||||||
{
|
|
||||||
return &m_strFlags;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ke::AString *GetComment(void) const
|
|
||||||
{
|
|
||||||
return &m_strComment;
|
|
||||||
};
|
|
||||||
|
|
||||||
const int Flags(void) const
|
|
||||||
{
|
|
||||||
return m_iFlags;
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetName(const char *data)
|
|
||||||
{
|
|
||||||
m_strName = data;
|
|
||||||
};
|
|
||||||
void SetFlags(const char *flags)
|
|
||||||
{
|
|
||||||
// If this is a "!" entry then stop
|
|
||||||
if (flags && flags[0]=='!')
|
|
||||||
{
|
|
||||||
SetHidden(1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_strFlags = flags;
|
|
||||||
m_iFlags=UTIL_ReadFlags(flags);
|
|
||||||
};
|
|
||||||
void SetFlags(const int flags)
|
|
||||||
{
|
|
||||||
m_iFlags=flags;
|
|
||||||
|
|
||||||
char FlagsString[32];
|
|
||||||
UTIL_GetFlags(FlagsString, flags);
|
|
||||||
|
|
||||||
m_strFlags = FlagsString;
|
|
||||||
};
|
|
||||||
void SetComment(const char *comment)
|
|
||||||
{
|
|
||||||
m_strComment = comment;
|
|
||||||
};
|
|
||||||
void SetHidden(int i=1)
|
|
||||||
{
|
|
||||||
m_iHidden=i;
|
|
||||||
};
|
|
||||||
int IsHidden(void) const
|
|
||||||
{
|
|
||||||
return m_iHidden;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
class CFlagManager
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
List<CFlagEntry *> m_FlagList;
|
|
||||||
ke::AString m_strConfigFile;
|
|
||||||
struct stat m_Stat;
|
|
||||||
int m_iForceRead;
|
|
||||||
int m_iDisabled;
|
|
||||||
|
|
||||||
|
|
||||||
void CreateIfNotExist(void) const
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopen(GetFile(), "r");
|
|
||||||
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
// File does not exist, create the header
|
|
||||||
fp = fopen(GetFile(), "a");
|
|
||||||
|
|
||||||
if (fp)
|
|
||||||
{
|
|
||||||
fprintf(fp,"; This file will store the commands used by plugins, and their access level\n");
|
|
||||||
fprintf(fp,"; To change the access of a command, edit the flags beside it and then\n");
|
|
||||||
fprintf(fp,"; change the server's map.\n;\n");
|
|
||||||
fprintf(fp,"; Example: If I wanted to change the amx_slap access to require\n");
|
|
||||||
fprintf(fp,"; RCON access (flag \"l\") I would change this:\n");
|
|
||||||
fprintf(fp,"; \"amx_slap\" \"e\" ; admincmd.amxx\n");
|
|
||||||
fprintf(fp,"; To this:\n");
|
|
||||||
fprintf(fp,"; \"amx_slap\" \"l\" ; admincmd.amxx\n;\n");
|
|
||||||
fprintf(fp,"; To disable a specific command from being used with the command manager\n");
|
|
||||||
fprintf(fp,"; and to only use the plugin-specified access set the flag to \"!\"\n;\n");
|
|
||||||
fprintf(fp,"; NOTE: The plugin name at the end is just for reference to what plugin\n");
|
|
||||||
fprintf(fp,"; uses what commands. It is ignored.\n\n");
|
|
||||||
fclose(fp);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Returns 1 if the timestamp for the file is different than the one we have loaded
|
|
||||||
* 0 otherwise
|
|
||||||
*/
|
|
||||||
inline int NeedToLoad(void)
|
|
||||||
{
|
|
||||||
struct stat TempStat;
|
|
||||||
|
|
||||||
stat(GetFile(), &TempStat);
|
|
||||||
|
|
||||||
// If the modified timestamp does not match the stored
|
|
||||||
// timestamp than we need to re-read this file.
|
|
||||||
// Otherwise, ignore the file.
|
|
||||||
if (TempStat.st_mtime != m_Stat.st_mtime)
|
|
||||||
{
|
|
||||||
// Save down the modified timestamp
|
|
||||||
m_Stat.st_mtime=TempStat.st_mtime;
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
|
|
||||||
CFlagManager()
|
|
||||||
{
|
|
||||||
memset(&m_Stat,0x0,sizeof(struct stat));
|
|
||||||
m_iDisabled=0;
|
|
||||||
m_iForceRead=0;
|
|
||||||
};
|
|
||||||
~CFlagManager()
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the filename in relation to amxmodx/configs
|
|
||||||
*/
|
|
||||||
void SetFile(const char *Filename="cmdaccess.ini");
|
|
||||||
|
|
||||||
const char *GetFile(void) const { return m_strConfigFile.chars(); };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the file, and load all entries
|
|
||||||
* Returns 1 on success, 0 on refusal (no need to), and -1 on error
|
|
||||||
*/
|
|
||||||
const int LoadFile(const int force=0);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the command exists in the list
|
|
||||||
* If it does, it byrefs the flags for it
|
|
||||||
* If it does not, it adds it to the list
|
|
||||||
* These are added from register_*cmd calls
|
|
||||||
*/
|
|
||||||
void LookupOrAdd(const char *Command, int &Flags, AMX *Plugin);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write the commands back to the file
|
|
||||||
*/
|
|
||||||
void WriteCommands(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add this straight from the cmdaccess.ini file
|
|
||||||
*/
|
|
||||||
void AddFromFile(const char *Command, const char *Flags);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this command should be added to flagman or not
|
|
||||||
* This is only checked when adding commands from the register_* natives
|
|
||||||
* If an admin manually adds a command to cmdaccess.ini it will be used
|
|
||||||
* regardless of whatever this function would say should be done with it
|
|
||||||
*/
|
|
||||||
int ShouldIAddThisCommand(const AMX *amx, const cell *params, const char *cmdname) const;
|
|
||||||
|
|
||||||
void Clear(void);
|
|
||||||
|
|
||||||
void CheckIfDisabled(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CFLAGMANAGER_H
|
|
@ -1,813 +1,80 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
#include "amxmodx.h"
|
* your option) any later version.
|
||||||
#include "debugger.h"
|
*
|
||||||
#include "binlog.h"
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
CForward::CForward(const char *name, ForwardExecType et, int numParams, const ForwardParam *paramTypes)
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
{
|
* General Public License for more details.
|
||||||
m_FuncName = name;
|
*
|
||||||
m_ExecType = et;
|
* You should have received a copy of the GNU General Public License
|
||||||
m_NumParams = numParams;
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
memcpy((void *)m_ParamTypes, paramTypes, numParams * sizeof(ForwardParam));
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
// find funcs
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
int func;
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
m_Funcs.clear();
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
for (CPluginMngr::iterator iter = g_plugins.begin(); iter; ++iter)
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
{
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
if ((*iter).isValid() && amx_FindPublic((*iter).getAMX(), name, &func) == AMX_ERR_NONE)
|
* you do not wish to do so, delete this exception statement from your
|
||||||
{
|
* version.
|
||||||
AMXForward tmp;
|
*/
|
||||||
tmp.pPlugin = &(*iter);
|
|
||||||
tmp.func = func;
|
#include <extdll.h>
|
||||||
m_Funcs.append(tmp);
|
#include <meta_api.h>
|
||||||
}
|
#include "amxmod.h"
|
||||||
}
|
#include "CForward.h"
|
||||||
|
|
||||||
m_Name = name;
|
void CForwardMngr::registerForward( CPluginMngr::CPlugin* p, int func , int type ){
|
||||||
}
|
|
||||||
|
CForward** a = &head[ type ];
|
||||||
cell CForward::execute(cell *params, ForwardPreparedArray *preparedArrays)
|
while(*a) a = &(*a)->next;
|
||||||
{
|
*a = new CForward( p , func );
|
||||||
cell realParams[FORWARD_MAX_PARAMS];
|
|
||||||
cell *physAddrs[FORWARD_MAX_PARAMS];
|
}
|
||||||
|
|
||||||
const int STRINGEX_MAXLENGTH = 128;
|
void CForwardMngr::clearForwards( CForward** a ){
|
||||||
|
while( *a ) {
|
||||||
cell globRetVal = 0;
|
CForward* b = (*a)->next;
|
||||||
|
delete *a;
|
||||||
for (size_t i = 0; i < m_Funcs.length(); ++i)
|
*a = b;
|
||||||
{
|
|
||||||
auto iter = &m_Funcs[i];
|
|
||||||
|
|
||||||
if (iter->pPlugin->isExecutable(iter->func))
|
|
||||||
{
|
|
||||||
// Get debug info
|
|
||||||
AMX *amx = iter->pPlugin->getAMX();
|
|
||||||
Debugger *pDebugger = (Debugger *)amx->userdata[UD_DEBUGGER];
|
|
||||||
|
|
||||||
if (pDebugger)
|
|
||||||
pDebugger->BeginExec();
|
|
||||||
|
|
||||||
// handle strings & arrays & values by reference
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < m_NumParams; ++i)
|
|
||||||
{
|
|
||||||
if (m_ParamTypes[i] == FP_STRING || m_ParamTypes[i] == FP_STRINGEX)
|
|
||||||
{
|
|
||||||
const char *str = reinterpret_cast<const char*>(params[i]);
|
|
||||||
cell *tmp;
|
|
||||||
if (!str)
|
|
||||||
str = "";
|
|
||||||
amx_Allot(amx, (m_ParamTypes[i] == FP_STRING) ? strlen(str) + 1 : STRINGEX_MAXLENGTH, &realParams[i], &tmp);
|
|
||||||
amx_SetStringOld(tmp, str, 0, 0);
|
|
||||||
physAddrs[i] = tmp;
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_ARRAY)
|
|
||||||
{
|
|
||||||
cell *tmp;
|
|
||||||
amx_Allot(amx, preparedArrays[params[i]].size, &realParams[i], &tmp);
|
|
||||||
physAddrs[i] = tmp;
|
|
||||||
|
|
||||||
if (preparedArrays[params[i]].type == Type_Cell)
|
|
||||||
{
|
|
||||||
memcpy(tmp, preparedArrays[params[i]].ptr, preparedArrays[params[i]].size * sizeof(cell));
|
|
||||||
} else {
|
|
||||||
char *data = (char*)preparedArrays[params[i]].ptr;
|
|
||||||
|
|
||||||
for (unsigned int j = 0; j < preparedArrays[params[i]].size; ++j)
|
|
||||||
*tmp++ = (static_cast<cell>(*data++)) & 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_CELL_BYREF || m_ParamTypes[i] == FP_FLOAT_BYREF)
|
|
||||||
{
|
|
||||||
cell *tmp;
|
|
||||||
amx_Allot(amx, 1, &realParams[i], &tmp);
|
|
||||||
physAddrs[i] = tmp;
|
|
||||||
|
|
||||||
if (m_ParamTypes[i] == FP_CELL_BYREF)
|
|
||||||
{
|
|
||||||
memcpy(tmp, reinterpret_cast<cell *>(params[i]), sizeof(cell));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(tmp, reinterpret_cast<REAL *>(params[i]), sizeof(REAL));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
realParams[i] = params[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Push the parameters in reverse order. Weird, unfriendly part of Small 3.0!
|
|
||||||
for (i = m_NumParams-1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
amx_Push(amx, realParams[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// exec
|
|
||||||
cell retVal = 0;
|
|
||||||
#if defined BINLOG_ENABLED
|
|
||||||
g_BinLog.WriteOp(BinLog_CallPubFunc, iter->pPlugin->getId(), iter->func);
|
|
||||||
#endif
|
|
||||||
int err = amx_Exec(amx, &retVal, iter->func);
|
|
||||||
|
|
||||||
// log runtime error, if any
|
|
||||||
if (err != AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
//Did something else set an error?
|
|
||||||
if (pDebugger && pDebugger->ErrorExists())
|
|
||||||
{
|
|
||||||
//we don't care, something else logged the error.
|
|
||||||
}
|
|
||||||
else if (err != -1)
|
|
||||||
{
|
|
||||||
//nothing logged the error so spit it out anyway
|
|
||||||
LogError(amx, err, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
amx->error = AMX_ERR_NONE;
|
|
||||||
|
|
||||||
if (pDebugger)
|
|
||||||
pDebugger->EndExec();
|
|
||||||
|
|
||||||
// cleanup strings & arrays & values by reference
|
|
||||||
for (i = 0; i < m_NumParams; ++i)
|
|
||||||
{
|
|
||||||
if (m_ParamTypes[i] == FP_STRING)
|
|
||||||
{
|
|
||||||
amx_Release(amx, realParams[i]);
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_STRINGEX)
|
|
||||||
{
|
|
||||||
// copy back
|
|
||||||
amx_GetStringOld(reinterpret_cast<char*>(params[i]), physAddrs[i], 0);
|
|
||||||
amx_Release(amx, realParams[i]);
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_ARRAY)
|
|
||||||
{
|
|
||||||
// copy back
|
|
||||||
if (preparedArrays[params[i]].copyBack)
|
|
||||||
{
|
|
||||||
cell *tmp = physAddrs[i];
|
|
||||||
if (preparedArrays[params[i]].type == Type_Cell)
|
|
||||||
{
|
|
||||||
memcpy(preparedArrays[params[i]].ptr, tmp, preparedArrays[params[i]].size * sizeof(cell));
|
|
||||||
} else {
|
|
||||||
char *data = (char*)preparedArrays[params[i]].ptr;
|
|
||||||
|
|
||||||
for (unsigned int j = 0; j < preparedArrays[params[i]].size; ++j)
|
|
||||||
*data++ = static_cast<char>(*tmp++ & 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
amx_Release(amx, realParams[i]);
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_CELL_BYREF || m_ParamTypes[i] == FP_FLOAT_BYREF)
|
|
||||||
{
|
|
||||||
//copy back
|
|
||||||
cell *tmp = physAddrs[i];
|
|
||||||
if (m_ParamTypes[i] == FP_CELL_BYREF)
|
|
||||||
{
|
|
||||||
memcpy(reinterpret_cast<cell *>(params[i]), tmp, sizeof(cell));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(reinterpret_cast<REAL *>(params[i]), tmp, sizeof(REAL));
|
|
||||||
}
|
|
||||||
amx_Release(amx, realParams[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// decide what to do (based on exectype and retval)
|
|
||||||
switch (m_ExecType)
|
|
||||||
{
|
|
||||||
case ET_IGNORE:
|
|
||||||
break;
|
|
||||||
case ET_STOP:
|
|
||||||
if (retVal > 0)
|
|
||||||
return retVal;
|
|
||||||
case ET_STOP2:
|
|
||||||
if (retVal == 1)
|
|
||||||
return 1;
|
|
||||||
else if (retVal > globRetVal)
|
|
||||||
globRetVal = retVal;
|
|
||||||
break;
|
|
||||||
case ET_CONTINUE:
|
|
||||||
if (retVal > globRetVal)
|
|
||||||
globRetVal = retVal;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return globRetVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSPForward::Set(int func, AMX *amx, int numParams, const ForwardParam *paramTypes)
|
|
||||||
{
|
|
||||||
char name[sNAMEMAX];
|
|
||||||
m_Func = func;
|
|
||||||
m_Amx = amx;
|
|
||||||
m_NumParams = numParams;
|
|
||||||
memcpy((void *)m_ParamTypes, paramTypes, numParams * sizeof(ForwardParam));
|
|
||||||
m_HasFunc = true;
|
|
||||||
isFree = false;
|
|
||||||
name[0] = '\0';
|
|
||||||
amx_GetPublic(amx, func, name);
|
|
||||||
m_Name = name;
|
|
||||||
m_ToDelete = false;
|
|
||||||
m_InExec = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSPForward::Set(const char *funcName, AMX *amx, int numParams, const ForwardParam *paramTypes)
|
|
||||||
{
|
|
||||||
m_Amx = amx;
|
|
||||||
m_NumParams = numParams;
|
|
||||||
memcpy((void *)m_ParamTypes, paramTypes, numParams * sizeof(ForwardParam));
|
|
||||||
m_HasFunc = (amx_FindPublic(amx, funcName, &m_Func) == AMX_ERR_NONE);
|
|
||||||
isFree = false;
|
|
||||||
m_Name = funcName;
|
|
||||||
m_ToDelete = false;
|
|
||||||
m_InExec = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell CSPForward::execute(cell *params, ForwardPreparedArray *preparedArrays)
|
|
||||||
{
|
|
||||||
if (isFree)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
const int STRINGEX_MAXLENGTH = 128;
|
|
||||||
|
|
||||||
cell realParams[FORWARD_MAX_PARAMS];
|
|
||||||
cell *physAddrs[FORWARD_MAX_PARAMS];
|
|
||||||
|
|
||||||
if (!m_HasFunc || m_ToDelete)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(m_Amx);
|
|
||||||
if (!pPlugin->isExecutable(m_Func))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
m_InExec = true;
|
|
||||||
|
|
||||||
Debugger *pDebugger = (Debugger *)m_Amx->userdata[UD_DEBUGGER];
|
|
||||||
if (pDebugger)
|
|
||||||
pDebugger->BeginExec();
|
|
||||||
|
|
||||||
// handle strings & arrays & values by reference
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < m_NumParams; ++i)
|
|
||||||
{
|
|
||||||
if (m_ParamTypes[i] == FP_STRING || m_ParamTypes[i] == FP_STRINGEX)
|
|
||||||
{
|
|
||||||
const char *str = reinterpret_cast<const char*>(params[i]);
|
|
||||||
if (!str)
|
|
||||||
str = "";
|
|
||||||
cell *tmp;
|
|
||||||
amx_Allot(m_Amx, (m_ParamTypes[i] == FP_STRING) ? strlen(str) + 1 : STRINGEX_MAXLENGTH, &realParams[i], &tmp);
|
|
||||||
amx_SetStringOld(tmp, str, 0, 0);
|
|
||||||
physAddrs[i] = tmp;
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_ARRAY)
|
|
||||||
{
|
|
||||||
cell *tmp;
|
|
||||||
amx_Allot(m_Amx, preparedArrays[params[i]].size, &realParams[i], &tmp);
|
|
||||||
physAddrs[i] = tmp;
|
|
||||||
|
|
||||||
if (preparedArrays[params[i]].type == Type_Cell)
|
|
||||||
{
|
|
||||||
memcpy(tmp, preparedArrays[params[i]].ptr, preparedArrays[params[i]].size * sizeof(cell));
|
|
||||||
} else {
|
|
||||||
char *data = (char*)preparedArrays[params[i]].ptr;
|
|
||||||
|
|
||||||
for (unsigned int j = 0; j < preparedArrays[params[i]].size; ++j)
|
|
||||||
*tmp++ = (static_cast<cell>(*data++)) & 0xFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_CELL_BYREF || m_ParamTypes[i] == FP_FLOAT_BYREF)
|
|
||||||
{
|
|
||||||
cell *tmp;
|
|
||||||
amx_Allot(m_Amx, 1, &realParams[i], &tmp);
|
|
||||||
physAddrs[i] = tmp;
|
|
||||||
|
|
||||||
if (m_ParamTypes[i] == FP_CELL_BYREF)
|
|
||||||
{
|
|
||||||
memcpy(tmp, reinterpret_cast<cell *>(params[i]), sizeof(cell));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(tmp, reinterpret_cast<REAL *>(params[i]), sizeof(REAL));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
realParams[i] = params[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = m_NumParams - 1; i >= 0; i--)
|
|
||||||
amx_Push(m_Amx, realParams[i]);
|
|
||||||
|
|
||||||
// exec
|
|
||||||
cell retVal = 0;
|
|
||||||
#if defined BINLOG_ENABLED
|
|
||||||
g_BinLog.WriteOp(BinLog_CallPubFunc, pPlugin->getId(), m_Func);
|
|
||||||
#endif
|
|
||||||
int err = amx_Exec(m_Amx, &retVal, m_Func);
|
|
||||||
|
|
||||||
if (err != AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
//Did something else set an error?
|
|
||||||
if (pDebugger && pDebugger->ErrorExists())
|
|
||||||
{
|
|
||||||
//we don't care, something else logged the error.
|
|
||||||
}
|
|
||||||
else if (err != -1)
|
|
||||||
{
|
|
||||||
//nothing logged the error so spit it out anyway
|
|
||||||
LogError(m_Amx, err, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pDebugger)
|
|
||||||
pDebugger->EndExec();
|
|
||||||
|
|
||||||
m_Amx->error = AMX_ERR_NONE;
|
|
||||||
|
|
||||||
// cleanup strings & arrays & values by reference
|
|
||||||
for (i = 0; i < m_NumParams; ++i)
|
|
||||||
{
|
|
||||||
if (m_ParamTypes[i] == FP_STRING)
|
|
||||||
{
|
|
||||||
amx_Release(m_Amx, realParams[i]);
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_STRINGEX)
|
|
||||||
{
|
|
||||||
// copy back
|
|
||||||
amx_GetStringOld(reinterpret_cast<char*>(params[i]), physAddrs[i], 0);
|
|
||||||
amx_Release(m_Amx, realParams[i]);
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_ARRAY)
|
|
||||||
{
|
|
||||||
// copy back
|
|
||||||
if (preparedArrays[params[i]].copyBack)
|
|
||||||
{
|
|
||||||
cell *tmp = physAddrs[i];
|
|
||||||
if (preparedArrays[params[i]].type == Type_Cell)
|
|
||||||
{
|
|
||||||
memcpy(preparedArrays[params[i]].ptr, tmp, preparedArrays[params[i]].size * sizeof(cell));
|
|
||||||
} else {
|
|
||||||
char *data = (char*)preparedArrays[params[i]].ptr;
|
|
||||||
|
|
||||||
for (unsigned int j = 0; j < preparedArrays[params[i]].size; ++j)
|
|
||||||
*data++ = static_cast<char>(*tmp++ & 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
amx_Release(m_Amx, realParams[i]);
|
|
||||||
}
|
|
||||||
else if (m_ParamTypes[i] == FP_CELL_BYREF || m_ParamTypes[i] == FP_FLOAT_BYREF)
|
|
||||||
{
|
|
||||||
//copy back
|
|
||||||
cell *tmp = physAddrs[i];
|
|
||||||
if (m_ParamTypes[i] == FP_CELL_BYREF)
|
|
||||||
{
|
|
||||||
memcpy(reinterpret_cast<cell *>(params[i]), tmp, sizeof(cell));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy(reinterpret_cast<REAL *>(params[i]), tmp, sizeof(REAL));
|
|
||||||
}
|
|
||||||
amx_Release(m_Amx, realParams[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_InExec = false;
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CForwardMngr::registerForward(const char *funcName, ForwardExecType et, int numParams, const ForwardParam * paramTypes)
|
|
||||||
{
|
|
||||||
int retVal = m_Forwards.length() << 1;
|
|
||||||
CForward *tmp = new CForward(funcName, et, numParams, paramTypes);
|
|
||||||
|
|
||||||
if (!tmp)
|
|
||||||
{
|
|
||||||
return -1; // should be invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Forwards.append(tmp);
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CForwardMngr::registerSPForward(int func, AMX *amx, int numParams, const ForwardParam *paramTypes)
|
|
||||||
{
|
|
||||||
int retVal = -1;
|
|
||||||
CSPForward *pForward;
|
|
||||||
|
|
||||||
if (!m_FreeSPForwards.empty())
|
|
||||||
{
|
|
||||||
retVal = m_FreeSPForwards.front();
|
|
||||||
pForward = m_SPForwards[retVal >> 1];
|
|
||||||
pForward->Set(func, amx, numParams, paramTypes);
|
|
||||||
|
|
||||||
if (pForward->getFuncsNum() == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
m_FreeSPForwards.pop();
|
|
||||||
} else {
|
|
||||||
retVal = (m_SPForwards.length() << 1) | 1;
|
|
||||||
pForward = new CSPForward();
|
|
||||||
|
|
||||||
if (!pForward)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
pForward->Set(func, amx, numParams, paramTypes);
|
|
||||||
|
|
||||||
if (pForward->getFuncsNum() == 0)
|
|
||||||
{
|
|
||||||
delete pForward;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_SPForwards.append(pForward);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CForwardMngr::registerSPForward(const char *funcName, AMX *amx, int numParams, const ForwardParam *paramTypes)
|
|
||||||
{
|
|
||||||
int retVal = (m_SPForwards.length() << 1) | 1;
|
|
||||||
CSPForward *pForward;
|
|
||||||
|
|
||||||
if (!m_FreeSPForwards.empty())
|
|
||||||
{
|
|
||||||
retVal = m_FreeSPForwards.front();
|
|
||||||
pForward = m_SPForwards[retVal>>1]; // >>1 because unregisterSPForward pushes the id which contains the sp flag
|
|
||||||
pForward->Set(funcName, amx, numParams, paramTypes);
|
|
||||||
|
|
||||||
if (pForward->getFuncsNum() == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
m_FreeSPForwards.pop();
|
|
||||||
} else {
|
|
||||||
pForward = new CSPForward();
|
|
||||||
|
|
||||||
if (!pForward)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
pForward->Set(funcName, amx, numParams, paramTypes);
|
|
||||||
|
|
||||||
if (pForward->getFuncsNum() == 0)
|
|
||||||
{
|
|
||||||
delete pForward;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_SPForwards.append(pForward);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CForwardMngr::isIdValid(int id) const
|
|
||||||
{
|
|
||||||
return (id >= 0) && ((id & 1) ? (static_cast<size_t>(id >> 1) < m_SPForwards.length()) : (static_cast<size_t>(id >> 1) < m_Forwards.length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
cell CForwardMngr::executeForwards(int id, cell *params)
|
|
||||||
{
|
|
||||||
int retVal;
|
|
||||||
if (id & 1)
|
|
||||||
{
|
|
||||||
CSPForward *fwd = m_SPForwards[id >> 1];
|
|
||||||
retVal = fwd->execute(params, m_TmpArrays);
|
|
||||||
if (fwd->m_ToDelete)
|
|
||||||
{
|
|
||||||
fwd->m_ToDelete = false;
|
|
||||||
unregisterSPForward(id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
retVal = m_Forwards[id >> 1]->execute(params, m_TmpArrays);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_TmpArraysNum = 0;
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *CForwardMngr::getFuncName(int id) const
|
|
||||||
{
|
|
||||||
if (!isIdValid(id))
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return (id & 1) ? m_SPForwards[id >> 1]->getFuncName() : m_Forwards[id >> 1]->getFuncName();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CForwardMngr::getFuncsNum(int id) const
|
|
||||||
{
|
|
||||||
if (!isIdValid(id))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return (id & 1) ? m_SPForwards[id >> 1]->getFuncsNum() : m_Forwards[id >> 1]->getFuncsNum();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CForwardMngr::getParamsNum(int id) const
|
|
||||||
{
|
|
||||||
return (id & 1) ? m_SPForwards[id >> 1]->getParamsNum() : m_Forwards[id >> 1]->getParamsNum();
|
|
||||||
}
|
|
||||||
|
|
||||||
ForwardParam CForwardMngr::getParamType(int id, int paramNum) const
|
|
||||||
{
|
|
||||||
if (!isIdValid(id))
|
|
||||||
{
|
|
||||||
return FP_DONE;
|
|
||||||
}
|
}
|
||||||
return (id & 1) ? m_SPForwards[id >> 1]->getParamType(paramNum) : m_Forwards[id >> 1]->getParamType(paramNum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CForwardMngr::clear()
|
void CForwardMngr::clear()
|
||||||
{
|
{
|
||||||
size_t i;
|
for ( int a = 0; a < FORWARD_NUM; ++a )
|
||||||
|
clearForwards( &head[ a ] );
|
||||||
for (i = 0; i < m_Forwards.length(); ++i)
|
|
||||||
{
|
|
||||||
delete m_Forwards[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < m_SPForwards.length(); ++i)
|
void CForwardMngr::executeForwards( int type , int num , int player ) {
|
||||||
|
|
||||||
|
cell ret = 0;
|
||||||
|
int err;
|
||||||
|
CForward* a = head[ type ];
|
||||||
|
|
||||||
|
while ( a )
|
||||||
{
|
{
|
||||||
delete m_SPForwards[i];
|
if ( a->getPlugin()->isExecutable( a->getFunction() ) )
|
||||||
}
|
|
||||||
|
|
||||||
m_Forwards.clear();
|
|
||||||
m_SPForwards.clear();
|
|
||||||
|
|
||||||
while (!m_FreeSPForwards.empty())
|
|
||||||
{
|
{
|
||||||
m_FreeSPForwards.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_TmpArraysNum = 0;
|
if ((err = amx_Exec(a->getPlugin()->getAMX(), &ret, a->getFunction() , num, player)) != AMX_ERR_NONE)
|
||||||
}
|
UTIL_Log("[AMXX] Run time error %d on line %ld (plugin \"%s\")", err,a->getPlugin()->getAMX()->curline,a->getPlugin()->getName());
|
||||||
|
|
||||||
bool CForwardMngr::isSPForward(int id) const
|
if ( ret )
|
||||||
{
|
|
||||||
return ((id & 1) == 0) ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CForwardMngr::unregisterSPForward(int id)
|
|
||||||
{
|
|
||||||
//make sure the id is valid
|
|
||||||
if (!isIdValid(id) || m_SPForwards.at(id >> 1)->isFree)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSPForward *fwd = m_SPForwards.at(id >> 1);
|
|
||||||
|
|
||||||
if (fwd->m_InExec)
|
|
||||||
{
|
|
||||||
fwd->m_ToDelete = true;
|
|
||||||
} else {
|
|
||||||
fwd->isFree = true;
|
|
||||||
m_FreeSPForwards.push(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int CForwardMngr::duplicateSPForward(int id)
|
|
||||||
{
|
|
||||||
if (!isIdValid(id) || m_SPForwards.at(id >> 1)->isFree)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSPForward *fwd = m_SPForwards.at(id >> 1);
|
|
||||||
|
|
||||||
return registerSPForward(fwd->m_Func, fwd->m_Amx, fwd->m_NumParams, fwd->m_ParamTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CForwardMngr::isSameSPForward(int id1, int id2)
|
|
||||||
{
|
|
||||||
if (!isIdValid(id1) || !isIdValid(id2))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSPForward *fwd1 = m_SPForwards.at(id1 >> 1);
|
|
||||||
CSPForward *fwd2 = m_SPForwards.at(id2 >> 1);
|
|
||||||
|
|
||||||
if (fwd1->isFree || fwd2->isFree)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((fwd1->m_Amx == fwd2->m_Amx)
|
|
||||||
&& (fwd1->m_Func == fwd2->m_Func)
|
|
||||||
&& (fwd1->m_NumParams == fwd2->m_NumParams));
|
|
||||||
}
|
|
||||||
|
|
||||||
int registerForwardC(const char *funcName, ForwardExecType et, cell *list, size_t num)
|
|
||||||
{
|
|
||||||
ForwardParam params[FORWARD_MAX_PARAMS];
|
|
||||||
|
|
||||||
for (size_t i=0; i<num; i++)
|
|
||||||
{
|
|
||||||
params[i] = static_cast<ForwardParam>(list[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_forwards.registerForward(funcName, et, num, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
int registerForward(const char *funcName, ForwardExecType et, ...)
|
|
||||||
{
|
|
||||||
int curParam = 0;
|
|
||||||
|
|
||||||
va_list argptr;
|
|
||||||
va_start(argptr, et);
|
|
||||||
|
|
||||||
ForwardParam params[FORWARD_MAX_PARAMS];
|
|
||||||
ForwardParam tmp;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (curParam == FORWARD_MAX_PARAMS)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
tmp = (ForwardParam)va_arg(argptr, int);
|
|
||||||
|
|
||||||
if (tmp == FP_DONE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
params[curParam] = tmp;
|
|
||||||
++curParam;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(argptr);
|
a = a->next;
|
||||||
|
|
||||||
return g_forwards.registerForward(funcName, et, curParam, params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int registerSPForwardByNameC(AMX *amx, const char *funcName, cell *list, size_t num)
|
|
||||||
{
|
|
||||||
ForwardParam params[FORWARD_MAX_PARAMS];
|
|
||||||
|
|
||||||
for (size_t i=0; i<num; i++)
|
|
||||||
params[i] = static_cast<ForwardParam>(list[i]);
|
|
||||||
|
|
||||||
return g_forwards.registerSPForward(funcName, amx, num, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
int registerSPForwardByName(AMX *amx, const char *funcName, ...)
|
|
||||||
{
|
|
||||||
int curParam = 0;
|
|
||||||
|
|
||||||
va_list argptr;
|
|
||||||
va_start(argptr, funcName);
|
|
||||||
|
|
||||||
ForwardParam params[FORWARD_MAX_PARAMS];
|
|
||||||
ForwardParam tmp;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (curParam == FORWARD_MAX_PARAMS)
|
|
||||||
break;
|
|
||||||
|
|
||||||
tmp = (ForwardParam)va_arg(argptr, int);
|
|
||||||
|
|
||||||
if (tmp == FP_DONE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
params[curParam] = tmp;
|
|
||||||
++curParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(argptr);
|
|
||||||
|
|
||||||
return g_forwards.registerSPForward(funcName, amx, curParam, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
int registerSPForward(AMX *amx, int func, ...)
|
|
||||||
{
|
|
||||||
int curParam = 0;
|
|
||||||
|
|
||||||
va_list argptr;
|
|
||||||
va_start(argptr, func);
|
|
||||||
|
|
||||||
ForwardParam params[FORWARD_MAX_PARAMS];
|
|
||||||
ForwardParam tmp;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (curParam == FORWARD_MAX_PARAMS)
|
|
||||||
break;
|
|
||||||
|
|
||||||
tmp = (ForwardParam)va_arg(argptr, int);
|
|
||||||
|
|
||||||
if (tmp == FP_DONE)
|
|
||||||
break;
|
|
||||||
|
|
||||||
params[curParam] = tmp;
|
|
||||||
++curParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(argptr);
|
|
||||||
|
|
||||||
return g_forwards.registerSPForward(func, amx, curParam, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
cell executeForwards(int id, ...)
|
|
||||||
{
|
|
||||||
if (!g_forwards.isIdValid(id))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
cell params[FORWARD_MAX_PARAMS];
|
|
||||||
|
|
||||||
int paramsNum = g_forwards.getParamsNum(id);
|
|
||||||
|
|
||||||
va_list argptr;
|
|
||||||
va_start(argptr, id);
|
|
||||||
|
|
||||||
ForwardParam param_type;
|
|
||||||
|
|
||||||
for (int i = 0; i < paramsNum && i < FORWARD_MAX_PARAMS; ++i)
|
|
||||||
{
|
|
||||||
param_type = g_forwards.getParamType(id, i);
|
|
||||||
if (param_type == FP_FLOAT)
|
|
||||||
{
|
|
||||||
REAL tmp = (REAL)va_arg(argptr, double); // floats get converted to doubles
|
|
||||||
params[i] = amx_ftoc(tmp);
|
|
||||||
}
|
|
||||||
else if(param_type == FP_FLOAT_BYREF)
|
|
||||||
{
|
|
||||||
REAL *tmp = reinterpret_cast<REAL *>(va_arg(argptr, double*));
|
|
||||||
params[i] = reinterpret_cast<cell>(tmp);
|
|
||||||
}
|
|
||||||
else if(param_type == FP_CELL_BYREF)
|
|
||||||
{
|
|
||||||
cell *tmp = reinterpret_cast<cell *>(va_arg(argptr, cell*));
|
|
||||||
params[i] = reinterpret_cast<cell>(tmp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
params[i] = (cell)va_arg(argptr, cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(argptr);
|
|
||||||
|
|
||||||
return g_forwards.executeForwards(id, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
cell CForwardMngr::prepareArray(void *ptr, unsigned int size, ForwardArrayElemType type, bool copyBack)
|
|
||||||
{
|
|
||||||
if (m_TmpArraysNum >= FORWARD_MAX_PARAMS)
|
|
||||||
{
|
|
||||||
#ifdef MEMORY_TEST
|
|
||||||
m_validateAllAllocUnits();
|
|
||||||
#endif // MEMORY_TEST
|
|
||||||
|
|
||||||
AMXXLOG_Log("[AMXX] Forwards with more than 32 parameters are not supported (tried to prepare array # %d).", m_TmpArraysNum + 1);
|
|
||||||
m_TmpArraysNum = 0;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_TmpArrays[m_TmpArraysNum].ptr = ptr;
|
|
||||||
m_TmpArrays[m_TmpArraysNum].size = size;
|
|
||||||
m_TmpArrays[m_TmpArraysNum].type = type;
|
|
||||||
m_TmpArrays[m_TmpArraysNum].copyBack = copyBack;
|
|
||||||
|
|
||||||
return m_TmpArraysNum++;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell prepareCellArray(cell *ptr, unsigned int size, bool copyBack)
|
|
||||||
{
|
|
||||||
return g_forwards.prepareArray((void*)ptr, size, Type_Cell, copyBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
cell prepareCharArray(char *ptr, unsigned int size, bool copyBack)
|
|
||||||
{
|
|
||||||
return g_forwards.prepareArray((void*)ptr, size, Type_Char, copyBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unregisterSPForward(int id)
|
|
||||||
{
|
|
||||||
g_forwards.unregisterSPForward(id);
|
|
||||||
}
|
}
|
@ -1,226 +1,115 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
/*
|
* your option) any later version.
|
||||||
CForward.h
|
*
|
||||||
forwards
|
* This program is distributed in the hope that it will be useful, but
|
||||||
1) normal forwards: called in all plugins
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
2) single plugin (sp) forwards: called in one plugin
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
The SP Forwards are handled differently because they are expected to be created / deleted
|
*
|
||||||
often, but the "normal" forwards are expected to be initialized at start up.
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
Note about forward ids:
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
for normal forwards: <index to vector> << 1
|
*
|
||||||
for sp forwards: (<index to vector> << 1) | 1
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FORWARD_H
|
#ifndef FORWARD_H
|
||||||
#define FORWARD_H
|
#define FORWARD_H
|
||||||
|
|
||||||
#include <stdarg.h>
|
// *****************************************************
|
||||||
#include "sh_stack.h"
|
// class CmdMngr
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
const int FORWARD_MAX_PARAMS = 32;
|
#define FORWARD_NUM 12
|
||||||
|
|
||||||
enum ForwardExecType
|
enum {
|
||||||
{
|
FF_ClientCommand,
|
||||||
ET_IGNORE = 0, // Ignore return vaue
|
FF_ClientConnect,
|
||||||
ET_STOP, // Stop on PLUGIN_HANDLED
|
FF_ClientDisconnect,
|
||||||
ET_STOP2, // Stop on PLUGIN_HANDLED, continue on other values, return biggest return value
|
FF_ClientInfoChanged,
|
||||||
ET_CONTINUE, // Continue; return biggest return value
|
FF_ClientPutInServer,
|
||||||
};
|
FF_PluginInit,
|
||||||
|
FF_PluginCfg,
|
||||||
enum ForwardParam
|
FF_PluginPrecache,
|
||||||
{
|
FF_PluginLog,
|
||||||
FP_DONE = -1, // specify this as the last argument
|
FF_PluginEnd,
|
||||||
// only tells the function that there are no more arguments
|
FF_InconsistentFile,
|
||||||
FP_CELL, // normal cell
|
FF_ClientAuthorized,
|
||||||
FP_FLOAT, // float; used as normal cell though
|
|
||||||
FP_STRING, // string
|
|
||||||
FP_STRINGEX, // string; will be updated to the last function's value
|
|
||||||
FP_ARRAY, // array; use the return value of prepareArray.
|
|
||||||
FP_CELL_BYREF, // cell; pass by reference
|
|
||||||
FP_FLOAT_BYREF, // float; pass by reference
|
|
||||||
};
|
|
||||||
|
|
||||||
// for prepareArray
|
|
||||||
enum ForwardArrayElemType
|
|
||||||
{
|
|
||||||
Type_Cell = 0,
|
|
||||||
Type_Char
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ForwardPreparedArray
|
|
||||||
{
|
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
ForwardArrayElemType type;
|
|
||||||
|
|
||||||
unsigned int size;
|
|
||||||
bool copyBack;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Normal forward
|
|
||||||
class CForward
|
|
||||||
{
|
|
||||||
const char *m_FuncName;
|
|
||||||
ForwardExecType m_ExecType;
|
|
||||||
int m_NumParams;
|
|
||||||
ke::AString m_Name;
|
|
||||||
|
|
||||||
struct AMXForward
|
|
||||||
{
|
|
||||||
CPluginMngr::CPlugin *pPlugin;
|
|
||||||
int func;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef ke::Vector<AMXForward> AMXForwardList;
|
|
||||||
|
|
||||||
AMXForwardList m_Funcs;
|
|
||||||
ForwardParam m_ParamTypes[FORWARD_MAX_PARAMS];
|
|
||||||
|
|
||||||
public:
|
|
||||||
CForward(const char *name, ForwardExecType et, int numParams, const ForwardParam * paramTypes);
|
|
||||||
CForward() {} // leaves everything unitialized'
|
|
||||||
|
|
||||||
cell execute(cell *params, ForwardPreparedArray *preparedArrays);
|
|
||||||
|
|
||||||
int getParamsNum() const
|
|
||||||
{
|
|
||||||
return m_NumParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getFuncsNum() const
|
|
||||||
{
|
|
||||||
return m_Funcs.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *getFuncName() const
|
|
||||||
{
|
|
||||||
return m_Name.chars();
|
|
||||||
}
|
|
||||||
|
|
||||||
ForwardParam getParamType(int paramId) const
|
|
||||||
{
|
|
||||||
if (paramId < 0 || paramId >= m_NumParams)
|
|
||||||
return FP_DONE;
|
|
||||||
|
|
||||||
return m_ParamTypes[paramId];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Single plugin forward
|
|
||||||
class CSPForward
|
|
||||||
{
|
|
||||||
friend class CForwardMngr;
|
|
||||||
int m_NumParams;
|
|
||||||
|
|
||||||
ForwardParam m_ParamTypes[FORWARD_MAX_PARAMS];
|
|
||||||
AMX *m_Amx;
|
|
||||||
|
|
||||||
int m_Func;
|
|
||||||
bool m_HasFunc;
|
|
||||||
ke::AString m_Name;
|
|
||||||
bool m_InExec;
|
|
||||||
bool m_ToDelete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool isFree;
|
|
||||||
public:
|
|
||||||
CSPForward() { m_HasFunc = false; }
|
|
||||||
void Set(const char *funcName, AMX *amx, int numParams, const ForwardParam * paramTypes);
|
|
||||||
void Set(int func, AMX *amx, int numParams, const ForwardParam * paramTypes);
|
|
||||||
|
|
||||||
cell execute(cell *params, ForwardPreparedArray *preparedArrays);
|
|
||||||
|
|
||||||
int getParamsNum() const
|
|
||||||
{
|
|
||||||
return m_NumParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getFuncsNum() const
|
|
||||||
{
|
|
||||||
return (m_HasFunc) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *getFuncName() const
|
|
||||||
{
|
|
||||||
return m_Name.chars();
|
|
||||||
}
|
|
||||||
|
|
||||||
ForwardParam getParamType(int paramId) const
|
|
||||||
{
|
|
||||||
if (paramId < 0 || paramId >= m_NumParams)
|
|
||||||
return FP_DONE;
|
|
||||||
|
|
||||||
return m_ParamTypes[paramId];
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CForwardMngr
|
class CForwardMngr
|
||||||
{
|
{
|
||||||
typedef ke::Vector<CForward*> ForwardVec;
|
|
||||||
typedef ke::Vector<CSPForward*> SPForwardVec;
|
|
||||||
typedef CStack<int> FreeSPVec; // Free SP Forwards
|
|
||||||
|
|
||||||
ForwardVec m_Forwards;
|
|
||||||
|
|
||||||
SPForwardVec m_SPForwards;
|
|
||||||
FreeSPVec m_FreeSPForwards; // so we don't have to free memory
|
|
||||||
|
|
||||||
ForwardPreparedArray m_TmpArrays[FORWARD_MAX_PARAMS]; // used by prepareArray
|
|
||||||
int m_TmpArraysNum;
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CForwardMngr()
|
class iterator;
|
||||||
{ m_TmpArraysNum = 0; }
|
|
||||||
~CForwardMngr() {}
|
|
||||||
|
|
||||||
// Interface
|
class CForward
|
||||||
// Register normal forward
|
{
|
||||||
int registerForward(const char *funcName, ForwardExecType et, int numParams, const ForwardParam *paramTypes);
|
|
||||||
// Register single plugin forward
|
|
||||||
int registerSPForward(const char *funcName, AMX *amx, int numParams, const ForwardParam * paramTypes);
|
|
||||||
int registerSPForward(int func, AMX *amx, int numParams, const ForwardParam * paramTypes);
|
|
||||||
|
|
||||||
// Unregister single plugin forward
|
friend class iterator;
|
||||||
void unregisterSPForward(int id);
|
friend class CForwardMngr;
|
||||||
int duplicateSPForward(int id);
|
|
||||||
int isSameSPForward(int id1, int id2);
|
CPluginMngr::CPlugin* plugin;
|
||||||
|
int function;
|
||||||
|
CForward* next;
|
||||||
|
CForward( CPluginMngr::CPlugin* p, int func ) : plugin(p) , function(func) {next=0;}
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline CPluginMngr::CPlugin* getPlugin() { return plugin; }
|
||||||
|
inline int getFunction() { return function; }
|
||||||
|
|
||||||
// execute forward
|
|
||||||
cell executeForwards(int id, cell *params);
|
|
||||||
void clear(); // delete all forwards
|
|
||||||
|
|
||||||
bool isIdValid(int id) const; // check whether forward id is valid
|
|
||||||
bool isSPForward(int id) const; // check whether forward is single plugin
|
|
||||||
int getParamsNum(int id) const; // get num of params of a forward
|
|
||||||
int getFuncsNum(int id) const; // get num of found functions of a forward
|
|
||||||
const char *getFuncName(int id) const; // get the function name
|
|
||||||
|
|
||||||
ForwardParam getParamType(int id, int paramId) const;
|
|
||||||
cell prepareArray(void *ptr, unsigned int size, ForwardArrayElemType type, bool copyBack); // prepare array
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// (un)register forward
|
|
||||||
int registerForward(const char *funcName, ForwardExecType et, ...);
|
|
||||||
int registerForwardC(const char *funcName, ForwardExecType et, cell *list, size_t num);
|
|
||||||
int registerSPForwardByName(AMX *amx, const char *funcName, ...);
|
|
||||||
int registerSPForwardByNameC(AMX *amx, const char *funcName, cell *list, size_t num);
|
|
||||||
int registerSPForward(AMX *amx, int func, ...);
|
|
||||||
void unregisterSPForward(int id);
|
|
||||||
|
|
||||||
// execute forwards
|
|
||||||
cell executeForwards(int id, ...);
|
|
||||||
// prepare array
|
|
||||||
cell prepareCellArray(cell *ptr, unsigned int size, bool copyBack = false);
|
|
||||||
cell prepareCharArray(char *ptr, unsigned int size, bool copyBack = false);
|
|
||||||
|
|
||||||
#endif //FORWARD_H
|
private:
|
||||||
|
CForward *head[ FORWARD_NUM ];
|
||||||
|
void clearForwards( CForward** a );
|
||||||
|
|
||||||
|
public:
|
||||||
|
CForwardMngr() {memset( head, 0, sizeof(head));}
|
||||||
|
~CForwardMngr() { clear(); }
|
||||||
|
|
||||||
|
// Interface
|
||||||
|
|
||||||
|
void registerForward( CPluginMngr::CPlugin* p, int func , int type );
|
||||||
|
void executeForwards( int type , int num = 0, int player = 0 );
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
|
||||||
|
class iterator {
|
||||||
|
CForward *a;
|
||||||
|
public:
|
||||||
|
iterator(CForward*aa) : a(aa) {}
|
||||||
|
iterator& operator++() { a = a->next; return *this; }
|
||||||
|
bool operator==(const iterator& b) const { return a == b.a; }
|
||||||
|
bool operator!=(const iterator& b) const { return !operator==(b); }
|
||||||
|
operator bool () const { return a ? true : false; }
|
||||||
|
CForward& operator*() { return *a; }
|
||||||
|
};
|
||||||
|
inline iterator begin( int type ) const { return iterator(head[(int)type]); }
|
||||||
|
inline iterator end() const { return iterator(0); }
|
||||||
|
inline bool forwardsExist( int type ) {return head[(int)type]?true:false;}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
#ifndef FRAMEACTION_H
|
|
||||||
#define FRAMEACTION_H
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include <amtl/am-deque.h>
|
|
||||||
#include <amtl/am-autoptr.h>
|
|
||||||
|
|
||||||
class CFrameActionMngr
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
class CFrameAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CFrameAction(int callbackForward, cell callbackData) :
|
|
||||||
m_callbackForward(callbackForward),
|
|
||||||
m_callbackData(callbackData)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
~CFrameAction()
|
|
||||||
{
|
|
||||||
unregisterSPForward(m_callbackForward);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Execute()
|
|
||||||
{
|
|
||||||
executeForwards(m_callbackForward, m_callbackData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
int m_callbackForward;
|
|
||||||
cell m_callbackData;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void AddFrameAction(int callbackForward, cell callbackData)
|
|
||||||
{
|
|
||||||
m_requestedFrames.append(new CFrameAction(callbackForward, callbackData));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecuteFrameCallbacks()
|
|
||||||
{
|
|
||||||
// In case a frame callback requests another frame, newly added frames won't be executed this way
|
|
||||||
int callbacksToRun = m_requestedFrames.length();
|
|
||||||
while (callbacksToRun--)
|
|
||||||
{
|
|
||||||
ke::AutoPtr<CFrameAction> action = ke::Move(m_requestedFrames.front());
|
|
||||||
m_requestedFrames.popFront();
|
|
||||||
action->Execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ke::Deque<ke::AutoPtr<CFrameAction>> m_requestedFrames;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // FRAMEACTION_H
|
|
File diff suppressed because it is too large
Load Diff
@ -1,186 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_GAMECONFIG_H_
|
|
||||||
#define _INCLUDE_GAMECONFIG_H_
|
|
||||||
|
|
||||||
#include <IGameConfigs.h>
|
|
||||||
#include "CLibrarySys.h"
|
|
||||||
#include <amtl/am-autoptr.h>
|
|
||||||
#include <amtl/am-vector.h>
|
|
||||||
#include <amtl/am-string.h>
|
|
||||||
#include <amtl/am-refcounting.h>
|
|
||||||
#include <sm_stringhashmap.h>
|
|
||||||
#include <sm_namehashset.h>
|
|
||||||
|
|
||||||
class CGameConfig
|
|
||||||
:
|
|
||||||
public ITextListener_SMC,
|
|
||||||
public IGameConfig,
|
|
||||||
public ke::Refcounted <CGameConfig>
|
|
||||||
{
|
|
||||||
friend class CGameConfigManager;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
CGameConfig(const char *file);
|
|
||||||
~CGameConfig();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool Reparse(char *error, size_t maxlength);
|
|
||||||
bool EnterFile(const char *file, char *error, size_t maxlength);
|
|
||||||
|
|
||||||
public: // ITextListener_SMC
|
|
||||||
|
|
||||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
|
||||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
|
||||||
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
|
||||||
|
|
||||||
public: // IGameConfig
|
|
||||||
|
|
||||||
const char* GetKeyValue(const char *key);
|
|
||||||
bool GetOffset(const char *key, TypeDescription *value);
|
|
||||||
bool GetOffsetByClass(const char *classname, const char *key, TypeDescription *value);
|
|
||||||
bool GetMemSig(const char *key, void **addr);
|
|
||||||
bool GetAddress(const char *key, void **addr);
|
|
||||||
|
|
||||||
public: // NameHashSet
|
|
||||||
|
|
||||||
static inline bool matches(const char *key, const CGameConfig *value)
|
|
||||||
{
|
|
||||||
return strcmp(key, value->m_File) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
struct OffsetClass
|
|
||||||
{
|
|
||||||
StringHashMap<TypeDescription> list;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef StringHashMap<ke::AutoPtr<OffsetClass>> OffsetClassMap;
|
|
||||||
typedef StringHashMap<TypeDescription> OffsetMap;
|
|
||||||
|
|
||||||
char m_File[PLATFORM_MAX_PATH];
|
|
||||||
char m_CurrentPath[PLATFORM_MAX_PATH];
|
|
||||||
|
|
||||||
OffsetMap m_Offsets;
|
|
||||||
OffsetClassMap m_OffsetsByClass;
|
|
||||||
StringHashMap<ke::AString> m_Keys;
|
|
||||||
StringHashMap<void*> m_Sigs;
|
|
||||||
|
|
||||||
int m_ParseState;
|
|
||||||
unsigned int m_IgnoreLevel;
|
|
||||||
|
|
||||||
char m_Class[64];
|
|
||||||
char m_Offset[64];
|
|
||||||
char m_Game[256];
|
|
||||||
|
|
||||||
bool m_FoundOffset;
|
|
||||||
bool m_MatchedClasses;
|
|
||||||
bool m_ShouldBeReadingDefault;
|
|
||||||
bool m_HadGame;
|
|
||||||
bool m_MatchedGame;
|
|
||||||
bool m_HadEngine;
|
|
||||||
bool m_MatchedEngine;
|
|
||||||
bool m_MatchedPlatform;
|
|
||||||
|
|
||||||
unsigned int m_CustomLevel;
|
|
||||||
ITextListener_SMC* m_CustomHandler;
|
|
||||||
|
|
||||||
struct AddressConf
|
|
||||||
{
|
|
||||||
char m_SignatureName[64];
|
|
||||||
size_t m_ReadCount;
|
|
||||||
int m_ReadBytes[8];
|
|
||||||
|
|
||||||
AddressConf(const char *sigName, size_t sigLength, size_t readCount, int *read);
|
|
||||||
AddressConf() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
char m_Address[64];
|
|
||||||
char m_AddressSignature[64];
|
|
||||||
int m_AddressReadCount;
|
|
||||||
int m_AddressRead[8];
|
|
||||||
StringHashMap<AddressConf> m_Addresses;
|
|
||||||
|
|
||||||
char m_pEngine[64];
|
|
||||||
};
|
|
||||||
|
|
||||||
class CGameMasterReader : public ITextListener_SMC
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
void ReadSMC_ParseStart();
|
|
||||||
|
|
||||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
|
||||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
|
||||||
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ke::Vector<ke::AString>* m_FileList;
|
|
||||||
|
|
||||||
unsigned int m_State;
|
|
||||||
unsigned int m_IgnoreLevel;
|
|
||||||
|
|
||||||
char m_CurrentPath[PLATFORM_MAX_PATH];
|
|
||||||
|
|
||||||
bool m_HadEngine;
|
|
||||||
bool m_MatchedEngine;
|
|
||||||
bool m_HadGame;
|
|
||||||
bool m_MatchedGame;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CGameConfigManager : public IGameConfigManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
CGameConfigManager();
|
|
||||||
~CGameConfigManager();
|
|
||||||
|
|
||||||
public: // IGameConfigManager
|
|
||||||
|
|
||||||
bool LoadGameConfigFile(const char *file, IGameConfig **pConfig, char *error, size_t maxlength);
|
|
||||||
void CloseGameConfigFile(IGameConfig *cfg);
|
|
||||||
void AddUserConfigHook(const char *sectionname, ITextListener_SMC *listener);
|
|
||||||
void RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void OnAmxxStartup();
|
|
||||||
void RemoveCachedConfig(CGameConfig *config);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
NameHashSet<CGameConfig*> m_Lookup;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
StringHashMap<ITextListener_SMC*> m_customHandlers;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define GET_OFFSET(classname, member) \
|
|
||||||
static int member = -1; \
|
|
||||||
if (member == -1) \
|
|
||||||
{ \
|
|
||||||
TypeDescription type; \
|
|
||||||
if (!CommonConfig->GetOffsetByClass(classname, #member, &type) || type.fieldOffset < 0)\
|
|
||||||
{ \
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid %s offset. Native %s is disabled", #member, __FUNCTION__);\
|
|
||||||
return 0; \
|
|
||||||
} \
|
|
||||||
member = type.fieldOffset; \
|
|
||||||
}
|
|
||||||
|
|
||||||
extern CGameConfigManager ConfigManager;
|
|
||||||
extern IGameConfig *CommonConfig;
|
|
||||||
|
|
||||||
#endif // _INCLUDE_GAMECONFIG_H_
|
|
@ -1,628 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "CLang.h"
|
|
||||||
#include "format.h"
|
|
||||||
#include "ITextParsers.h"
|
|
||||||
|
|
||||||
#define LITIDX_NONE 0
|
|
||||||
#define LITIDX_BRACKET 1
|
|
||||||
#define LITIDX_DEFINITION 2
|
|
||||||
|
|
||||||
#define INSERT_NUMBER 1
|
|
||||||
#define INSERT_FLOAT 2
|
|
||||||
#define INSERT_STRING 3
|
|
||||||
#define INSERT_NEWLINE 4
|
|
||||||
|
|
||||||
template<>
|
|
||||||
int Compare<ke::AString>(const ke::AString &k1, const ke::AString &k2)
|
|
||||||
{
|
|
||||||
return k1.compare(k2);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
int CompareAlt<char const *, ke::AString>(char const * const &k1, ke::AString const &k2)
|
|
||||||
{
|
|
||||||
return k2.compare(k1);
|
|
||||||
}
|
|
||||||
template<>
|
|
||||||
int CompareAlt<ke::AString, ke::AString>(ke::AString const &k1, ke::AString const &k2)
|
|
||||||
{
|
|
||||||
return k1.compare(k2);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
int HashFunction<ke::AString>(const ke::AString &k)
|
|
||||||
{
|
|
||||||
unsigned long hash = 5381;
|
|
||||||
register const char *str = k.chars();
|
|
||||||
register char c;
|
|
||||||
while ((c = *str++))
|
|
||||||
{
|
|
||||||
hash = ((hash << 5) + hash) + c; // hash*33 + c
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
int HashAlt<const char *>(char const * const &k)
|
|
||||||
{
|
|
||||||
unsigned long hash = 5381;
|
|
||||||
register const char *str = k;
|
|
||||||
register char c;
|
|
||||||
while ((c = *str++))
|
|
||||||
{
|
|
||||||
hash = ((hash << 5) + hash) + c; // hash*33 + c
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
int HashAlt<ke::AString>(ke::AString const &k)
|
|
||||||
{
|
|
||||||
unsigned long hash = 5381;
|
|
||||||
register const char *str = k.chars();
|
|
||||||
register char c;
|
|
||||||
while ((c = *str++))
|
|
||||||
{
|
|
||||||
hash = ((hash << 5) + hash) + c; // hash*33 + c
|
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<>
|
|
||||||
int HashFunction<int>(const int &k)
|
|
||||||
{
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
int Compare<int>(const int &k1, const int &k2)
|
|
||||||
{
|
|
||||||
return (k1 - k2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// strip the whitespaces at the beginning and the end of a string
|
|
||||||
// also convert to lowercase if needed
|
|
||||||
// return the number of written characters (including the terimating zero char)
|
|
||||||
size_t CLangMngr::strip(char *str, char *newstr, bool makelower)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
size_t pos = 0;
|
|
||||||
int flag = 0;
|
|
||||||
size_t strln = strlen(str);
|
|
||||||
|
|
||||||
for (i = strln - 1; i < strln; i--)
|
|
||||||
{
|
|
||||||
if (str[i] == '\n' || str[i] == ' ' || str[i] == '\t')
|
|
||||||
{
|
|
||||||
str[i] = 0;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ptr = str;
|
|
||||||
while (*ptr)
|
|
||||||
{
|
|
||||||
if (!flag)
|
|
||||||
{
|
|
||||||
if (*ptr != '\n' && *ptr != ' ' && *ptr != '\t')
|
|
||||||
{
|
|
||||||
flag = 1;
|
|
||||||
newstr[pos++] = makelower ? tolower(*ptr) : *ptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newstr[pos++] = makelower ? tolower(*ptr) : *ptr;
|
|
||||||
}
|
|
||||||
++ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
newstr[pos] = 0;
|
|
||||||
|
|
||||||
return ptr - str + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/******** CLangMngr::CLang *********/
|
|
||||||
|
|
||||||
CLangMngr::CLang::CLang()
|
|
||||||
{
|
|
||||||
m_LookUpTable.clear();
|
|
||||||
m_entries = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CLangMngr::CLang::CLang(const char *lang)
|
|
||||||
{
|
|
||||||
m_LookUpTable.clear();
|
|
||||||
m_entries = 0;
|
|
||||||
strncpy(m_LanguageName, lang, 2);
|
|
||||||
m_LanguageName[2] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::CLang::AddEntry(int key, const char *definition)
|
|
||||||
{
|
|
||||||
defentry &d = m_LookUpTable[key];
|
|
||||||
|
|
||||||
if (d.definition)
|
|
||||||
{
|
|
||||||
delete d.definition;
|
|
||||||
} else {
|
|
||||||
m_entries++;
|
|
||||||
}
|
|
||||||
|
|
||||||
d.definition = new ke::AString(definition);
|
|
||||||
}
|
|
||||||
|
|
||||||
CLangMngr::CLang::~CLang()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::CLang::Clear()
|
|
||||||
{
|
|
||||||
THash<int, defentry>::iterator iter;
|
|
||||||
for (iter=m_LookUpTable.begin(); iter!=m_LookUpTable.end(); iter++)
|
|
||||||
{
|
|
||||||
if (iter->val.definition)
|
|
||||||
{
|
|
||||||
delete iter->val.definition;
|
|
||||||
iter->val.definition = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_LookUpTable.clear();
|
|
||||||
m_entries = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::CLang::MergeDefinitions(ke::Vector<sKeyDef> &vec)
|
|
||||||
{
|
|
||||||
ke::AutoString *pDef;
|
|
||||||
int key = -1;
|
|
||||||
|
|
||||||
while (!vec.empty())
|
|
||||||
{
|
|
||||||
auto keydef = vec.popCopy();
|
|
||||||
|
|
||||||
key = keydef.key;
|
|
||||||
pDef = keydef.definition;
|
|
||||||
|
|
||||||
AddEntry(key, pDef->ptr());
|
|
||||||
|
|
||||||
delete pDef;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * CLangMngr::CLang::GetDef(int key, int &status)
|
|
||||||
{
|
|
||||||
defentry &def = m_LookUpTable[key];
|
|
||||||
|
|
||||||
if (!def.definition)
|
|
||||||
{
|
|
||||||
status = ERR_BADKEY;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = 0;
|
|
||||||
return def.definition->chars();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::CLang::Entries()
|
|
||||||
{
|
|
||||||
return m_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******** CLangMngr *********/
|
|
||||||
|
|
||||||
CLangMngr::CLangMngr()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * CLangMngr::GetKey(int key)
|
|
||||||
{
|
|
||||||
if (key < 0 || key >= (int)KeyList.length())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return KeyList[key]->chars();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::GetKeyEntry(const char *key)
|
|
||||||
{
|
|
||||||
keytbl_val &val = KeyTable[ke::AString(key)];
|
|
||||||
|
|
||||||
return val.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::AddKeyEntry(const char *key)
|
|
||||||
{
|
|
||||||
keytbl_val val;
|
|
||||||
val.index = static_cast<int>(KeyList.length());
|
|
||||||
|
|
||||||
KeyList.append(new ke::AString(key));
|
|
||||||
|
|
||||||
KeyTable[ke::AString(key)] = val;
|
|
||||||
|
|
||||||
return val.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::AddKeyEntry(ke::AString &key)
|
|
||||||
{
|
|
||||||
return AddKeyEntry(key.chars());
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::GetKeyEntry(ke::AString &key)
|
|
||||||
{
|
|
||||||
keytbl_val &val = KeyTable[key];
|
|
||||||
|
|
||||||
return val.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * CLangMngr::FormatAmxString(AMX *amx, cell *params, int parm, int &len)
|
|
||||||
{
|
|
||||||
//do an initial run through all this
|
|
||||||
static char outbuf[4096];
|
|
||||||
cell *addr = get_amxaddr(amx, params[parm++]);
|
|
||||||
|
|
||||||
len = atcprintf(outbuf, sizeof(outbuf)-1, addr, amx, params, &parm);
|
|
||||||
|
|
||||||
return outbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::MergeDefinitions(const char *lang, ke::Vector<sKeyDef> &tmpVec)
|
|
||||||
{
|
|
||||||
CLang * language = GetLang(lang);
|
|
||||||
if (language)
|
|
||||||
language->MergeDefinitions(tmpVec);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reparse_newlines_and_color(char* def)
|
|
||||||
{
|
|
||||||
size_t len = strlen(def);
|
|
||||||
int offs = 0;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
if (!len)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
c = def[i];
|
|
||||||
|
|
||||||
if (c == '^' && (i != len - 1))
|
|
||||||
{
|
|
||||||
c = def[++i];
|
|
||||||
|
|
||||||
if (c == 'n' || c == 't' || (c >= '1' && c <= '4'))
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case '1': c = '\x01'; break;
|
|
||||||
case '2': c = '\x02'; break;
|
|
||||||
case '3': c = '\x03'; break;
|
|
||||||
case '4': c = '\x04'; break;
|
|
||||||
case 'n': c = '\n'; break;
|
|
||||||
case 't': c = '\t'; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_bmod_cstrike && (c >= '1' && c <= '4')) // remove completely these two characters if not under CS
|
|
||||||
{
|
|
||||||
offs += 2;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
offs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def[i - offs] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
def[len-offs] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LangFileData
|
|
||||||
{
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
multiLine = false;
|
|
||||||
|
|
||||||
*language = '\0';
|
|
||||||
*valueBuffer = '\0';
|
|
||||||
|
|
||||||
clearEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearEntry()
|
|
||||||
{
|
|
||||||
entry.key = -1;
|
|
||||||
entry.definition = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool multiLine;
|
|
||||||
char language[3];
|
|
||||||
char valueBuffer[512];
|
|
||||||
ke::AString currentFile;
|
|
||||||
ke::AString lastKey;
|
|
||||||
ke::Vector<sKeyDef> defsQueue;
|
|
||||||
sKeyDef entry;
|
|
||||||
|
|
||||||
} Data;
|
|
||||||
|
|
||||||
void CLangMngr::ReadINI_ParseStart()
|
|
||||||
{
|
|
||||||
Data.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CLangMngr::ReadINI_NewSection(const char *section, bool invalid_tokens, bool close_bracket, bool extra_tokens, unsigned int *curtok)
|
|
||||||
{
|
|
||||||
if (Data.multiLine)
|
|
||||||
{
|
|
||||||
AMXXLOG_Log("New section, unterminated block (file \"%s\" key \"%s\" lang \"%s\")", Data.currentFile.chars(), Data.lastKey.chars(), Data.language);
|
|
||||||
|
|
||||||
Data.clearEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Data.defsQueue.empty())
|
|
||||||
{
|
|
||||||
MergeDefinitions(Data.language, Data.defsQueue);
|
|
||||||
}
|
|
||||||
|
|
||||||
Data.reset();
|
|
||||||
|
|
||||||
Data.language[0] = section[0];
|
|
||||||
Data.language[1] = section[1];
|
|
||||||
Data.language[2] = '\0';
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CLangMngr::ReadINI_KeyValue(const char *key, const char *value, bool invalid_tokens, bool equal_token, bool quotes, unsigned int *curtok)
|
|
||||||
{
|
|
||||||
bool colons_token = (key[strlen(key) - 1] == ':');
|
|
||||||
|
|
||||||
if (!Data.multiLine)
|
|
||||||
{
|
|
||||||
Data.lastKey = key;
|
|
||||||
|
|
||||||
if (colons_token || equal_token)
|
|
||||||
{
|
|
||||||
int iKey = GetKeyEntry(key);
|
|
||||||
|
|
||||||
if (iKey == -1)
|
|
||||||
{
|
|
||||||
iKey = AddKeyEntry(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (equal_token)
|
|
||||||
{
|
|
||||||
if(value == nullptr) // Support empty value
|
|
||||||
Data.valueBuffer[0] = '\0';
|
|
||||||
else
|
|
||||||
strncopy(Data.valueBuffer, value, sizeof(Data.valueBuffer));
|
|
||||||
|
|
||||||
reparse_newlines_and_color(Data.valueBuffer);
|
|
||||||
|
|
||||||
Data.entry.key = iKey;
|
|
||||||
Data.entry.definition = new ke::AutoString;
|
|
||||||
*Data.entry.definition = Data.valueBuffer;
|
|
||||||
|
|
||||||
Data.defsQueue.append(Data.entry);
|
|
||||||
Data.clearEntry();
|
|
||||||
}
|
|
||||||
else if (!value && colons_token)
|
|
||||||
{
|
|
||||||
Data.entry.key = iKey;
|
|
||||||
Data.entry.definition = new ke::AutoString;
|
|
||||||
|
|
||||||
Data.multiLine = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AMXXLOG_Log("Invalid multi-lingual line (file \"%s\" key \"%s\" lang \"%s\")", Data.currentFile.chars(), Data.lastKey.chars(), Data.language);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!value && colons_token)
|
|
||||||
{
|
|
||||||
strncopy(Data.valueBuffer, Data.entry.definition->ptr(), sizeof(Data.valueBuffer));
|
|
||||||
reparse_newlines_and_color(Data.valueBuffer);
|
|
||||||
|
|
||||||
*Data.entry.definition = Data.valueBuffer;
|
|
||||||
|
|
||||||
Data.defsQueue.append(Data.entry);
|
|
||||||
Data.clearEntry();
|
|
||||||
|
|
||||||
Data.multiLine = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!Data.entry.definition)
|
|
||||||
{
|
|
||||||
Data.entry.definition = new ke::AutoString();
|
|
||||||
}
|
|
||||||
|
|
||||||
*Data.entry.definition = *Data.entry.definition + key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::ReadINI_ParseEnd(bool halted)
|
|
||||||
{
|
|
||||||
if (!Data.defsQueue.empty())
|
|
||||||
{
|
|
||||||
MergeDefinitions(Data.language, Data.defsQueue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//this is the file parser for dictionary text files
|
|
||||||
// -- BAILOPAN
|
|
||||||
int CLangMngr::MergeDefinitionFile(const char *file)
|
|
||||||
{
|
|
||||||
/** Tries to open the file. */
|
|
||||||
struct stat fileStat;
|
|
||||||
if (stat(file, &fileStat))
|
|
||||||
{
|
|
||||||
FileList.remove(file);
|
|
||||||
AMXXLOG_Log("[AMXX] Failed to open dictionary file: %s", file);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks if there is an existing entry with same time stamp. */
|
|
||||||
time_t timeStamp;
|
|
||||||
if (FileList.retrieve(file, &timeStamp) && fileStat.st_mtime == timeStamp)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** If yes, it either means that the entry doesn't exist or the existing entry needs to be updated. */
|
|
||||||
FileList.replace(file, fileStat.st_mtime);
|
|
||||||
|
|
||||||
Data.currentFile = file;
|
|
||||||
|
|
||||||
unsigned int line, col;
|
|
||||||
bool result = textparsers->ParseFile_INI(file, static_cast<ITextListener_INI*>(this), &line, &col, false);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
AMXXLOG_Log("[AMXX] Failed to re-open dictionary file: %s", file);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find a CLang by name, if not found, add it
|
|
||||||
CLangMngr::CLang * CLangMngr::GetLang(const char *name)
|
|
||||||
{
|
|
||||||
for (size_t iter = 0; iter < m_Languages.length(); ++iter)
|
|
||||||
{
|
|
||||||
if (strcmp(m_Languages[iter]->GetName(), name) == 0)
|
|
||||||
return m_Languages[iter];
|
|
||||||
}
|
|
||||||
|
|
||||||
CLang *p = new CLang(name);
|
|
||||||
p->SetMngr(this);
|
|
||||||
|
|
||||||
m_Languages.append(p);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find a CLang by name, if not found, return NULL
|
|
||||||
CLangMngr::CLang * CLangMngr::GetLangR(const char *name)
|
|
||||||
{
|
|
||||||
for (size_t iter = 0; iter < m_Languages.length(); ++iter)
|
|
||||||
{
|
|
||||||
if (strcmp(m_Languages[iter]->GetName(), name) == 0)
|
|
||||||
return m_Languages[iter];
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *CLangMngr::GetDef(const char *langName, const char *key, int &status)
|
|
||||||
{
|
|
||||||
CLang *lang = GetLangR(langName);
|
|
||||||
|
|
||||||
keytbl_val &val = KeyTable.AltFindOrInsert(ke::AString(key)); //KeyTable[make_string(key)];
|
|
||||||
if (lang == NULL)
|
|
||||||
{
|
|
||||||
status = ERR_BADLANG;
|
|
||||||
return NULL;
|
|
||||||
} else if (val.index == -1) {
|
|
||||||
status = ERR_BADKEY;
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
status = 0;
|
|
||||||
return lang->GetDef(val.index, status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::InvalidateCache()
|
|
||||||
{
|
|
||||||
FileList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
CLangMngr::~CLangMngr()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::Clear()
|
|
||||||
{
|
|
||||||
unsigned int i = 0;
|
|
||||||
|
|
||||||
KeyTable.clear();
|
|
||||||
|
|
||||||
for (i = 0; i < m_Languages.length(); i++)
|
|
||||||
{
|
|
||||||
if (m_Languages[i])
|
|
||||||
delete m_Languages[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < KeyList.length(); i++)
|
|
||||||
{
|
|
||||||
if (KeyList[i])
|
|
||||||
delete KeyList[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Languages.clear();
|
|
||||||
KeyList.clear();
|
|
||||||
FileList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
int CLangMngr::GetLangsNum()
|
|
||||||
{
|
|
||||||
return m_Languages.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *CLangMngr::GetLangName(int langId)
|
|
||||||
{
|
|
||||||
for (size_t iter = 0; iter < m_Languages.length(); ++iter)
|
|
||||||
{
|
|
||||||
if ((int)iter == langId)
|
|
||||||
{
|
|
||||||
return m_Languages[iter]->GetName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CLangMngr::LangExists(const char *langName)
|
|
||||||
{
|
|
||||||
char buf[3] = {0};
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while ((buf[i] = tolower(*langName++)))
|
|
||||||
{
|
|
||||||
if (++i == 2)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t iter = 0; iter < m_Languages.length(); ++iter)
|
|
||||||
{
|
|
||||||
if (strcmp(m_Languages[iter]->GetName(), buf) == 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLangMngr::SetDefLang(int id)
|
|
||||||
{
|
|
||||||
m_CurGlobId = id;
|
|
||||||
}
|
|
169
amxmodx/CLang.h
169
amxmodx/CLang.h
@ -1,169 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_CLANG_H
|
|
||||||
#define _INCLUDE_CLANG_H
|
|
||||||
|
|
||||||
#include "sh_tinyhash.h"
|
|
||||||
#include "sm_stringhashmap.h"
|
|
||||||
#include <ITextParsers.h>
|
|
||||||
|
|
||||||
#define LANG_SERVER 0
|
|
||||||
#define LANG_PLAYER -1
|
|
||||||
|
|
||||||
#define ERR_BADKEY 1 // Lang key not found
|
|
||||||
#define ERR_BADLANG 2 // Invalid lang
|
|
||||||
|
|
||||||
struct sKeyDef
|
|
||||||
{
|
|
||||||
ke::AutoString* definition;
|
|
||||||
int key;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lang_err
|
|
||||||
{
|
|
||||||
lang_err() : last(0.0f)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
float last;
|
|
||||||
};
|
|
||||||
|
|
||||||
class defentry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
defentry() : definition(NULL)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
defentry(const defentry &src)
|
|
||||||
{
|
|
||||||
definition = src.definition;
|
|
||||||
}
|
|
||||||
~defentry()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
ke::AString *definition;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct keytbl_val
|
|
||||||
{
|
|
||||||
keytbl_val() : index(-1)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
int index;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CLangMngr : public ITextListener_INI
|
|
||||||
{
|
|
||||||
class CLang
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Construct an empty CLang object
|
|
||||||
CLang();
|
|
||||||
// Construct a CLang object initialized with a language name
|
|
||||||
CLang(const char *lang);
|
|
||||||
// Destructor
|
|
||||||
~CLang();
|
|
||||||
|
|
||||||
// Get the definition
|
|
||||||
const char *GetDef(int key, int &status);
|
|
||||||
// Add definitions to this language
|
|
||||||
void MergeDefinitions(ke::Vector <sKeyDef> & vec);
|
|
||||||
// Reset this language
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
// compare this language to a language name
|
|
||||||
friend bool operator == (const CLang &left, const char *right)
|
|
||||||
{
|
|
||||||
return strcmp(left.m_LanguageName, right) == 0 ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get language name
|
|
||||||
const char *GetName() { return m_LanguageName; }
|
|
||||||
void SetMngr(CLangMngr *l) { m_LMan = l; }
|
|
||||||
// Get number of entries
|
|
||||||
int Entries();
|
|
||||||
protected:
|
|
||||||
typedef THash<int, defentry> LookUpVec;
|
|
||||||
typedef LookUpVec::iterator LookUpVecIter;
|
|
||||||
|
|
||||||
char m_LanguageName[3];
|
|
||||||
|
|
||||||
// our lookup table
|
|
||||||
LookUpVec m_LookUpTable;
|
|
||||||
int m_entries;
|
|
||||||
CLangMngr *m_LMan;
|
|
||||||
public:
|
|
||||||
void AddEntry(int key, const char *definition);
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
// Merge definitions into a language
|
|
||||||
void MergeDefinitions(const char *lang, ke::Vector <sKeyDef> &tmpVec);
|
|
||||||
|
|
||||||
public: // ITextListener_INI
|
|
||||||
void ReadINI_ParseStart();
|
|
||||||
void ReadINI_ParseEnd(bool halted);
|
|
||||||
bool ReadINI_NewSection(const char *section, bool invalid_tokens, bool close_bracket, bool extra_tokens, unsigned int *curtok);
|
|
||||||
bool ReadINI_KeyValue(const char *key, const char *value, bool invalid_tokens, bool equal_token, bool quotes, unsigned int *curtok);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// strip lowercase; make lower if needed
|
|
||||||
static size_t strip(char *str, char *newstr, bool makelower = false);
|
|
||||||
|
|
||||||
typedef ke::Vector<CLang*> LangVec;
|
|
||||||
|
|
||||||
LangVec m_Languages;
|
|
||||||
|
|
||||||
StringHashMap<time_t> FileList;
|
|
||||||
ke::Vector<ke::AString *> KeyList;
|
|
||||||
THash<ke::AString, keytbl_val> KeyTable;
|
|
||||||
|
|
||||||
// Get a lang object (construct if needed)
|
|
||||||
CLang * GetLang(const char *name);
|
|
||||||
|
|
||||||
CLang * GetLangR(const char *name);
|
|
||||||
|
|
||||||
// Current global client-id for functions like client_print with first parameter 0
|
|
||||||
int m_CurGlobId;
|
|
||||||
public:
|
|
||||||
// Merge a definitions file
|
|
||||||
int MergeDefinitionFile(const char *file);
|
|
||||||
// Get a definition from a lang name and a key
|
|
||||||
const char *GetDef(const char *langName, const char *key, int &status);
|
|
||||||
// Format a string for an AMX plugin
|
|
||||||
char *FormatAmxString(AMX *amx, cell *params, int parm, int &len);
|
|
||||||
void InvalidateCache();
|
|
||||||
// Get index
|
|
||||||
int GetKeyEntry(ke::AString &key);
|
|
||||||
int GetKeyEntry(const char *key);
|
|
||||||
// Get key from index
|
|
||||||
const char *GetKey(int key);
|
|
||||||
// Add key
|
|
||||||
int AddKeyEntry(ke::AString &key);
|
|
||||||
int AddKeyEntry(const char *key);
|
|
||||||
|
|
||||||
// Get the number of languages
|
|
||||||
int GetLangsNum();
|
|
||||||
// Get the name of a language
|
|
||||||
const char *GetLangName(int langId);
|
|
||||||
// Check if a language exists
|
|
||||||
bool LangExists(const char *langName);
|
|
||||||
|
|
||||||
// When a language id in a format string in FormatAmxString is LANG_PLAYER, the glob id decides which language to take.
|
|
||||||
void SetDefLang(int id);
|
|
||||||
|
|
||||||
inline int GetDefLang() const { return m_CurGlobId; }
|
|
||||||
|
|
||||||
// Reset
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
CLangMngr();
|
|
||||||
~CLangMngr();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //_INCLUDE_CLANG_H
|
|
@ -1,388 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "CLibrarySys.h"
|
|
||||||
#include <amxmodx.h>
|
|
||||||
#include <amtl/os/am-fsutil.h>
|
|
||||||
#include <amtl/os/am-path.h>
|
|
||||||
#include <amtl/os/am-system-errors.h>
|
|
||||||
|
|
||||||
LibrarySystem g_LibSys;
|
|
||||||
|
|
||||||
/******************/
|
|
||||||
/* Directory Code */
|
|
||||||
/******************/
|
|
||||||
|
|
||||||
CDirectory::CDirectory(const char *path)
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
char newpath[PLATFORM_MAX_PATH];
|
|
||||||
ke::SafeSprintf(newpath, sizeof(newpath), "%s\\*.*", path);
|
|
||||||
|
|
||||||
m_dir = FindFirstFile(newpath, &m_fd);
|
|
||||||
|
|
||||||
if (!IsValid())
|
|
||||||
{
|
|
||||||
m_fd.cFileName[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
m_dir = opendir(path);
|
|
||||||
|
|
||||||
if (IsValid())
|
|
||||||
{
|
|
||||||
m_ep = readdir(m_dir); // TODO: we need to read past "." and ".."!
|
|
||||||
ke::SafeSprintf(m_origpath, sizeof(m_origpath), "%s", path);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_ep = nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
CDirectory::~CDirectory()
|
|
||||||
{
|
|
||||||
if (IsValid())
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
FindClose(m_dir);
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
closedir(m_dir);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DirHandle CDirectory::GetHandle()
|
|
||||||
{
|
|
||||||
return m_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDirectory::NextEntry()
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
if (FindNextFile(m_dir, &m_fd) == 0)
|
|
||||||
{
|
|
||||||
FindClose(m_dir);
|
|
||||||
m_dir = INVALID_HANDLE_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
if (!(m_ep = readdir(m_dir)))
|
|
||||||
{
|
|
||||||
closedir(m_dir);
|
|
||||||
m_dir = nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDirectory::IsEntryValid()
|
|
||||||
{
|
|
||||||
return IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDirectory::IsEntryDirectory()
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
char temppath[PLATFORM_MAX_PATH];
|
|
||||||
ke::SafeSprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
|
||||||
|
|
||||||
return ke::file::IsDirectory(temppath);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDirectory::IsEntryFile()
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE));
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
char temppath[PLATFORM_MAX_PATH];
|
|
||||||
ke::SafeSprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
|
||||||
|
|
||||||
return ke::file::IsFile(temppath);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* CDirectory::GetEntryName()
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
return m_fd.cFileName;
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
return m_ep ? m_ep->d_name : "";
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDirectory::MoreFiles()
|
|
||||||
{
|
|
||||||
return IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDirectory::IsValid()
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
return (m_dir != INVALID_HANDLE_VALUE);
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
return (m_dir != nullptr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/****************/
|
|
||||||
/* Library Code */
|
|
||||||
/****************/
|
|
||||||
|
|
||||||
CLibrary::CLibrary(ke::RefPtr<ke::SharedLib> lib) : lib_(lib)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void CLibrary::CloseLibrary()
|
|
||||||
{
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CLibrary::GetSymbolAddress(const char* symname)
|
|
||||||
{
|
|
||||||
return lib_->lookup(symname);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************/
|
|
||||||
/* Library System Code */
|
|
||||||
/***********************/
|
|
||||||
|
|
||||||
bool LibrarySystem::PathExists(const char *path)
|
|
||||||
{
|
|
||||||
return ke::file::PathExists(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LibrarySystem::IsPathFile(const char* path)
|
|
||||||
{
|
|
||||||
return ke::file::IsFile(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LibrarySystem::IsPathDirectory(const char* path)
|
|
||||||
{
|
|
||||||
return ke::file::IsDirectory(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
CDirectory *LibrarySystem::OpenDirectory(const char* path)
|
|
||||||
{
|
|
||||||
CDirectory* dir = new CDirectory(path);
|
|
||||||
|
|
||||||
if (!dir->IsValid())
|
|
||||||
{
|
|
||||||
delete dir;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
CLibrary* LibrarySystem::OpenLibrary(const char* path, char* error, size_t maxlength)
|
|
||||||
{
|
|
||||||
ke::RefPtr<ke::SharedLib> lib = ke::SharedLib::Open(path, error, maxlength);
|
|
||||||
|
|
||||||
if (!lib)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CLibrary(lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LibrarySystem::GetPlatformError(char* error, size_t maxlength)
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
return GetPlatformErrorEx(GetLastError(), error, maxlength);
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
return GetPlatformErrorEx(errno, error, maxlength);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void LibrarySystem::GetPlatformErrorEx(int code, char* error, size_t maxlength)
|
|
||||||
{
|
|
||||||
if (error && maxlength)
|
|
||||||
{
|
|
||||||
ke::FormatSystemErrorCode(code, error, maxlength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LibrarySystem::GetLoaderError(char* buffer, size_t maxlength)
|
|
||||||
{
|
|
||||||
ke::FormatSystemError(buffer, maxlength);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LibrarySystem::CloseDirectory(CDirectory *dir)
|
|
||||||
{
|
|
||||||
delete dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t LibrarySystem::PathFormat(char* buffer, size_t len, const char* fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
size_t mylen = ke::path::FormatVa(buffer, len, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return mylen;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* LibrarySystem::PathFormat(const char* fmt, ...)
|
|
||||||
{
|
|
||||||
static char buffer[PLATFORM_MAX_PATH];
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
ke::path::FormatVa(buffer, sizeof(buffer), fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* LibrarySystem::GetFileExtension(const char* filename)
|
|
||||||
{
|
|
||||||
size_t len, end;
|
|
||||||
|
|
||||||
len = strlen(filename);
|
|
||||||
|
|
||||||
/* Minimum string length for filename with ext would be 3; example: a.a */
|
|
||||||
if (len < 3)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
end = len - 1;
|
|
||||||
|
|
||||||
for (size_t i = end; i <= end; i--)
|
|
||||||
{
|
|
||||||
if (filename[i] == PLATFORM_SEP_CHAR || filename[i] == PLATFORM_SEP_ALTCHAR)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filename[i] == '.' && i != end && i != 0)
|
|
||||||
{
|
|
||||||
return &filename[++i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LibrarySystem::CreateFolder(const char* path)
|
|
||||||
{
|
|
||||||
return ke::file::CreateDirectory(path, 0775);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t LibrarySystem::GetFileFromPath(char* buffer, size_t maxlength, const char* path)
|
|
||||||
{
|
|
||||||
size_t length = strlen(path);
|
|
||||||
|
|
||||||
for (size_t i = length - 1; i <= length - 1; i--)
|
|
||||||
{
|
|
||||||
if (path[i] == '/'
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|| path[i] == '\\'
|
|
||||||
#endif
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return ke::SafeSprintf(buffer, maxlength, "%s", &path[i + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We scanned and found no path separator */
|
|
||||||
return ke::SafeSprintf(buffer, maxlength, "%s", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LibrarySystem::FileTime(const char* path, FileTimeType type, time_t* pTime)
|
|
||||||
{
|
|
||||||
struct stat s;
|
|
||||||
|
|
||||||
if (stat(path, &s) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case FileTime_LastAccess:
|
|
||||||
{
|
|
||||||
*pTime = s.st_atime;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FileTime_Created:
|
|
||||||
{
|
|
||||||
*pTime = s.st_ctime;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FileTime_LastChange:
|
|
||||||
{
|
|
||||||
*pTime = s.st_mtime;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LibrarySystem::DoesPlatformMatch(const char *platform)
|
|
||||||
{
|
|
||||||
return strcmp(platform, PLATFORM_NAME) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LibrarySystem::IsPlatformCompatible(const char *platform, bool *hadPrimaryMatch)
|
|
||||||
{
|
|
||||||
if (DoesPlatformMatch(platform))
|
|
||||||
{
|
|
||||||
#if defined PLATFORM_COMPAT_ALT
|
|
||||||
*hadPrimaryMatch = true;
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined PLATFORM_COMPAT_ALT
|
|
||||||
/* If entry hasn't been found for the primary platform name, check for compatible alternate */
|
|
||||||
if (!*hadPrimaryMatch)
|
|
||||||
{
|
|
||||||
return strcmp(platform, PLATFORM_COMPAT_ALT) == 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_LIBRARY_SYS_H_
|
|
||||||
#define _INCLUDE_LIBRARY_SYS_H_
|
|
||||||
|
|
||||||
#include "amx.h" // cell
|
|
||||||
#include <platform_helpers.h>
|
|
||||||
#include <amtl/os/am-shared-library.h>
|
|
||||||
|
|
||||||
enum FileTimeType
|
|
||||||
{
|
|
||||||
FileTime_LastAccess = 0, /* Last access (not available on FAT) */
|
|
||||||
FileTime_Created = 1, /* Creation (not available on FAT) */
|
|
||||||
FileTime_LastChange = 2, /* Last modification */
|
|
||||||
};
|
|
||||||
|
|
||||||
class CDirectory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
CDirectory(const char* path);
|
|
||||||
~CDirectory();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool MoreFiles();
|
|
||||||
void NextEntry();
|
|
||||||
const char* GetEntryName();
|
|
||||||
bool IsEntryDirectory();
|
|
||||||
bool IsEntryFile();
|
|
||||||
bool IsEntryValid();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool IsValid();
|
|
||||||
DirHandle GetHandle();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
|
|
||||||
HANDLE m_dir;
|
|
||||||
WIN32_FIND_DATAA m_fd;
|
|
||||||
|
|
||||||
#elif defined PLATFORM_POSIX
|
|
||||||
|
|
||||||
DIR* m_dir;
|
|
||||||
struct dirent* m_ep;
|
|
||||||
char m_origpath[PLATFORM_MAX_PATH];
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class CLibrary
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
CLibrary(ke::RefPtr<ke::SharedLib> lib);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void CloseLibrary();
|
|
||||||
void *GetSymbolAddress(const char* symname);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
ke::RefPtr<ke::SharedLib> lib_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LibrarySystem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
CLibrary* OpenLibrary(const char* path, char* error = nullptr, size_t maxlength = 0);
|
|
||||||
CDirectory* OpenDirectory(const char* path);
|
|
||||||
void CloseDirectory(CDirectory *dir);
|
|
||||||
|
|
||||||
bool PathExists(const char* path);
|
|
||||||
bool IsPathFile(const char* path);
|
|
||||||
bool IsPathDirectory(const char* path);
|
|
||||||
|
|
||||||
void GetPlatformError(char* error, size_t maxlength);
|
|
||||||
void GetPlatformErrorEx(int code, char* error, size_t maxlength);
|
|
||||||
|
|
||||||
size_t PathFormat(char* buffer, size_t len, const char* fmt, ...);
|
|
||||||
char* PathFormat(const char* fmt, ...);
|
|
||||||
|
|
||||||
const char* GetFileExtension(const char* filename);
|
|
||||||
bool CreateFolder(const char* path);
|
|
||||||
size_t GetFileFromPath(char* buffer, size_t maxlength, const char* path);
|
|
||||||
|
|
||||||
bool FileTime(const char* path, FileTimeType type, time_t* pTime);
|
|
||||||
void GetLoaderError(char* buffer, size_t maxlength);
|
|
||||||
|
|
||||||
bool DoesPlatformMatch(const char* platform);
|
|
||||||
bool IsPlatformCompatible(const char *platform, bool *hadPrimaryMatch);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern LibrarySystem g_LibSys;
|
|
||||||
|
|
||||||
#endif // _INCLUDE_LIBRARY_SYS_H_
|
|
110
amxmodx/CList.h
Executable file
110
amxmodx/CList.h
Executable file
@ -0,0 +1,110 @@
|
|||||||
|
/* AMX Mod X
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
* originally developed by OLO
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLIST_H
|
||||||
|
#define CLIST_H
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// class CList
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
template <typename T, typename F = char* >
|
||||||
|
class CList {
|
||||||
|
public:
|
||||||
|
class iterator;
|
||||||
|
class CListEle {
|
||||||
|
friend class CList<T,F>;
|
||||||
|
friend class iterator;
|
||||||
|
T* obj;
|
||||||
|
CListEle* next;
|
||||||
|
CListEle( T* a , CListEle* nn ) : obj(a) , next(nn) {}
|
||||||
|
public:
|
||||||
|
T& operator* () { return *obj; }
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
CListEle *head;
|
||||||
|
int cur_size;
|
||||||
|
public:
|
||||||
|
CList<T,F>() { head = 0; cur_size = 0; }
|
||||||
|
~CList<T,F>() { clear(); }
|
||||||
|
void clear() {
|
||||||
|
iterator a = begin();
|
||||||
|
while( a ) a.remove();
|
||||||
|
cur_size = 0;
|
||||||
|
}
|
||||||
|
void put( T* a ) {
|
||||||
|
head = new CListEle( a , head );
|
||||||
|
++cur_size;
|
||||||
|
}
|
||||||
|
int size() {
|
||||||
|
return cur_size;
|
||||||
|
}
|
||||||
|
class iterator {
|
||||||
|
CListEle** a;
|
||||||
|
public:
|
||||||
|
iterator(CListEle** i=0) : a(i){}
|
||||||
|
T& operator*() const { return *(*a)->obj;}
|
||||||
|
inline operator bool () const { return (a && *a); }
|
||||||
|
inline iterator& operator++() {
|
||||||
|
a = &(*a)->next;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline iterator operator++(int) {
|
||||||
|
iterator tmp(a);
|
||||||
|
a = &(*a)->next;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
iterator& remove(){
|
||||||
|
CListEle* aa = (*a)->next;
|
||||||
|
delete (*a)->obj;
|
||||||
|
delete *a;
|
||||||
|
*a = aa;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
iterator& put( T* aa ){
|
||||||
|
*a = new CListEle( aa , *a );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
inline iterator begin() { return iterator(&head); }
|
||||||
|
iterator find( F a ){
|
||||||
|
iterator cc = begin();
|
||||||
|
while(cc){
|
||||||
|
if ( *cc == a )
|
||||||
|
break;
|
||||||
|
++cc;
|
||||||
|
}
|
||||||
|
return cc;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,163 +1,138 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include <extdll.h>
|
||||||
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
#include "CLogEvent.h"
|
#include "CLogEvent.h"
|
||||||
|
|
||||||
NativeHandle<LogEventHook> LogEventHandles;
|
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class LogEventsMngr
|
// class LogEventsMngr
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
LogEventsMngr::LogEventsMngr() {
|
||||||
LogEventsMngr::LogEventsMngr()
|
|
||||||
{
|
|
||||||
logCurrent = logCounter = 0;
|
logCurrent = logCounter = 0;
|
||||||
logcmplist = 0;
|
logcmplist = 0;
|
||||||
arelogevents = false;
|
arelogevents = false;
|
||||||
memset( logevents, 0, sizeof(logevents) );
|
memset( logevents, 0, sizeof(logevents) );
|
||||||
}
|
}
|
||||||
|
|
||||||
LogEventsMngr::~LogEventsMngr()
|
LogEventsMngr::~LogEventsMngr() {
|
||||||
{
|
|
||||||
clearLogEvents();
|
clearLogEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
int LogEventsMngr::CLogCmp::compareCondition(const char* string)
|
int LogEventsMngr::CLogCmp::compareCondition(const char* string){
|
||||||
{
|
|
||||||
if ( logid == parent->logCounter )
|
if ( logid == parent->logCounter )
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
logid = parent->logCounter;
|
logid = parent->logCounter;
|
||||||
|
if ( in ) return result = strstr( string , text.str() ) ? 0 : 1;
|
||||||
if (in)
|
return result = strcmp(string,text.str());
|
||||||
return result = strstr(string, text.chars()) ? 0 : 1;
|
|
||||||
|
|
||||||
return result = strcmp(string,text.chars());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogEventsMngr::CLogCmp* LogEventsMngr::registerCondition(char* filter)
|
LogEventsMngr::CLogCmp* LogEventsMngr::registerCondition(char* filter){
|
||||||
{
|
|
||||||
char* temp = filter;
|
char* temp = filter;
|
||||||
// expand "1=message"
|
// expand "1=message"
|
||||||
|
|
||||||
while ( isdigit(*filter) )
|
while ( isdigit(*filter) )
|
||||||
++filter;
|
++filter;
|
||||||
|
|
||||||
bool in = (*filter=='&');
|
bool in = (*filter=='&');
|
||||||
*filter++ = 0;
|
*filter++ = 0;
|
||||||
int pos = atoi(temp);
|
int pos = atoi(temp);
|
||||||
|
if ( pos < 0 || pos >= MAX_LOGARGS) pos = 0;
|
||||||
if (pos < 0 || pos >= MAX_LOGARGS)
|
|
||||||
pos = 0;
|
|
||||||
|
|
||||||
CLogCmp* c = logcmplist;
|
CLogCmp* c = logcmplist;
|
||||||
|
while( c ) {
|
||||||
while (c)
|
if ( (c->pos==pos) && (c->in==in) && !strcmp(c->text.str(), filter))
|
||||||
{
|
|
||||||
if ((c->pos == pos) && (c->in == in) && !strcmp(c->text.chars(), filter))
|
|
||||||
return c;
|
return c;
|
||||||
c = c->next;
|
c = c->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return logcmplist = new CLogCmp( filter , in , pos , logcmplist,this );
|
return logcmplist = new CLogCmp( filter , in , pos , logcmplist,this );
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEventsMngr::CLogEvent::registerFilter(char* filter)
|
void LogEventsMngr::CLogEvent::registerFilter( char* filter ){
|
||||||
{
|
|
||||||
CLogCmp *cmp = parent->registerCondition( filter );
|
CLogCmp *cmp = parent->registerCondition( filter );
|
||||||
if ( cmp == 0 ) return;
|
if ( cmp == 0 ) return;
|
||||||
|
for(LogCond* c = filters; c ; c = c->next){
|
||||||
for (LogCond* c = filters; c; c = c->next)
|
if ( c->argnum == cmp->pos ){
|
||||||
{
|
|
||||||
if (c->argnum == cmp->pos)
|
|
||||||
{
|
|
||||||
c->list = new LogCondEle( cmp , c->list );
|
c->list = new LogCondEle( cmp , c->list );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogCondEle* aa = new LogCondEle( cmp , 0 );
|
LogCondEle* aa = new LogCondEle( cmp , 0 );
|
||||||
|
if ( aa == 0 ) return;
|
||||||
if (aa == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
filters = new LogCond( cmp->pos , aa , filters );
|
filters = new LogCond( cmp->pos , aa , filters );
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEventsMngr::setLogString(const char* frmt, va_list& vaptr)
|
void LogEventsMngr::setLogString( char* frmt, va_list& vaptr ) {
|
||||||
{
|
|
||||||
++logCounter;
|
++logCounter;
|
||||||
int len = vsnprintf (logString, 255 , frmt, vaptr );
|
int len = vsnprintf (logString, 255 , frmt, vaptr );
|
||||||
|
if ( len == - 1) {
|
||||||
if (len == - 1)
|
|
||||||
{
|
|
||||||
len = 255;
|
len = 255;
|
||||||
logString[len] = 0;
|
logString[len] = 0;
|
||||||
}
|
}
|
||||||
|
if ( len ) logString[--len] = 0;
|
||||||
if (len)
|
|
||||||
logString[--len] = 0;
|
|
||||||
|
|
||||||
logArgc = 0;
|
logArgc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEventsMngr::setLogString(const char* frmt, ...)
|
void LogEventsMngr::setLogString( char* frmt, ... ) {
|
||||||
{
|
|
||||||
++logCounter;
|
++logCounter;
|
||||||
va_list logArgPtr;
|
va_list logArgPtr;
|
||||||
va_start ( logArgPtr , frmt );
|
va_start ( logArgPtr , frmt );
|
||||||
int len = vsnprintf(logString, 255 , frmt, logArgPtr );
|
int len = vsnprintf(logString, 255 , frmt, logArgPtr );
|
||||||
|
if ( len == - 1) {
|
||||||
if (len == - 1)
|
|
||||||
{
|
|
||||||
len = 255;
|
len = 255;
|
||||||
logString[len] = 0;
|
logString[len] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end ( logArgPtr );
|
va_end ( logArgPtr );
|
||||||
|
if ( len ) logString[--len] = 0;
|
||||||
if (len)
|
|
||||||
logString[--len] = 0;
|
|
||||||
|
|
||||||
logArgc = 0;
|
logArgc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEventsMngr::parseLogString()
|
void LogEventsMngr::parseLogString( ) {
|
||||||
{
|
|
||||||
register const char* b = logString;
|
register const char* b = logString;
|
||||||
register int a;
|
register int a;
|
||||||
|
while( *b && logArgc < MAX_LOGARGS ){
|
||||||
while (*b && logArgc < MAX_LOGARGS)
|
|
||||||
{
|
|
||||||
a = 0;
|
a = 0;
|
||||||
|
if ( *b == '"' ) {
|
||||||
if (*b == '"')
|
|
||||||
{
|
|
||||||
++b;
|
++b;
|
||||||
|
|
||||||
while ( *b && *b != '"' && a < 127 )
|
while ( *b && *b != '"' && a < 127 )
|
||||||
logArgs[logArgc][a++] = *b++;
|
logArgs[logArgc][a++] = *b++;
|
||||||
|
|
||||||
logArgs[logArgc++][a] = 0;
|
logArgs[logArgc++][a] = 0;
|
||||||
if ( *b) b+=2; // thanks to double terminator
|
if ( *b) b+=2; // thanks to double terminator
|
||||||
}
|
}
|
||||||
else if (*b == '(')
|
else if ( *b == '(' ) {
|
||||||
{
|
|
||||||
++b;
|
++b;
|
||||||
|
|
||||||
while ( *b && *b != ')' && a < 127 )
|
while ( *b && *b != ')' && a < 127 )
|
||||||
logArgs[logArgc][a++] = *b++;
|
logArgs[logArgc][a++] = *b++;
|
||||||
|
|
||||||
logArgs[logArgc++][a] = 0;
|
logArgs[logArgc++][a] = 0;
|
||||||
if ( *b) b+=2;
|
if ( *b) b+=2;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
while ( *b && *b != '(' && *b != '"' && a < 127 )
|
while ( *b && *b != '(' && *b != '"' && a < 127 )
|
||||||
logArgs[logArgc][a++] = *b++;
|
logArgs[logArgc][a++] = *b++;
|
||||||
if ( *b ) --a;
|
if ( *b ) --a;
|
||||||
@ -166,121 +141,87 @@ void LogEventsMngr::parseLogString()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEventsMngr::CLogEvent::setForwardState(ForwardState state)
|
LogEventsMngr::CLogEvent* LogEventsMngr::registerLogEvent( CPluginMngr::CPlugin* plugin, int func, int pos )
|
||||||
{
|
|
||||||
m_State = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LogEventsMngr::registerLogEvent(CPluginMngr::CPlugin* plugin, int func, int pos)
|
|
||||||
{
|
{
|
||||||
if ( pos < 1 || pos > MAX_LOGARGS)
|
if ( pos < 1 || pos > MAX_LOGARGS)
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
arelogevents = true;
|
arelogevents = true;
|
||||||
auto d = &logevents[pos];
|
CLogEvent** d = &logevents[pos];
|
||||||
|
while(*d) d = &(*d)->next;
|
||||||
while (*d)
|
return *d = new CLogEvent( plugin , func, this );
|
||||||
{
|
|
||||||
d = &(*d)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto logevent = new CLogEvent(plugin, func, this);
|
|
||||||
auto handle = LogEventHandles.create(logevent);
|
|
||||||
|
|
||||||
if (!handle)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*d = logevent;
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEventsMngr::executeLogEvents()
|
void LogEventsMngr::executeLogEvents()
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
bool valid;
|
bool valid;
|
||||||
|
for(CLogEvent* a = logevents[ logArgc ]; a ; a = a->next){
|
||||||
for (CLogEvent* a = logevents[logArgc]; a; a = a->next)
|
|
||||||
{
|
|
||||||
if (a->m_State != FSTATE_ACTIVE)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
|
for( CLogEvent::LogCond* b = a->filters; b ; b = b->next){
|
||||||
for (CLogEvent::LogCond* b = a->filters; b; b = b->next)
|
|
||||||
{
|
|
||||||
valid = false;
|
valid = false;
|
||||||
|
for( CLogEvent::LogCondEle* c = b->list; c ; c = c->next) {
|
||||||
for (CLogEvent::LogCondEle* c = b->list; c; c = c->next)
|
if ( c->cmp->compareCondition( logArgs[b->argnum] ) == 0 ){
|
||||||
{
|
|
||||||
if (c->cmp->compareCondition(logArgs[b->argnum]) == 0)
|
|
||||||
{
|
|
||||||
valid = true;
|
valid = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!valid) break;
|
||||||
if (!valid)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid)
|
#ifdef ENABLEEXEPTIONS
|
||||||
|
try
|
||||||
{
|
{
|
||||||
executeForwards(a->func);
|
#endif
|
||||||
|
|
||||||
|
if (valid){
|
||||||
|
if ((err = amx_Exec(a->plugin->getAMX(), NULL , a->func , 0)) != AMX_ERR_NONE)
|
||||||
|
UTIL_Log("[AMXX] Run time error %d on line %ld (plugin \"%s\")",
|
||||||
|
err,a->plugin->getAMX()->curline,a->plugin->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLEEXEPTIONS
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
UTIL_Log( "[AMXX] fatal error at log forward function execution");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEventsMngr::clearLogEvents()
|
void LogEventsMngr::clearLogEvents(){
|
||||||
{
|
|
||||||
logCurrent = logCounter = 0;
|
logCurrent = logCounter = 0;
|
||||||
arelogevents = false;
|
arelogevents = false;
|
||||||
|
for(int i = 0; i < MAX_LOGARGS + 1; ++i){
|
||||||
for (int i = 0; i < MAX_LOGARGS + 1; ++i)
|
|
||||||
{
|
|
||||||
CLogEvent **a = &logevents[i];
|
CLogEvent **a = &logevents[i];
|
||||||
while (*a)
|
while(*a){
|
||||||
{
|
|
||||||
CLogEvent* bb = (*a)->next;
|
CLogEvent* bb = (*a)->next;
|
||||||
delete *a;
|
delete *a;
|
||||||
*a = bb;
|
*a = bb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clearConditions();
|
clearConditions();
|
||||||
|
|
||||||
LogEventHandles.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogEventsMngr::clearConditions()
|
void LogEventsMngr::clearConditions() {
|
||||||
{
|
while (logcmplist){
|
||||||
while (logcmplist)
|
|
||||||
{
|
|
||||||
CLogCmp* a = logcmplist->next;
|
CLogCmp* a = logcmplist->next;
|
||||||
delete logcmplist;
|
delete logcmplist;
|
||||||
logcmplist = a;
|
logcmplist = a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogEventsMngr::CLogEvent::LogCond::~LogCond()
|
LogEventsMngr::CLogEvent::LogCond::~LogCond() {
|
||||||
{
|
while( list ) {
|
||||||
while (list)
|
|
||||||
{
|
|
||||||
LogCondEle* cc = list->next;
|
LogCondEle* cc = list->next;
|
||||||
delete list;
|
delete list;
|
||||||
list = cc;
|
list = cc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogEventsMngr::CLogEvent::~CLogEvent()
|
LogEventsMngr::CLogEvent::~CLogEvent() {
|
||||||
{
|
while( filters ) {
|
||||||
while (filters)
|
|
||||||
{
|
|
||||||
LogCond* cc = filters->next;
|
LogCond* cc = filters->next;
|
||||||
delete filters;
|
delete filters;
|
||||||
filters = cc;
|
filters = cc;
|
||||||
@ -290,35 +231,23 @@ LogEventsMngr::CLogEvent::~CLogEvent()
|
|||||||
LogEventsMngr::CLogEvent *LogEventsMngr::getValidLogEvent( CLogEvent * a )
|
LogEventsMngr::CLogEvent *LogEventsMngr::getValidLogEvent( CLogEvent * a )
|
||||||
{
|
{
|
||||||
bool valid;
|
bool valid;
|
||||||
|
while(a){
|
||||||
while (a)
|
|
||||||
{
|
|
||||||
valid = true;
|
valid = true;
|
||||||
|
for( CLogEvent::LogCond* b = a->filters; b ; b = b->next){
|
||||||
for (CLogEvent::LogCond* b = a->filters; b; b = b->next)
|
|
||||||
{
|
|
||||||
valid = false;
|
valid = false;
|
||||||
|
for( CLogEvent::LogCondEle* c = b->list; c ; c = c->next) {
|
||||||
for (CLogEvent::LogCondEle* c = b->list; c; c = c->next)
|
if ( c->cmp->compareCondition( logArgs[b->argnum] ) == 0 ){
|
||||||
{
|
|
||||||
if (c->cmp->compareCondition(logArgs[b->argnum]) == 0)
|
|
||||||
{
|
|
||||||
valid = true;
|
valid = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!valid) break;
|
if (!valid) break;
|
||||||
}
|
}
|
||||||
|
if (!valid){
|
||||||
if (!valid)
|
|
||||||
{
|
|
||||||
a = a->next;
|
a = a->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -1,11 +1,33 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef LOGEVENTS_H
|
#ifndef LOGEVENTS_H
|
||||||
#define LOGEVENTS_H
|
#define LOGEVENTS_H
|
||||||
@ -13,14 +35,13 @@
|
|||||||
#define MAX_LOGARGS 12
|
#define MAX_LOGARGS 12
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "natives_handles.h"
|
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class LogEventsMngr
|
// class LogEventsMngr
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
class LogEventsMngr
|
class LogEventsMngr {
|
||||||
{
|
|
||||||
char logString[256];
|
char logString[256];
|
||||||
char logArgs[MAX_LOGARGS][128];
|
char logArgs[MAX_LOGARGS][128];
|
||||||
int logArgc;
|
int logArgc;
|
||||||
@ -32,6 +53,7 @@ public:
|
|||||||
class CLogCmp;
|
class CLogCmp;
|
||||||
class iterator;
|
class iterator;
|
||||||
class CLogEvent;
|
class CLogEvent;
|
||||||
|
|
||||||
friend class CLogEvent;
|
friend class CLogEvent;
|
||||||
friend class CLogCmp;
|
friend class CLogCmp;
|
||||||
friend class iterator;
|
friend class iterator;
|
||||||
@ -40,129 +62,105 @@ public:
|
|||||||
{
|
{
|
||||||
friend class LogEventsMngr;
|
friend class LogEventsMngr;
|
||||||
friend class CLogEvent;
|
friend class CLogEvent;
|
||||||
|
|
||||||
LogEventsMngr* parent;
|
LogEventsMngr* parent;
|
||||||
ke::AString text;
|
String text;
|
||||||
|
|
||||||
int logid;
|
int logid;
|
||||||
int pos;
|
int pos;
|
||||||
int result;
|
int result;
|
||||||
bool in;
|
bool in;
|
||||||
|
|
||||||
CLogCmp *next;
|
CLogCmp *next;
|
||||||
|
CLogCmp( const char* s, bool r, int p, CLogCmp *n, LogEventsMngr* mg ) : text(s) {
|
||||||
CLogCmp(const char* s, bool r, int p, CLogCmp *n, LogEventsMngr* mg) : text(s)
|
|
||||||
{
|
|
||||||
logid = result = 0;
|
logid = result = 0;
|
||||||
pos = p;
|
pos = p;
|
||||||
parent = mg;
|
parent = mg;
|
||||||
in = r;
|
in = r;
|
||||||
next = n;
|
next = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
int compareCondition(const char* string);
|
int compareCondition(const char* string);
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CLogCmp *logcmplist;
|
CLogCmp *logcmplist;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class CLogEvent
|
class CLogEvent {
|
||||||
{
|
|
||||||
friend class LogEventsMngr;
|
friend class LogEventsMngr;
|
||||||
friend class iterator;
|
friend class iterator;
|
||||||
|
struct LogCondEle {
|
||||||
struct LogCondEle
|
|
||||||
{
|
|
||||||
CLogCmp *cmp;
|
CLogCmp *cmp;
|
||||||
LogCondEle *next;
|
LogCondEle *next;
|
||||||
LogCondEle(CLogCmp *c, LogCondEle *n): cmp(c) , next(n) { }
|
LogCondEle(CLogCmp *c, LogCondEle *n): cmp(c) , next(n) { }
|
||||||
};
|
};
|
||||||
|
struct LogCond {
|
||||||
struct LogCond
|
|
||||||
{
|
|
||||||
int argnum;
|
|
||||||
|
|
||||||
LogCondEle *list;
|
LogCondEle *list;
|
||||||
|
int argnum;
|
||||||
LogCond *next;
|
LogCond *next;
|
||||||
LogCond( int a , LogCondEle* ee , LogCond* n ) : argnum(a) , list(ee), next(n) {}
|
LogCond( int a , LogCondEle* ee , LogCond* n ) : argnum(a) , list(ee), next(n) {}
|
||||||
~LogCond();
|
~LogCond();
|
||||||
};
|
};
|
||||||
|
|
||||||
CPluginMngr::CPlugin *plugin;
|
CPluginMngr::CPlugin *plugin;
|
||||||
|
|
||||||
int func;
|
int func;
|
||||||
|
|
||||||
LogCond *filters;
|
|
||||||
LogEventsMngr* parent;
|
LogEventsMngr* parent;
|
||||||
|
LogCond *filters;
|
||||||
ForwardState m_State;
|
|
||||||
|
|
||||||
CLogEvent *next;
|
CLogEvent *next;
|
||||||
CLogEvent(CPluginMngr::CPlugin *p, int f, LogEventsMngr* ppp) : plugin(p), func(f), filters(nullptr), parent(ppp), m_State(FSTATE_ACTIVE), next(nullptr) {}
|
CLogEvent(CPluginMngr::CPlugin *p,int f, LogEventsMngr* ppp) : plugin(p),func(f), filters(0),parent(ppp) ,next(0) { }
|
||||||
~CLogEvent();
|
~CLogEvent();
|
||||||
public:
|
public:
|
||||||
inline CPluginMngr::CPlugin *getPlugin() { return plugin; }
|
|
||||||
void registerFilter( char* filter );
|
void registerFilter( char* filter );
|
||||||
void setForwardState(ForwardState value);
|
inline CPluginMngr::CPlugin *getPlugin() { return plugin; }
|
||||||
inline int getFunction() { return func; }
|
inline int getFunction() { return func; }
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
CLogEvent *logevents[MAX_LOGARGS+1];
|
CLogEvent *logevents[MAX_LOGARGS+1];
|
||||||
CLogEvent *getValidLogEvent( CLogEvent * a );
|
CLogEvent *getValidLogEvent( CLogEvent * a );
|
||||||
CLogCmp* registerCondition(char* filter);
|
CLogCmp* registerCondition(char* filter);
|
||||||
|
|
||||||
void clearConditions();
|
void clearConditions();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LogEventsMngr();
|
LogEventsMngr();
|
||||||
~LogEventsMngr();
|
~LogEventsMngr();
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
int registerLogEvent(CPluginMngr::CPlugin* plugin, int func, int pos);
|
|
||||||
inline bool logEventsExist() { return arelogevents; }
|
|
||||||
|
|
||||||
void setLogString(const char* frmt, va_list& vaptr);
|
|
||||||
void setLogString(const char* frmt, ...);
|
CLogEvent* registerLogEvent( CPluginMngr::CPlugin* plugin, int func, int pos );
|
||||||
|
inline bool logEventsExist() { return arelogevents; }
|
||||||
|
void setLogString( char* frmt, va_list& vaptr );
|
||||||
|
void setLogString( char* frmt , ... );
|
||||||
void parseLogString( );
|
void parseLogString( );
|
||||||
void executeLogEvents();
|
void executeLogEvents();
|
||||||
|
|
||||||
inline const char* getLogString() { return logString; }
|
inline const char* getLogString() { return logString; }
|
||||||
inline int getLogArgNum() { return logArgc; }
|
inline int getLogArgNum() { return logArgc; }
|
||||||
inline const char* getLogArg( int i ) { return ( i < 0 || i >= logArgc ) ? "" : logArgs[ i ]; }
|
inline const char* getLogArg( int i ) { return ( i < 0 || i >= logArgc ) ? "" : logArgs[ i ]; }
|
||||||
void clearLogEvents();
|
void clearLogEvents();
|
||||||
|
|
||||||
class iterator
|
|
||||||
{
|
|
||||||
CLogEvent* a;
|
|
||||||
LogEventsMngr* b;
|
|
||||||
|
|
||||||
|
class iterator {
|
||||||
|
LogEventsMngr* b;
|
||||||
|
CLogEvent* a;
|
||||||
public:
|
public:
|
||||||
inline iterator(CLogEvent*aa,LogEventsMngr* bb) : a(aa), b(bb) {}
|
inline iterator(CLogEvent*aa,LogEventsMngr* bb) : a(aa), b(bb) {}
|
||||||
|
inline iterator& operator++() {
|
||||||
inline iterator& operator++()
|
|
||||||
{
|
|
||||||
a = b->getValidLogEvent( a->next );
|
a = b->getValidLogEvent( a->next );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const iterator& c) const { return a == c.a; }
|
inline bool operator==(const iterator& c) const { return a == c.a; }
|
||||||
inline bool operator!=(const iterator& c) const { return !operator==(c); }
|
inline bool operator!=(const iterator& c) const { return !operator==(c); }
|
||||||
CLogEvent& operator*() { return *a; }
|
CLogEvent& operator*() { return *a; }
|
||||||
operator bool ( ) const { return a ? true : false; }
|
operator bool ( ) const { return a ? true : false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline iterator begin() { return iterator(getValidLogEvent(logevents[ logArgc ]),this); }
|
inline iterator begin() { return iterator(getValidLogEvent(logevents[ logArgc ]),this); }
|
||||||
inline iterator end() { return iterator(0,this); }
|
inline iterator end() { return iterator(0,this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LogEventHook
|
#endif
|
||||||
{
|
|
||||||
explicit LogEventHook(LogEventsMngr::CLogEvent *logevent) : m_logevent(logevent) {}
|
|
||||||
LogEventsMngr::CLogEvent *m_logevent;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern NativeHandle<LogEventHook> LogEventHandles;
|
|
||||||
|
|
||||||
#endif //LOGEVENTS_H
|
|
||||||
|
@ -1,87 +1,77 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include <extdll.h>
|
||||||
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
#include "CMenu.h"
|
#include "CMenu.h"
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class MenuMngr
|
// class MenuMngr
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
MenuMngr::MenuCommand::MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f, bool new_menu)
|
MenuMngr::MenuCommand::MenuCommand( CPluginMngr::CPlugin *a, int mi, int k, int f ) {
|
||||||
{
|
|
||||||
plugin = a;
|
plugin = a;
|
||||||
keys = k;
|
keys = k;
|
||||||
menuid = mi;
|
menuid = mi;
|
||||||
next = 0;
|
|
||||||
is_new_menu = new_menu;
|
|
||||||
|
|
||||||
function = f;
|
function = f;
|
||||||
|
next = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuMngr::~MenuMngr()
|
MenuMngr::~MenuMngr()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
MenuMngr::MenuIdEle::uniqueid = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MenuMngr::findMenuId(const char* name, AMX* amx)
|
int MenuMngr::findMenuId(const char* name, AMX* amx)
|
||||||
{
|
{
|
||||||
for (MenuIdEle* b = headid; b; b = b->next)
|
for( MenuIdEle* b = headid; b ; b = b->next) {
|
||||||
{
|
if ( (!b->amx || amx == b->amx) && strstr(name,b->name.str()) )
|
||||||
if ((!amx || !b->amx || amx == b->amx) && strstr(name,b->name.chars()))
|
|
||||||
return b->id;
|
return b->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MenuMngr::registerMenuId(const char* n, AMX* a )
|
int MenuMngr::registerMenuId(const char* n, AMX* a )
|
||||||
{
|
{
|
||||||
int id = findMenuId( n, a );
|
int id = findMenuId( n, a );
|
||||||
|
if (id) return id;
|
||||||
if (id)
|
|
||||||
{
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
headid = new MenuIdEle( n, a , headid );
|
headid = new MenuIdEle( n, a , headid );
|
||||||
|
|
||||||
return headid->id;
|
return headid->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuMngr::registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f, bool from_new_menu)
|
void MenuMngr::registerMenuCmd( CPluginMngr::CPlugin *a,int mi, int k , int f )
|
||||||
{
|
{
|
||||||
MenuCommand** temp = &headcmd;
|
MenuCommand** temp = &headcmd;
|
||||||
if (from_new_menu)
|
while(*temp) temp = &(*temp)->next;
|
||||||
{
|
*temp = new MenuCommand(a,mi, k,f);
|
||||||
MenuCommand *ptr;
|
|
||||||
while (*temp)
|
|
||||||
{
|
|
||||||
ptr = *temp;
|
|
||||||
if (ptr->is_new_menu
|
|
||||||
&& ptr->plugin == a
|
|
||||||
&& ptr->menuid == mi)
|
|
||||||
{
|
|
||||||
if (g_forwards.isSameSPForward(ptr->function, f))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
temp = &(*temp)->next;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (*temp)
|
|
||||||
{
|
|
||||||
temp = &(*temp)->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*temp = new MenuCommand(a, mi, k, f, from_new_menu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuMngr::clear()
|
void MenuMngr::clear()
|
||||||
@ -101,13 +91,4 @@ void MenuMngr::clear()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuMngr::iterator MenuMngr::SetWatchIter(MenuMngr::iterator iter)
|
|
||||||
{
|
|
||||||
MenuMngr::iterator old = m_watch_iter;
|
|
||||||
|
|
||||||
m_watch_iter = iter;
|
|
||||||
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MenuMngr::MenuIdEle::uniqueid = 0;
|
int MenuMngr::MenuIdEle::uniqueid = 0;
|
@ -1,11 +1,33 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef MENUS_H
|
#ifndef MENUS_H
|
||||||
#define MENUS_H
|
#define MENUS_H
|
||||||
@ -18,21 +40,20 @@ class MenuMngr
|
|||||||
{
|
{
|
||||||
struct MenuIdEle
|
struct MenuIdEle
|
||||||
{
|
{
|
||||||
ke::AString name;
|
String name;
|
||||||
AMX* amx;
|
AMX* amx;
|
||||||
MenuIdEle* next;
|
MenuIdEle* next;
|
||||||
|
|
||||||
int id;
|
int id;
|
||||||
static int uniqueid;
|
static int uniqueid;
|
||||||
|
MenuIdEle( const char* n, AMX* a, MenuIdEle* m ) : name( n ) , amx(a) , next( m ) {
|
||||||
MenuIdEle(const char* n, AMX* a, MenuIdEle* m) : name(n), amx(a), next(m)
|
|
||||||
{
|
|
||||||
id = ++uniqueid;
|
id = ++uniqueid;
|
||||||
}
|
}
|
||||||
|
~MenuIdEle() { --uniqueid; }
|
||||||
} *headid;
|
} *headid;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class iterator;
|
class iterator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
class MenuCommand
|
class MenuCommand
|
||||||
@ -44,34 +65,28 @@ private:
|
|||||||
int menuid;
|
int menuid;
|
||||||
int keys;
|
int keys;
|
||||||
int function;
|
int function;
|
||||||
int is_new_menu;
|
|
||||||
|
|
||||||
MenuCommand* next;
|
MenuCommand* next;
|
||||||
MenuCommand(CPluginMngr::CPlugin *a, int mi, int k, int f, bool new_menu=false);
|
MenuCommand( CPluginMngr::CPlugin *a, int mi, int k, int f );
|
||||||
public:
|
public:
|
||||||
inline int getFunction() { return function; }
|
inline int getFunction() { return function; }
|
||||||
inline CPluginMngr::CPlugin* getPlugin() { return plugin; }
|
inline CPluginMngr::CPlugin* getPlugin() { return plugin; }
|
||||||
inline bool matchCommand(int m, int k)
|
inline bool matchCommand( int m, int k ) { return ((m == menuid) && (keys & k)); }
|
||||||
{
|
|
||||||
return ((m == menuid) && (keys & k));
|
|
||||||
}
|
|
||||||
} *headcmd;
|
} *headcmd;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MenuMngr() : m_watch_iter(end())
|
|
||||||
{ headid = NULL; headcmd = NULL; }
|
MenuMngr() { headid = 0; headcmd = 0; }
|
||||||
~MenuMngr();
|
~MenuMngr();
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
|
|
||||||
|
|
||||||
int findMenuId(const char* name, AMX* a = 0);
|
int findMenuId(const char* name, AMX* a = 0);
|
||||||
int registerMenuId(const char* n, AMX* a );
|
int registerMenuId(const char* n, AMX* a );
|
||||||
void registerMenuCmd(CPluginMngr::CPlugin *a, int mi, int k, int f, bool from_new_menu=false);
|
void registerMenuCmd( CPluginMngr::CPlugin *a,int mi, int k , int f );
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
class iterator
|
class iterator {
|
||||||
{
|
|
||||||
friend class MenuMngr;
|
|
||||||
MenuCommand* a;
|
MenuCommand* a;
|
||||||
public:
|
public:
|
||||||
iterator(MenuCommand*aa) : a(aa) {}
|
iterator(MenuCommand*aa) : a(aa) {}
|
||||||
@ -81,16 +96,12 @@ public:
|
|||||||
operator bool () const { return a ? true : false; }
|
operator bool () const { return a ? true : false; }
|
||||||
MenuCommand& operator*() { return *a; }
|
MenuCommand& operator*() { return *a; }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline iterator begin() const { return iterator(headcmd); }
|
inline iterator begin() const { return iterator(headcmd); }
|
||||||
inline iterator end() const { return iterator(0); }
|
inline iterator end() const { return iterator(0); }
|
||||||
|
|
||||||
MenuMngr::iterator SetWatchIter(MenuMngr::iterator iter);
|
|
||||||
inline MenuMngr::iterator GetWatchIter() { return m_watch_iter; }
|
|
||||||
private:
|
|
||||||
MenuMngr::iterator m_watch_iter;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MenuMngr g_menucmds;
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif //MENUS_H
|
|
||||||
|
@ -1,27 +1,49 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <extdll.h>
|
||||||
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "newmenus.h"
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class CPlayer
|
// class CPlayer
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
void CPlayer::Init( edict_t* e , int i )
|
void CPlayer::Init( edict_t* e , int i )
|
||||||
{
|
{
|
||||||
index = i;
|
index = i;
|
||||||
pEdict = e;
|
pEdict = e;
|
||||||
initialized = false;
|
initialized = false;
|
||||||
ingame = false;
|
ingame = false;
|
||||||
|
bot = false;
|
||||||
authorized = false;
|
authorized = false;
|
||||||
disconnecting = false;
|
|
||||||
teamIdsInitialized = false;
|
|
||||||
|
|
||||||
current = 0;
|
current = 0;
|
||||||
teamId = -1;
|
teamId = -1;
|
||||||
@ -29,100 +51,47 @@ void CPlayer::Init(edict_t* e, int i)
|
|||||||
aiming = 0;
|
aiming = 0;
|
||||||
menu = 0;
|
menu = 0;
|
||||||
keys = 0;
|
keys = 0;
|
||||||
menuexpire = 0.0;
|
|
||||||
newmenu = -1;
|
|
||||||
|
|
||||||
death_weapon = nullptr;
|
death_weapon.clear();
|
||||||
name = nullptr;
|
name.clear();
|
||||||
ip = nullptr;
|
ip.clear();
|
||||||
team = nullptr;
|
team.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayer::Disconnect()
|
void CPlayer::Disconnect() {
|
||||||
{
|
|
||||||
ingame = false;
|
ingame = false;
|
||||||
initialized = false;
|
initialized = false;
|
||||||
authorized = false;
|
authorized = false;
|
||||||
disconnecting = false;
|
|
||||||
teamIdsInitialized = false;
|
|
||||||
|
|
||||||
if (Menu *pMenu = get_menu_by_id(newmenu))
|
|
||||||
pMenu->Close(index);
|
|
||||||
|
|
||||||
List<ClientCvarQuery_Info *>::iterator iter, end=queries.end();
|
|
||||||
for (iter=queries.begin(); iter!=end; iter++)
|
|
||||||
{
|
|
||||||
unregisterSPForward((*iter)->resultFwd);
|
|
||||||
delete [] (*iter)->params;
|
|
||||||
delete (*iter);
|
|
||||||
}
|
}
|
||||||
queries.clear();
|
void CPlayer::PutInServer() {
|
||||||
|
|
||||||
menu = 0;
|
|
||||||
newmenu = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPlayer::PutInServer()
|
|
||||||
{
|
|
||||||
playtime = gpGlobals->time;
|
playtime = gpGlobals->time;
|
||||||
ingame = true;
|
ingame = true;
|
||||||
}
|
}
|
||||||
|
bool CPlayer::Connect(const char* connectname,const char* ipaddress) {
|
||||||
int CPlayer::NextHUDChannel()
|
name.set(connectname);
|
||||||
{
|
ip.set(ipaddress);
|
||||||
int ilow = 1;
|
|
||||||
|
|
||||||
for (int i=ilow+1; i<=4; i++)
|
|
||||||
{
|
|
||||||
if (channels[i] < channels[ilow])
|
|
||||||
ilow = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ilow;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CPlayer::Connect(const char* connectname, const char* ipaddress)
|
|
||||||
{
|
|
||||||
name = connectname;
|
|
||||||
ip = ipaddress;
|
|
||||||
time = gpGlobals->time;
|
time = gpGlobals->time;
|
||||||
|
bot = IsBot();
|
||||||
death_killer = 0;
|
death_killer = 0;
|
||||||
menu = 0;
|
|
||||||
newmenu = -1;
|
|
||||||
|
|
||||||
memset(flags,0,sizeof(flags));
|
memset(flags,0,sizeof(flags));
|
||||||
memset(weapons,0,sizeof(weapons));
|
memset(weapons,0,sizeof(weapons));
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
authorized = false;
|
authorized = false;
|
||||||
|
|
||||||
for (int i=0; i<=4; i++)
|
|
||||||
{
|
|
||||||
channels[i] = 0.0f;
|
|
||||||
hudmap[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ClientCvarQuery_Info *>::iterator iter, end=queries.end();
|
|
||||||
for (iter=queries.begin(); iter!=end; iter++)
|
|
||||||
{
|
|
||||||
unregisterSPForward((*iter)->resultFwd);
|
|
||||||
delete [] (*iter)->params;
|
|
||||||
delete (*iter);
|
|
||||||
}
|
|
||||||
queries.clear();
|
|
||||||
|
|
||||||
const char* authid = GETPLAYERAUTHID( pEdict );
|
const char* authid = GETPLAYERAUTHID( pEdict );
|
||||||
|
|
||||||
if ((authid == 0) || (*authid == 0) || (strcmp(authid, "STEAM_ID_PENDING") == 0))
|
if ( (authid == 0) || (*authid == 0)
|
||||||
|
|| (strcmp( authid , "STEAM_ID_PENDING") == 0) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class Grenades
|
// class Grenades
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
void Grenades::put( edict_t* grenade, float time, int type, CPlayer* player )
|
void Grenades::put( edict_t* grenade, float time, int type, CPlayer* player )
|
||||||
{
|
{
|
||||||
Obj* a = new Obj;
|
Obj* a = new Obj;
|
||||||
@ -139,33 +108,29 @@ bool Grenades::find(edict_t* enemy, CPlayer** p, int& type)
|
|||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
Obj** a = &head;
|
Obj** a = &head;
|
||||||
|
while ( *a ){
|
||||||
while (*a)
|
if ( (*a)->time > gpGlobals->time ) {
|
||||||
{
|
if ( (*a)->grenade == enemy ) {
|
||||||
if ((*a)->time > gpGlobals->time)
|
|
||||||
{
|
|
||||||
if ((*a)->grenade == enemy)
|
|
||||||
{
|
|
||||||
found = true;
|
found = true;
|
||||||
(*p) = (*a)->player;
|
(*p) = (*a)->player;
|
||||||
type = (*a)->type;
|
type = (*a)->type;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Obj* b = (*a)->next;
|
Obj* b = (*a)->next;
|
||||||
delete *a;
|
delete *a;
|
||||||
*a = b;
|
*a = b;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
}
|
}
|
||||||
a = &(*a)->next;
|
a = &(*a)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Grenades::clear()
|
void Grenades::clear()
|
||||||
{
|
{
|
||||||
while (head)
|
while(head){
|
||||||
{
|
|
||||||
Obj* a = head->next;
|
Obj* a = head->next;
|
||||||
delete head;
|
delete head;
|
||||||
head = a;
|
head = a;
|
||||||
@ -175,9 +140,7 @@ void Grenades::clear()
|
|||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class XVars
|
// class XVars
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
void XVars::clear() {
|
||||||
void XVars::clear()
|
|
||||||
{
|
|
||||||
delete[] head;
|
delete[] head;
|
||||||
head = 0;
|
head = 0;
|
||||||
num = 0;
|
num = 0;
|
||||||
@ -186,8 +149,7 @@ void XVars::clear()
|
|||||||
|
|
||||||
int XVars::put( AMX* p, cell* v )
|
int XVars::put( AMX* p, cell* v )
|
||||||
{
|
{
|
||||||
for (int a = 0; a < num; ++a)
|
for(int a = 0; a < num; ++a) {
|
||||||
{
|
|
||||||
if ( (head[a].amx == p) && (head[a].value == v) )
|
if ( (head[a].amx == p) && (head[a].value == v) )
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@ -197,38 +159,29 @@ int XVars::put(AMX* p, cell* v)
|
|||||||
|
|
||||||
head[num].value = v;
|
head[num].value = v;
|
||||||
head[num].amx = p;
|
head[num].amx = p;
|
||||||
|
|
||||||
return num++;
|
return num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
int XVars::realloc_array( int nsize )
|
int XVars::realloc_array( int nsize )
|
||||||
{
|
{
|
||||||
XVarEle* me = new XVarEle[nsize];
|
XVarEle* me = new XVarEle[nsize];
|
||||||
|
if ( me ){
|
||||||
if (me)
|
|
||||||
{
|
|
||||||
for(int a = 0 ; a < num; ++a)
|
for(int a = 0 ; a < num; ++a)
|
||||||
me[a] = head[a];
|
me[a] = head[a];
|
||||||
|
|
||||||
delete[] head;
|
delete[] head;
|
||||||
head = me;
|
head = me;
|
||||||
size = nsize;
|
size = nsize;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class TeamIds
|
// class TeamIds
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
TeamIds::TeamIds() { head = 0; newTeam = 0; }
|
TeamIds::TeamIds() { head = 0; newTeam = 0; }
|
||||||
|
TeamIds::~TeamIds() {
|
||||||
TeamIds::~TeamIds()
|
while( head ) {
|
||||||
{
|
|
||||||
while (head)
|
|
||||||
{
|
|
||||||
TeamEle* a = head->next;
|
TeamEle* a = head->next;
|
||||||
delete head;
|
delete head;
|
||||||
head = a;
|
head = a;
|
||||||
@ -238,56 +191,42 @@ TeamIds::~TeamIds()
|
|||||||
void TeamIds::registerTeam( const char* n ,int s )
|
void TeamIds::registerTeam( const char* n ,int s )
|
||||||
{
|
{
|
||||||
TeamEle** a = &head;
|
TeamEle** a = &head;
|
||||||
|
while( *a ){
|
||||||
while (*a)
|
if ( strcmp((*a)->name.str(),n) == 0 ){
|
||||||
{
|
if (s != -1){
|
||||||
if (strcmp((*a)->name.chars(),n) == 0)
|
|
||||||
{
|
|
||||||
if (s != -1)
|
|
||||||
{
|
|
||||||
(*a)->id = s;
|
(*a)->id = s;
|
||||||
newTeam &= ~(1<<(*a)->tid);
|
newTeam &= ~(1<<(*a)->tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
a = &(*a)->next;
|
a = &(*a)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
*a = new TeamEle( n , s );
|
*a = new TeamEle( n , s );
|
||||||
|
if ( *a == 0 ) return;
|
||||||
if (*a == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
newTeam |= (1<<(*a)->tid);
|
newTeam |= (1<<(*a)->tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TeamIds::findTeamId( const char* n )
|
int TeamIds::findTeamId( const char* n )
|
||||||
{
|
{
|
||||||
TeamEle* a = head;
|
TeamEle* a = head;
|
||||||
|
while( a ){
|
||||||
while (a)
|
if ( !strcmpi(a->name.str(),n) )
|
||||||
{
|
|
||||||
if (!stricmp(a->name.chars(), n))
|
|
||||||
return a->id;
|
return a->id;
|
||||||
a = a->next;
|
a = a->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TeamIds::findTeamIdCase( const char* n)
|
int TeamIds::findTeamIdCase( const char* n)
|
||||||
{
|
{
|
||||||
TeamEle* a = head;
|
TeamEle* a = head;
|
||||||
|
while( a ){
|
||||||
while (a)
|
if ( !strcmp(a->name.str(), n) )
|
||||||
{
|
|
||||||
if (!strcmp(a->name.chars(), n))
|
|
||||||
return a->id;
|
return a->id;
|
||||||
a = a->next;
|
a = a->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char TeamIds::TeamEle::uid = 0;
|
char TeamIds::TeamEle::uid = 0;
|
||||||
|
|
||||||
|
260
amxmodx/CMisc.h
260
amxmodx/CMisc.h
@ -1,51 +1,87 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef CMISC_H
|
#ifndef CMISC_H
|
||||||
#define CMISC_H
|
#define CMISC_H
|
||||||
|
|
||||||
#include "sh_list.h"
|
#include "CList.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// class CCVar
|
||||||
|
// *****************************************************
|
||||||
|
class CCVar
|
||||||
|
{
|
||||||
|
cvar_t cvar;
|
||||||
|
String name;
|
||||||
|
String plugin;
|
||||||
|
public:
|
||||||
|
CCVar( const char* pname, const char* pplugin,
|
||||||
|
int pflags, float pvalue ) : name(pname) , plugin(pplugin ) {
|
||||||
|
cvar.name = (char*)name.str();
|
||||||
|
cvar.flags = pflags;
|
||||||
|
cvar.string = "";
|
||||||
|
cvar.value = pvalue;
|
||||||
|
}
|
||||||
|
inline cvar_t* getCvar() { return &cvar; }
|
||||||
|
inline const char* getPluginName() { return plugin.str(); }
|
||||||
|
inline const char* getName() { return name.str(); }
|
||||||
|
inline bool operator == ( const char* string ) const { return (strcmp(name.str(),string)==0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class CPlayer
|
// class CPlayer
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
struct ClientCvarQuery_Info
|
|
||||||
{
|
|
||||||
int resultFwd;
|
|
||||||
int requestId;
|
|
||||||
int paramLen;
|
|
||||||
cell *params;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CPlayer
|
class CPlayer
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
edict_t* pEdict;
|
edict_t* pEdict;
|
||||||
|
|
||||||
ke::AString name;
|
String name;
|
||||||
ke::AString ip;
|
String ip;
|
||||||
ke::AString team;
|
String team;
|
||||||
|
|
||||||
bool initialized;
|
bool initialized;
|
||||||
bool ingame;
|
bool ingame;
|
||||||
|
bool bot;
|
||||||
bool authorized;
|
bool authorized;
|
||||||
bool disconnecting;
|
|
||||||
bool vgui;
|
|
||||||
bool teamIdsInitialized;
|
|
||||||
|
|
||||||
float time;
|
float time;
|
||||||
float playtime;
|
float playtime;
|
||||||
float menuexpire;
|
|
||||||
|
|
||||||
struct
|
struct {
|
||||||
{
|
|
||||||
int ammo;
|
int ammo;
|
||||||
int clip;
|
int clip;
|
||||||
} weapons[MAX_WEAPONS];
|
} weapons[MAX_WEAPONS];
|
||||||
@ -63,49 +99,28 @@ public:
|
|||||||
int death_killer;
|
int death_killer;
|
||||||
int death_victim;
|
int death_victim;
|
||||||
bool death_tk;
|
bool death_tk;
|
||||||
ke::AString death_weapon;
|
String death_weapon;
|
||||||
int newmenu;
|
|
||||||
int page;
|
|
||||||
|
|
||||||
float channels[5];
|
|
||||||
cell hudmap[5];
|
|
||||||
|
|
||||||
Vector lastTrace;
|
Vector lastTrace;
|
||||||
|
Vector thisTrace;
|
||||||
Vector lastHit;
|
Vector lastHit;
|
||||||
|
|
||||||
List<ClientCvarQuery_Info *> queries;
|
|
||||||
|
|
||||||
void Init( edict_t* e , int i );
|
void Init( edict_t* e , int i );
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
void PutInServer();
|
void PutInServer();
|
||||||
|
|
||||||
bool Connect(const char* connectname,const char* ipaddress);
|
bool Connect(const char* connectname,const char* ipaddress);
|
||||||
|
|
||||||
inline bool IsBot()
|
inline bool IsBot(){
|
||||||
{
|
const char* auth= (*g_engfuncs.pfnGetPlayerAuthId)(pEdict);
|
||||||
if ((pEdict->v.flags & FL_FAKECLIENT) == FL_FAKECLIENT)
|
return ( auth && !strcmp( auth , "BOT" ) );
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *auth = GETPLAYERAUTHID(pEdict);
|
inline bool IsAlive(){
|
||||||
if (auth && (strcmp(auth, "BOT") == 0))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool IsAlive()
|
|
||||||
{
|
|
||||||
return ((pEdict->v.deadflag==DEAD_NO)&&(pEdict->v.health>0));
|
return ((pEdict->v.deadflag==DEAD_NO)&&(pEdict->v.health>0));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Authorize() { authorized = true; }
|
inline void Authorize() { authorized = true; }
|
||||||
|
|
||||||
int NextHUDChannel();
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
@ -123,10 +138,10 @@ class Grenades
|
|||||||
Obj* next;
|
Obj* next;
|
||||||
} *head;
|
} *head;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Grenades() { head = 0; }
|
Grenades() { head = 0; }
|
||||||
~Grenades() { clear(); }
|
~Grenades() { clear(); }
|
||||||
|
|
||||||
void put( edict_t* grenade, float time, int type, CPlayer* player );
|
void put( edict_t* grenade, float time, int type, CPlayer* player );
|
||||||
bool find( edict_t* enemy, CPlayer** p, int& type );
|
bool find( edict_t* enemy, CPlayer** p, int& type );
|
||||||
void clear();
|
void clear();
|
||||||
@ -135,23 +150,19 @@ public:
|
|||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class ForceObject
|
// class ForceObject
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
class ForceObject {
|
||||||
class ForceObject
|
AMX* amx;
|
||||||
{
|
String filename;
|
||||||
ke::AString filename;
|
|
||||||
FORCE_TYPE type;
|
FORCE_TYPE type;
|
||||||
Vector mins;
|
Vector mins;
|
||||||
Vector maxs;
|
Vector maxs;
|
||||||
AMX* amx;
|
|
||||||
public:
|
public:
|
||||||
ForceObject(const char* n, FORCE_TYPE c, Vector& mi, Vector& ma, AMX* a) : filename(n), type(c), mins(mi), maxs(ma), amx(a) {}
|
ForceObject(const char* n, FORCE_TYPE c,Vector& mi, Vector& ma, AMX* a) :
|
||||||
|
filename(n) , type(c), mins(mi), maxs(ma), amx(a) {}
|
||||||
inline const char* getFilename() { return filename.chars(); }
|
inline const char* getFilename() { return filename.str(); }
|
||||||
inline AMX* getAMX() { return amx; }
|
inline AMX* getAMX() { return amx; }
|
||||||
|
|
||||||
Vector& getMin() { return mins; }
|
Vector& getMin() { return mins; }
|
||||||
Vector& getMax() { return maxs; }
|
Vector& getMax() { return maxs; }
|
||||||
|
|
||||||
inline FORCE_TYPE getForceType() { return type; }
|
inline FORCE_TYPE getForceType() { return type; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -161,38 +172,30 @@ public:
|
|||||||
|
|
||||||
class XVars
|
class XVars
|
||||||
{
|
{
|
||||||
struct XVarEle
|
struct XVarEle {
|
||||||
{
|
|
||||||
AMX* amx;
|
AMX* amx;
|
||||||
cell* value;
|
cell* value;
|
||||||
};
|
};
|
||||||
|
|
||||||
XVarEle* head;
|
XVarEle* head;
|
||||||
|
|
||||||
int size;
|
int size;
|
||||||
int num;
|
int num;
|
||||||
|
|
||||||
int realloc_array( int nsize );
|
int realloc_array( int nsize );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
XVars() { num = 0; size = 0; head = 0; }
|
XVars() { num = 0; size = 0; head = 0; }
|
||||||
~XVars() { clear(); }
|
~XVars() { clear(); }
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
int put( AMX* a, cell* v );
|
int put( AMX* a, cell* v );
|
||||||
|
inline cell getValue( int a ) {
|
||||||
inline cell getValue(int a)
|
|
||||||
{
|
|
||||||
return ( a >= 0 && a < num ) ? *(head[a].value) : 0;
|
return ( a >= 0 && a < num ) ? *(head[a].value) : 0;
|
||||||
}
|
}
|
||||||
|
inline int setValue( int a, cell v ) {
|
||||||
inline int setValue(int a, cell v)
|
if ( a >= 0 && a < num ){
|
||||||
{
|
|
||||||
if (a >= 0 && a < num)
|
|
||||||
{
|
|
||||||
*(head[a].value) = v;
|
*(head[a].value) = v;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -200,39 +203,33 @@ public:
|
|||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class CScript
|
// class CScript
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
class CScript
|
||||||
class CScript : public ke::InlineListNode<CScript>
|
|
||||||
{
|
{
|
||||||
ke::AString filename;
|
String filename;
|
||||||
AMX* amx;
|
AMX* amx;
|
||||||
void* code;
|
void* code;
|
||||||
public:
|
public:
|
||||||
CScript(AMX* aa, void* cc,const char* ff):filename(ff),amx(aa),code(cc){}
|
CScript(AMX* aa, void* cc,const char* ff):filename(ff),amx(aa),code(cc){}
|
||||||
|
|
||||||
inline AMX* getAMX() { return amx; }
|
inline AMX* getAMX() { return amx; }
|
||||||
inline const char* getName() { return filename.chars(); }
|
inline const char* getName() { return filename.str(); }
|
||||||
|
inline bool operator==( void* a ) { return (amx == (AMX*)a); }
|
||||||
inline void* getCode() { return code; }
|
inline void* getCode() { return code; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class TeamIds
|
// class TeamIds
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
class TeamIds
|
class TeamIds
|
||||||
{
|
{
|
||||||
struct TeamEle
|
struct TeamEle {
|
||||||
{
|
String name;
|
||||||
ke::AString name;
|
|
||||||
int id;
|
int id;
|
||||||
char tid;
|
char tid;
|
||||||
static char uid;
|
static char uid;
|
||||||
TeamEle* next;
|
TeamEle* next;
|
||||||
|
TeamEle(const char* n, int& i) : name(n) , id(i) , next(0) {
|
||||||
TeamEle(const char* n, int& i) : name(n), id(i), next(0)
|
|
||||||
{
|
|
||||||
tid = uid++;
|
tid = uid++;
|
||||||
}
|
};
|
||||||
|
|
||||||
~TeamEle(){ --uid; }
|
~TeamEle(){ --uid; }
|
||||||
} *head;
|
} *head;
|
||||||
|
|
||||||
@ -241,94 +238,15 @@ class TeamIds
|
|||||||
public:
|
public:
|
||||||
TeamIds();
|
TeamIds();
|
||||||
~TeamIds();
|
~TeamIds();
|
||||||
|
|
||||||
void registerTeam( const char* n ,int s );
|
void registerTeam( const char* n ,int s );
|
||||||
int findTeamId( const char* n);
|
int findTeamId( const char* n);
|
||||||
int findTeamIdCase( const char* n);
|
int findTeamIdCase( const char* n);
|
||||||
inline bool isNewTeam() { return newTeam ? true : false; }
|
inline bool isNewTeam() { return newTeam ? true : false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CAdminData
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
cell m_AuthData[44];
|
|
||||||
cell m_Password[32];
|
|
||||||
cell m_Flags;
|
|
||||||
cell m_Access;
|
|
||||||
public:
|
|
||||||
|
|
||||||
CAdminData()
|
|
||||||
{
|
|
||||||
m_AuthData[0]=0;
|
|
||||||
m_Password[0]=0;
|
|
||||||
m_Flags=0;
|
|
||||||
m_Access=0;
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetAccess(cell Access)
|
#endif
|
||||||
{
|
|
||||||
m_Access=Access;
|
|
||||||
};
|
|
||||||
cell GetAccess(void) const
|
|
||||||
{
|
|
||||||
return m_Access;
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetFlags(cell Flags)
|
|
||||||
{
|
|
||||||
m_Flags=Flags;
|
|
||||||
};
|
|
||||||
cell GetFlags(void) const
|
|
||||||
{
|
|
||||||
return m_Flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetAuthID(const cell *Input)
|
|
||||||
{
|
|
||||||
unsigned int i=0;
|
|
||||||
while (i<sizeof(m_AuthData)-1)
|
|
||||||
{
|
|
||||||
if ((m_AuthData[i++]=*Input++)==0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_AuthData[arraysize(m_AuthData)-1]=0;
|
|
||||||
|
|
||||||
};
|
|
||||||
const cell *GetAuthID(void) const
|
|
||||||
{
|
|
||||||
return &m_AuthData[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetPass(const cell *Input)
|
|
||||||
{
|
|
||||||
unsigned int i=0;
|
|
||||||
while (i<sizeof(m_Password)-1)
|
|
||||||
{
|
|
||||||
if ((m_Password[i++]=*Input++)==0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Password[arraysize(m_Password)-1]=0;
|
|
||||||
|
|
||||||
};
|
|
||||||
const cell *GetPass(void) const
|
|
||||||
{
|
|
||||||
return &m_Password[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
CAdminData & operator = (const CAdminData &src)
|
|
||||||
{
|
|
||||||
this->SetAccess(src.GetAccess());
|
|
||||||
this->SetFlags(src.GetFlags());
|
|
||||||
this->SetAuthID(src.GetAuthID());
|
|
||||||
this->SetPass(src.GetPass());
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif //CMISC_H
|
|
||||||
|
@ -1,390 +1,184 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include <extdll.h>
|
||||||
#include "libraries.h"
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
|
|
||||||
#ifndef FAR
|
#ifndef FAR // PM: Test: FAR
|
||||||
#define FAR
|
#define FAR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// New
|
typedef int (FAR *QUERYMOD)(module_info_s**);
|
||||||
typedef void* (*PFN_REQ_FNPTR)(const char * /*name*/);
|
typedef int (FAR *ATTACHMOD)(pfnamx_engine_g*,pfnmodule_engine_g*);
|
||||||
typedef int (FAR *QUERYMOD_NEW)(int * /*ifvers*/, amxx_module_info_s * /*modInfo*/);
|
typedef int (FAR *DETACHMOD)(void);
|
||||||
typedef int (FAR *CHECKGAME_NEW)(const char *);
|
|
||||||
typedef int (FAR *ATTACHMOD_NEW)(PFN_REQ_FNPTR /*reqFnptrFunc*/);
|
QUERYMOD QueryModule;
|
||||||
typedef int (FAR *DETACHMOD_NEW)(void);
|
ATTACHMOD AttachModule;
|
||||||
typedef void (FAR *PLUGINSLOADED_NEW)(void);
|
DETACHMOD DetachModule;
|
||||||
typedef void (*PLUGINSUNLOADED_NEW)(void);
|
|
||||||
typedef void (*PLUGINSUNLOADING_NEW)(void);
|
|
||||||
|
|
||||||
|
pfnamx_engine_g engAmxFunc = {
|
||||||
|
amx_Align16,
|
||||||
|
amx_Align32,
|
||||||
|
amx_Allot,
|
||||||
|
amx_Callback,
|
||||||
|
amx_Clone,
|
||||||
|
amx_Debug,
|
||||||
|
amx_Exec,
|
||||||
|
amx_Execv,
|
||||||
|
amx_FindPublic,
|
||||||
|
amx_FindPubVar,
|
||||||
|
amx_FindTagId,
|
||||||
|
amx_Flags,
|
||||||
|
amx_GetAddr,
|
||||||
|
amx_GetPublic,
|
||||||
|
amx_GetPubVar,
|
||||||
|
amx_GetString,
|
||||||
|
amx_GetTag,
|
||||||
|
amx_GetUserData,
|
||||||
|
amx_Init,
|
||||||
|
amx_InitJIT,
|
||||||
|
amx_MemInfo,
|
||||||
|
amx_NameLength,
|
||||||
|
amx_NativeInfo,
|
||||||
|
amx_NumPublics,
|
||||||
|
amx_NumPubVars,
|
||||||
|
amx_NumTags,
|
||||||
|
amx_RaiseError,
|
||||||
|
amx_Register,
|
||||||
|
amx_Release,
|
||||||
|
amx_SetCallback,
|
||||||
|
amx_SetDebugHook,
|
||||||
|
amx_SetString,
|
||||||
|
amx_SetUserData,
|
||||||
|
amx_StrLen,
|
||||||
|
};
|
||||||
|
|
||||||
|
pfnmodule_engine_g engModuleFunc = {
|
||||||
|
add_amxnatives,
|
||||||
|
build_pathname,
|
||||||
|
copy_amxmemory,
|
||||||
|
format_amxstring,
|
||||||
|
get_amxaddr,
|
||||||
|
get_amxscript,
|
||||||
|
get_amxscriptname,
|
||||||
|
get_amxstring,
|
||||||
|
get_modname,
|
||||||
|
load_amxscript,
|
||||||
|
print_srvconsole,
|
||||||
|
report_error,
|
||||||
|
set_amxnatives,
|
||||||
|
set_amxstring,
|
||||||
|
amxstring_len,
|
||||||
|
unload_amxscript,
|
||||||
|
alloc_amxmemory,
|
||||||
|
free_amxmemory,
|
||||||
|
};
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class CModule
|
// class CModule
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
CModule::CModule(const char* fname)
|
CModule::CModule(const char* fname) : filename(fname)
|
||||||
{
|
{
|
||||||
m_Filename = fname;
|
metamod = false;
|
||||||
clear(false);
|
info = 0;
|
||||||
|
module = 0;
|
||||||
|
status = MODULE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CModule::~CModule()
|
CModule::~CModule()
|
||||||
{
|
{
|
||||||
// old & new
|
if ( module ) DLFREE(module);
|
||||||
if (m_Handle)
|
natives.clear();
|
||||||
DLFREE(m_Handle);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CModule::clear(bool clearFilename)
|
|
||||||
{
|
|
||||||
// old & new
|
|
||||||
m_Metamod = false;
|
|
||||||
m_Handle = NULL;
|
|
||||||
m_Status = MODULE_NONE;
|
|
||||||
|
|
||||||
if (clearFilename)
|
|
||||||
{
|
|
||||||
m_Filename = "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
// new
|
|
||||||
m_InfoNew.author = "unknown";
|
|
||||||
m_InfoNew.name = "unknown";
|
|
||||||
m_InfoNew.version = "unknown";
|
|
||||||
m_InfoNew.reload = 0;
|
|
||||||
m_MissingFunc = NULL;
|
|
||||||
|
|
||||||
for (size_t i=0; i<m_DestroyableIndexes.length(); i++)
|
|
||||||
{
|
|
||||||
delete [] m_Natives[m_DestroyableIndexes[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
m_DestroyableIndexes.clear();
|
|
||||||
m_Natives.clear();
|
|
||||||
m_NewNatives.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CModule::attachMetamod(const char *mmfile, PLUG_LOADTIME now)
|
|
||||||
{
|
|
||||||
void **handle;
|
|
||||||
void *dummy = NULL;
|
|
||||||
|
|
||||||
if (!m_Handle)
|
|
||||||
handle = &dummy;
|
|
||||||
else
|
|
||||||
handle = (void **)&m_Handle;
|
|
||||||
|
|
||||||
int res = LoadMetamodPlugin(mmfile, handle, now);
|
|
||||||
|
|
||||||
if (!res)
|
|
||||||
{
|
|
||||||
m_Metamod = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//this ugly function is ultimately something like O(n^4).
|
|
||||||
//sigh. it shouldn't be needed.
|
|
||||||
void CModule::rewriteNativeLists(AMX_NATIVE_INFO *list)
|
|
||||||
{
|
|
||||||
AMX_NATIVE_INFO *curlist;
|
|
||||||
for (size_t i=0; i<m_Natives.length(); i++)
|
|
||||||
{
|
|
||||||
curlist = m_Natives[i];
|
|
||||||
bool changed = false;
|
|
||||||
bool found = false;
|
|
||||||
ke::Vector<size_t> newlist;
|
|
||||||
for (size_t j=0; curlist[j].func != NULL; j++)
|
|
||||||
{
|
|
||||||
found = false;
|
|
||||||
for (size_t k=0; list[k].func != NULL; k++)
|
|
||||||
{
|
|
||||||
if (strcmp(curlist[j].name, list[k].name) == 0)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
changed = true;
|
|
||||||
//don't break, we have to search it all
|
|
||||||
} else {
|
|
||||||
newlist.append(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
//now build the new list
|
|
||||||
AMX_NATIVE_INFO *rlist = new AMX_NATIVE_INFO[newlist.length()+1];
|
|
||||||
for (size_t j=0; j<newlist.length(); j++)
|
|
||||||
{
|
|
||||||
rlist[j].func = curlist[newlist[j]].func;
|
|
||||||
rlist[j].name = curlist[newlist[j]].name;
|
|
||||||
}
|
|
||||||
rlist[newlist.length()].func = NULL;
|
|
||||||
rlist[newlist.length()].name = NULL;
|
|
||||||
m_Natives[i] = rlist;
|
|
||||||
m_DestroyableIndexes.append(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CModule::attachModule()
|
bool CModule::attachModule()
|
||||||
{
|
{
|
||||||
// old & new
|
if ( status != MODULE_QUERY )
|
||||||
if (m_Status != MODULE_QUERY || !m_Handle)
|
|
||||||
return false;
|
return false;
|
||||||
|
AttachModule = (ATTACHMOD)DLPROC(module,"AMX_Attach");
|
||||||
ATTACHMOD_NEW AttachFunc_New = (ATTACHMOD_NEW)DLPROC(m_Handle, "AMXX_Attach");
|
if ( AttachModule ) (*AttachModule)(&engAmxFunc,&engModuleFunc);
|
||||||
|
status = MODULE_LOADED;
|
||||||
if (!AttachFunc_New)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
g_ModuleCallReason = ModuleCall_Attach;
|
|
||||||
g_CurrentlyCalledModule = this;
|
|
||||||
int retVal = (*AttachFunc_New)(Module_ReqFnptr);
|
|
||||||
g_CurrentlyCalledModule = NULL;
|
|
||||||
g_ModuleCallReason = ModuleCall_NotCalled;
|
|
||||||
|
|
||||||
switch (retVal)
|
|
||||||
{
|
|
||||||
case AMXX_OK:
|
|
||||||
m_Status = MODULE_LOADED;
|
|
||||||
break;
|
|
||||||
case AMXX_PARAM:
|
|
||||||
AMXXLOG_Log("[AMXX] Internal Error: Module \"%s\" (version \"%s\") returned \"Invalid parameter\" from Attach func.", m_Filename.chars(), getVersion());
|
|
||||||
m_Status = MODULE_INTERROR;
|
|
||||||
return false;
|
|
||||||
case AMXX_FUNC_NOT_PRESENT:
|
|
||||||
m_Status = MODULE_FUNCNOTPRESENT;
|
|
||||||
m_MissingFunc = g_LastRequestedFunc;
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
AMXXLOG_Log("[AMXX] Module \"%s\" (version \"%s\") returned an invalid code.", m_Filename.chars(), getVersion());
|
|
||||||
m_Status = MODULE_BADLOAD;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Status == MODULE_LOADED)
|
|
||||||
{
|
|
||||||
AddLibrariesFromString(m_InfoNew.library, LibType_Library, LibSource_Module, this);
|
|
||||||
AddLibrariesFromString(m_InfoNew.libclass, LibType_Class, LibSource_Module, this);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CModule::queryModule()
|
bool CModule::queryModule()
|
||||||
{
|
{
|
||||||
if (m_Status != MODULE_NONE) // don't check if already queried
|
if ( status != MODULE_NONE ) // don't check if already quried
|
||||||
return false;
|
return false;
|
||||||
|
module = DLLOAD( filename.str() ); // link dll
|
||||||
m_Handle = DLLOAD(m_Filename.chars()); // load file
|
if ( !module ){
|
||||||
if (!m_Handle)
|
status = MODULE_BADLOAD;
|
||||||
{
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
|
||||||
AMXXLOG_Log("[AMXX] Module \"%s\" failed to load (%s)", m_Filename.chars(), dlerror());
|
|
||||||
#endif
|
|
||||||
m_Status = MODULE_BADLOAD;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
int meta = (int)DLPROC(module,"Meta_Attach"); // check if also MM
|
||||||
|
if ( meta ) metamod = true;
|
||||||
|
|
||||||
// Check whether the module uses metamod (for auto attach)
|
QueryModule = (QUERYMOD)DLPROC(module,"AMX_Query"); // check what version
|
||||||
if (DLPROC(m_Handle, "Meta_Attach"))
|
if (QueryModule == 0) {
|
||||||
m_Metamod = true;
|
status = MODULE_NOQUERY;
|
||||||
|
|
||||||
// Try new interface first
|
|
||||||
QUERYMOD_NEW queryFunc_New = (QUERYMOD_NEW)DLPROC(m_Handle, "AMXX_Query");
|
|
||||||
|
|
||||||
if (queryFunc_New)
|
|
||||||
{
|
|
||||||
int ifVers = AMXX_INTERFACE_VERSION;
|
|
||||||
g_ModuleCallReason = ModuleCall_Query;
|
|
||||||
g_CurrentlyCalledModule = this;
|
|
||||||
int retVal = (*queryFunc_New)(&ifVers, &m_InfoNew);
|
|
||||||
g_CurrentlyCalledModule = NULL;
|
|
||||||
g_ModuleCallReason = ModuleCall_NotCalled;
|
|
||||||
|
|
||||||
switch (retVal)
|
|
||||||
{
|
|
||||||
case AMXX_PARAM:
|
|
||||||
AMXXLOG_Log("[AMXX] Internal Error: Module \"%s\" (version \"%s\") returned \"Invalid parameter\" from Attach func.", m_Filename.chars(), getVersion());
|
|
||||||
m_Status = MODULE_INTERROR;
|
|
||||||
return false;
|
|
||||||
case AMXX_IFVERS:
|
|
||||||
if (ifVers < AMXX_INTERFACE_VERSION)
|
|
||||||
{
|
|
||||||
//backwards compat for new defs
|
|
||||||
if (ifVers == 3)
|
|
||||||
{
|
|
||||||
g_ModuleCallReason = ModuleCall_Query;
|
|
||||||
g_CurrentlyCalledModule = this;
|
|
||||||
retVal = (*queryFunc_New)(&ifVers, &m_InfoNew);
|
|
||||||
g_CurrentlyCalledModule = NULL;
|
|
||||||
g_ModuleCallReason = ModuleCall_NotCalled;
|
|
||||||
if (retVal == AMXX_OK)
|
|
||||||
{
|
|
||||||
m_InfoNew.library = m_InfoNew.logtag;
|
|
||||||
if (StrCaseStr(m_InfoNew.library, "sql")
|
|
||||||
|| StrCaseStr(m_InfoNew.library, "dbi"))
|
|
||||||
{
|
|
||||||
m_InfoNew.libclass = "DBI";
|
|
||||||
} else {
|
|
||||||
m_InfoNew.libclass = "";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
m_Status = MODULE_OLD;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
(*QueryModule)( &info );
|
||||||
m_Status = MODULE_NEWER;
|
if ( info == 0 ){
|
||||||
|
status = MODULE_NOINFO;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case AMXX_OK:
|
if ( info->ivers != AMX_INTERFACE_VERSION ) {
|
||||||
break;
|
status = MODULE_OLD;
|
||||||
default:
|
|
||||||
AMXXLOG_Log("[AMXX] Module \"%s\" (version \"%s\") returned an invalid code.", m_Filename.chars(), getVersion());
|
|
||||||
m_Status = MODULE_BADLOAD;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
AttachModule = (ATTACHMOD)DLPROC(module,"AMX_Attach"); // check for attach
|
||||||
// Check for attach
|
if ( AttachModule == 0) {
|
||||||
if (!DLPROC(m_Handle, "AMXX_Attach"))
|
status = MODULE_NOATTACH;
|
||||||
{
|
|
||||||
m_Status = MODULE_NOATTACH;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
info->serial = (long int)this;
|
||||||
|
status = MODULE_QUERY;
|
||||||
// Lastly, check to see if this module is able to load on this game mod
|
|
||||||
CHECKGAME_NEW checkGame_New = (CHECKGAME_NEW)DLPROC(m_Handle, "AMXX_CheckGame");
|
|
||||||
|
|
||||||
if (checkGame_New)
|
|
||||||
{
|
|
||||||
// This is an optional check; do not fail modules that do not have it
|
|
||||||
int ret = checkGame_New(g_mod_name.chars());
|
|
||||||
|
|
||||||
if (ret != AMXX_GAME_OK)
|
|
||||||
{
|
|
||||||
switch (ret)
|
|
||||||
{
|
|
||||||
case AMXX_GAME_BAD:
|
|
||||||
AMXXLOG_Log("[AMXX] Module \"%s\" (version \"%s\") reported that it cannot load on game \"%s\"", m_Filename.chars(), getVersion(), g_mod_name.chars());
|
|
||||||
m_Status = MODULE_BADGAME;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
AMXXLOG_Log("[AMXX] Module \"%s\" (version \"%s\") returned an unknown CheckGame code (value: %d)", m_Filename.chars(), getVersion(), ret);
|
|
||||||
m_Status = MODULE_BADLOAD;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Status = MODULE_QUERY;
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
m_Status = MODULE_NOQUERY;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool CModule::detachModule()
|
bool CModule::detachModule()
|
||||||
{
|
{
|
||||||
if (m_Status != MODULE_LOADED)
|
if ( status != MODULE_LOADED )
|
||||||
return false;
|
return false;
|
||||||
|
DetachModule = (DETACHMOD)DLPROC(module,"AMX_Detach");
|
||||||
RemoveLibraries(this);
|
if (DetachModule) (*DetachModule)();
|
||||||
|
DLFREE(module);
|
||||||
DETACHMOD_NEW detachFunc_New = (DETACHMOD_NEW)DLPROC(m_Handle, "AMXX_Detach");
|
module = 0;
|
||||||
|
natives.clear();
|
||||||
if (detachFunc_New)
|
status = MODULE_NONE;
|
||||||
{
|
|
||||||
g_ModuleCallReason = ModuleCall_Detach;
|
|
||||||
g_CurrentlyCalledModule = this;
|
|
||||||
(*detachFunc_New)();
|
|
||||||
g_CurrentlyCalledModule = NULL;
|
|
||||||
g_ModuleCallReason = ModuleCall_NotCalled;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsMetamod())
|
|
||||||
{
|
|
||||||
UnloadMetamodPlugin(m_Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
DLFREE(m_Handle);
|
|
||||||
clear();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
const char* CModule::getStatus() const {
|
||||||
void CModule::CallPluginsUnloaded()
|
switch(status){
|
||||||
{
|
|
||||||
if (m_Status != MODULE_LOADED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!m_Handle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PLUGINSUNLOADED_NEW func = (PLUGINSUNLOADED_NEW)DLPROC(m_Handle, "AMXX_PluginsUnloaded");
|
|
||||||
|
|
||||||
if (!func)
|
|
||||||
return;
|
|
||||||
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CModule::CallPluginsUnloading()
|
|
||||||
{
|
|
||||||
if (m_Status != MODULE_LOADED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!m_Handle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PLUGINSUNLOADING_NEW func = (PLUGINSUNLOADING_NEW)DLPROC(m_Handle, "AMXX_PluginsUnloading");
|
|
||||||
|
|
||||||
if (!func)
|
|
||||||
return;
|
|
||||||
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CModule::CallPluginsLoaded()
|
|
||||||
{
|
|
||||||
if (m_Status != MODULE_LOADED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!m_Handle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
PLUGINSLOADED_NEW func = (PLUGINSLOADED_NEW)DLPROC(m_Handle, "AMXX_PluginsLoaded");
|
|
||||||
|
|
||||||
if (!func)
|
|
||||||
return;
|
|
||||||
|
|
||||||
func();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* CModule::getStatus() const
|
|
||||||
{
|
|
||||||
switch (m_Status)
|
|
||||||
{
|
|
||||||
case MODULE_NONE: return "error";
|
case MODULE_NONE: return "error";
|
||||||
case MODULE_QUERY: return "pending";
|
case MODULE_QUERY: return "pending";
|
||||||
case MODULE_BADLOAD:return "bad load";
|
case MODULE_BADLOAD:return "bad load";
|
||||||
@ -393,13 +187,6 @@ const char* CModule::getStatus() const
|
|||||||
case MODULE_NOQUERY:return "no query";
|
case MODULE_NOQUERY:return "no query";
|
||||||
case MODULE_NOATTACH:return "no attach";
|
case MODULE_NOATTACH:return "no attach";
|
||||||
case MODULE_OLD:return "old";
|
case MODULE_OLD:return "old";
|
||||||
case MODULE_FUNCNOTPRESENT:
|
|
||||||
case MODULE_NEWER: return "newer";
|
|
||||||
case MODULE_INTERROR: return "internal err";
|
|
||||||
case MODULE_NOT64BIT: return "not 64bit";
|
|
||||||
case MODULE_BADGAME: return "bad game";
|
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,33 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class CModule
|
// class CModule
|
||||||
@ -14,88 +36,49 @@
|
|||||||
#ifndef CMODULE_H
|
#ifndef CMODULE_H
|
||||||
#define CMODULE_H
|
#define CMODULE_H
|
||||||
|
|
||||||
enum MODULE_STATUS
|
enum MODULE_STATUS {
|
||||||
{
|
MODULE_NONE,
|
||||||
MODULE_NONE, // No module loaded
|
MODULE_QUERY,
|
||||||
MODULE_QUERY, // Query failed
|
MODULE_BADLOAD,
|
||||||
MODULE_BADLOAD, // Bad file or the module writer messed something up ;]
|
MODULE_LOADED,
|
||||||
MODULE_LOADED, // Loaded
|
MODULE_NOINFO,
|
||||||
MODULE_NOINFO, // No info
|
MODULE_NOQUERY,
|
||||||
MODULE_NOQUERY, // No query function present
|
MODULE_NOATTACH,
|
||||||
MODULE_NOATTACH, // No attach function present
|
MODULE_OLD
|
||||||
MODULE_OLD, // Old interface
|
|
||||||
MODULE_NEWER, // newer interface
|
|
||||||
MODULE_INTERROR, // Internal error
|
|
||||||
MODULE_FUNCNOTPRESENT, // Function not present
|
|
||||||
MODULE_NOT64BIT, // Not 64 bit compatible
|
|
||||||
MODULE_BADGAME, // Module cannot load on the current game mod
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct amxx_module_info_s
|
class CModule
|
||||||
{
|
{
|
||||||
const char *name;
|
String filename;
|
||||||
const char *author;
|
bool metamod;
|
||||||
const char *version;
|
module_info_s* info;
|
||||||
int reload; // reload on mapchange when nonzero
|
DLHANDLE module;
|
||||||
const char *logtag; //added in version 2
|
MODULE_STATUS status;
|
||||||
const char *library; // added in version 4
|
|
||||||
const char *libclass; // added in version 4
|
|
||||||
};
|
|
||||||
|
|
||||||
#define AMXX_OK 0 /* no error */
|
|
||||||
#define AMXX_IFVERS 1 /* interface version */
|
|
||||||
#define AMXX_PARAM 2 /* Invalid parameter */
|
|
||||||
#define AMXX_FUNC_NOT_PRESENT 3 /* Function not present */
|
|
||||||
|
|
||||||
#define AMXX_GAME_OK 0 /* Module can load on this game. */
|
|
||||||
#define AMXX_GAME_BAD 1 /* Module cannot load on this game. */
|
|
||||||
|
|
||||||
#define AMXX_INTERFACE_VERSION 4
|
|
||||||
|
|
||||||
class CModule : public ke::InlineListNode<CModule>
|
|
||||||
{
|
|
||||||
ke::AString m_Filename; // Filename
|
|
||||||
|
|
||||||
bool m_Metamod; // Using metamod?
|
|
||||||
|
|
||||||
amxx_module_info_s m_InfoNew; // module info (new module interface)
|
|
||||||
DLHANDLE m_Handle; // handle
|
|
||||||
MODULE_STATUS m_Status; // status
|
|
||||||
const char *m_MissingFunc; // missing function; only set on MODULE_FUNCNOTPRESENT status
|
|
||||||
|
|
||||||
void clear(bool clearFilename = true);
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CModule(const char* fname);
|
CModule(const char* fname);
|
||||||
~CModule();
|
~CModule();
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
|
|
||||||
bool attachModule();
|
bool attachModule();
|
||||||
bool queryModule();
|
bool queryModule();
|
||||||
bool detachModule();
|
bool detachModule();
|
||||||
void rewriteNativeLists(AMX_NATIVE_INFO *list);
|
|
||||||
|
|
||||||
bool attachMetamod(const char *mmfile, PLUG_LOADTIME now);
|
|
||||||
|
|
||||||
const char* getStatus() const;
|
const char* getStatus() const;
|
||||||
inline const char* getType() const { return m_Metamod ? "amxx&mm" : "amxx"; }
|
inline const char* getType() const { return metamod ? "amx&mm" : "amx"; }
|
||||||
inline const char* getAuthor() const { return m_InfoNew.author; }
|
inline const char* getAuthor() const { return info ? info->author : "unknown"; }
|
||||||
inline const char* getVersion() const { return m_InfoNew.version; }
|
inline const char* getVersion() const { return info ? info->version : "unknown"; }
|
||||||
inline const char* getName() const { return m_InfoNew.name; }
|
inline const char* getName() const { return info ? info->name : "unknown"; }
|
||||||
inline const amxx_module_info_s* getInfoNew() const { return &m_InfoNew; } // new
|
inline module_info_s* getInfo() const { return info; }
|
||||||
inline int getStatusValue() { return m_Status; }
|
inline int getStatusValue() { return status; }
|
||||||
inline bool isReloadable() { return ((m_Status == MODULE_LOADED) && (m_InfoNew.reload != 0)); }
|
inline bool operator==( void* fname ) { return !strcmp( filename.str() , (char*)fname ); }
|
||||||
inline const char *getMissingFunc() const { return m_MissingFunc; }
|
inline bool isReloadable() { return ( (status==MODULE_LOADED) && (info->type==RELOAD_MODULE)); }
|
||||||
inline const char *getFilename() { return m_Filename.chars(); }
|
CList<AMX_NATIVE_INFO*> natives;
|
||||||
inline bool IsMetamod() { return m_Metamod; }
|
|
||||||
|
|
||||||
void CallPluginsLoaded();
|
|
||||||
void CallPluginsUnloaded();
|
|
||||||
void CallPluginsUnloading();
|
|
||||||
|
|
||||||
ke::Vector<AMX_NATIVE_INFO*> m_Natives;
|
|
||||||
ke::Vector<AMX_NATIVE_INFO*> m_NewNatives; // Natives for new (AMXX, not AMX) plugins only
|
|
||||||
ke::Vector<size_t> m_DestroyableIndexes;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //CMODULE_H
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
Preamble
|
Preamble
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
The licenses for most software are designed to take away your
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
License is intended to guarantee your freedom to share and change free
|
License is intended to guarantee your freedom to share and change free
|
||||||
@ -14,39 +17,48 @@ Foundation's software and to any other program whose authors commit to
|
|||||||
using it. (Some other Free Software Foundation software is covered by
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
the GNU Library General Public License instead.) You can apply it to
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
your programs, too.
|
your programs, too.
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
When we speak of free software, we are referring to freedom, not
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
have the freedom to distribute copies of free software (and charge for
|
have the freedom to distribute copies of free software (and charge for
|
||||||
this service if you wish), that you receive source code or can get it
|
this service if you wish), that you receive source code or can get it
|
||||||
if you want it, that you can change the software or use pieces of it
|
if you want it, that you can change the software or use pieces of it
|
||||||
in new free programs; and that you know you can do these things.
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
To protect your rights, we need to make restrictions that forbid
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
These restrictions translate to certain responsibilities for you if you
|
These restrictions translate to certain responsibilities for you if you
|
||||||
distribute copies of the software, or if you modify it.
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
For example, if you distribute copies of such a program, whether
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
you have. You must make sure that they, too, receive or can get the
|
you have. You must make sure that they, too, receive or can get the
|
||||||
source code. And you must show them these terms so they know their
|
source code. And you must show them these terms so they know their
|
||||||
rights.
|
rights.
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
distribute and/or modify the software.
|
distribute and/or modify the software.
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
Also, for each author's protection and ours, we want to make certain
|
||||||
that everyone understands that there is no warranty for this free
|
that everyone understands that there is no warranty for this free
|
||||||
software. If the software is modified by someone else and passed on, we
|
software. If the software is modified by someone else and passed on, we
|
||||||
want its recipients to know that what they have is not the original, so
|
want its recipients to know that what they have is not the original, so
|
||||||
that any problems introduced by others will not reflect on the original
|
that any problems introduced by others will not reflect on the original
|
||||||
authors' reputations.
|
authors' reputations.
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
Finally, any free program is threatened constantly by software
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
program will individually obtain patent licenses, in effect making the
|
program will individually obtain patent licenses, in effect making the
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
0. This License applies to any program or other work which contains
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
under the terms of this General Public License. The "Program", below,
|
under the terms of this General Public License. The "Program", below,
|
||||||
@ -56,12 +68,14 @@ that is to say, a work containing the Program or a portion of it,
|
|||||||
either verbatim or with modifications and/or translated into another
|
either verbatim or with modifications and/or translated into another
|
||||||
language. (Hereinafter, translation is included without limitation in
|
language. (Hereinafter, translation is included without limitation in
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
Activities other than copying, distribution and modification are not
|
||||||
covered by this License; they are outside its scope. The act of
|
covered by this License; they are outside its scope. The act of
|
||||||
running the Program is not restricted, and the output from the Program
|
running the Program is not restricted, and the output from the Program
|
||||||
is covered only if its contents constitute a work based on the
|
is covered only if its contents constitute a work based on the
|
||||||
Program (independent of having been made by running the Program).
|
Program (independent of having been made by running the Program).
|
||||||
Whether that is true depends on what the Program does.
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
source code as you receive it, in any medium, provided that you
|
source code as you receive it, in any medium, provided that you
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
@ -69,18 +83,23 @@ copyright notice and disclaimer of warranty; keep intact all the
|
|||||||
notices that refer to this License and to the absence of any warranty;
|
notices that refer to this License and to the absence of any warranty;
|
||||||
and give any other recipients of the Program a copy of this License
|
and give any other recipients of the Program a copy of this License
|
||||||
along with the Program.
|
along with the Program.
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
of it, thus forming a work based on the Program, and copy and
|
of it, thus forming a work based on the Program, and copy and
|
||||||
distribute such modifications or work under the terms of Section 1
|
distribute such modifications or work under the terms of Section 1
|
||||||
above, provided that you also meet all of these conditions:
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
a) You must cause the modified files to carry prominent notices
|
||||||
stating that you changed the files and the date of any change.
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
b) You must cause any work that you distribute or publish, that in
|
||||||
whole or in part contains or is derived from the Program or any
|
whole or in part contains or is derived from the Program or any
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
parties under the terms of this License.
|
parties under the terms of this License.
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
c) If the modified program normally reads commands interactively
|
||||||
when run, you must cause it, when started running for such
|
when run, you must cause it, when started running for such
|
||||||
interactive use in the most ordinary way, to print or display an
|
interactive use in the most ordinary way, to print or display an
|
||||||
@ -91,6 +110,7 @@ above, provided that you also meet all of these conditions:
|
|||||||
License. (Exception: if the Program itself is interactive but
|
License. (Exception: if the Program itself is interactive but
|
||||||
does not normally print such an announcement, your work based on
|
does not normally print such an announcement, your work based on
|
||||||
the Program is not required to print an announcement.)
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
These requirements apply to the modified work as a whole. If
|
||||||
identifiable sections of that work are not derived from the Program,
|
identifiable sections of that work are not derived from the Program,
|
||||||
and can be reasonably considered independent and separate works in
|
and can be reasonably considered independent and separate works in
|
||||||
@ -100,31 +120,38 @@ distribute the same sections as part of a whole which is a work based
|
|||||||
on the Program, the distribution of the whole must be on the terms of
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
this License, whose permissions for other licensees extend to the
|
this License, whose permissions for other licensees extend to the
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
exercise the right to control the distribution of derivative or
|
exercise the right to control the distribution of derivative or
|
||||||
collective works based on the Program.
|
collective works based on the Program.
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
In addition, mere aggregation of another work not based on the Program
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
a storage or distribution medium does not bring the other work under
|
a storage or distribution medium does not bring the other work under
|
||||||
the scope of this License.
|
the scope of this License.
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
under Section 2) in object code or executable form under the terms of
|
under Section 2) in object code or executable form under the terms of
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
source code, which must be distributed under the terms of Sections
|
source code, which must be distributed under the terms of Sections
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
b) Accompany it with a written offer, valid for at least three
|
||||||
years, to give any third party, for a charge no more than your
|
years, to give any third party, for a charge no more than your
|
||||||
cost of physically performing source distribution, a complete
|
cost of physically performing source distribution, a complete
|
||||||
machine-readable copy of the corresponding source code, to be
|
machine-readable copy of the corresponding source code, to be
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
customarily used for software interchange; or,
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
c) Accompany it with the information you received as to the offer
|
||||||
to distribute corresponding source code. (This alternative is
|
to distribute corresponding source code. (This alternative is
|
||||||
allowed only for noncommercial distribution and only if you
|
allowed only for noncommercial distribution and only if you
|
||||||
received the program in object code or executable form with such
|
received the program in object code or executable form with such
|
||||||
an offer, in accord with Subsection b above.)
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
The source code for a work means the preferred form of the work for
|
||||||
making modifications to it. For an executable work, complete source
|
making modifications to it. For an executable work, complete source
|
||||||
code means all the source code for all modules it contains, plus any
|
code means all the source code for all modules it contains, plus any
|
||||||
@ -135,11 +162,13 @@ anything that is normally distributed (in either source or binary
|
|||||||
form) with the major components (compiler, kernel, and so on) of the
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
operating system on which the executable runs, unless that component
|
operating system on which the executable runs, unless that component
|
||||||
itself accompanies the executable.
|
itself accompanies the executable.
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
If distribution of executable or object code is made by offering
|
||||||
access to copy from a designated place, then offering equivalent
|
access to copy from a designated place, then offering equivalent
|
||||||
access to copy the source code from the same place counts as
|
access to copy the source code from the same place counts as
|
||||||
distribution of the source code, even though third parties are not
|
distribution of the source code, even though third parties are not
|
||||||
compelled to copy the source along with the object code.
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
except as expressly provided under this License. Any attempt
|
except as expressly provided under this License. Any attempt
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
@ -147,6 +176,7 @@ void, and will automatically terminate your rights under this License.
|
|||||||
However, parties who have received copies, or rights, from you under
|
However, parties who have received copies, or rights, from you under
|
||||||
this License will not have their licenses terminated so long as such
|
this License will not have their licenses terminated so long as such
|
||||||
parties remain in full compliance.
|
parties remain in full compliance.
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
5. You are not required to accept this License, since you have not
|
||||||
signed it. However, nothing else grants you permission to modify or
|
signed it. However, nothing else grants you permission to modify or
|
||||||
distribute the Program or its derivative works. These actions are
|
distribute the Program or its derivative works. These actions are
|
||||||
@ -155,6 +185,7 @@ modifying or distributing the Program (or any work based on the
|
|||||||
Program), you indicate your acceptance of this License to do so, and
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
all its terms and conditions for copying, distributing or modifying
|
all its terms and conditions for copying, distributing or modifying
|
||||||
the Program or works based on it.
|
the Program or works based on it.
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
Program), the recipient automatically receives a license from the
|
Program), the recipient automatically receives a license from the
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
@ -162,6 +193,7 @@ these terms and conditions. You may not impose any further
|
|||||||
restrictions on the recipients' exercise of the rights granted herein.
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
You are not responsible for enforcing compliance by third parties to
|
You are not responsible for enforcing compliance by third parties to
|
||||||
this License.
|
this License.
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
infringement or for any other reason (not limited to patent issues),
|
infringement or for any other reason (not limited to patent issues),
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
@ -174,10 +206,12 @@ license would not permit royalty-free redistribution of the Program by
|
|||||||
all those who receive copies directly or indirectly through you, then
|
all those who receive copies directly or indirectly through you, then
|
||||||
the only way you could satisfy both it and this License would be to
|
the only way you could satisfy both it and this License would be to
|
||||||
refrain entirely from distribution of the Program.
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
If any portion of this section is held invalid or unenforceable under
|
||||||
any particular circumstance, the balance of the section is intended to
|
any particular circumstance, the balance of the section is intended to
|
||||||
apply and the section as a whole is intended to apply in other
|
apply and the section as a whole is intended to apply in other
|
||||||
circumstances.
|
circumstances.
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
It is not the purpose of this section to induce you to infringe any
|
||||||
patents or other property right claims or to contest validity of any
|
patents or other property right claims or to contest validity of any
|
||||||
such claims; this section has the sole purpose of protecting the
|
such claims; this section has the sole purpose of protecting the
|
||||||
@ -188,8 +222,10 @@ through that system in reliance on consistent application of that
|
|||||||
system; it is up to the author/donor to decide if he or she is willing
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
to distribute software through any other system and a licensee cannot
|
to distribute software through any other system and a licensee cannot
|
||||||
impose that choice.
|
impose that choice.
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
This section is intended to make thoroughly clear what is believed to
|
||||||
be a consequence of the rest of this License.
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
original copyright holder who places the Program under this License
|
original copyright holder who places the Program under this License
|
||||||
@ -197,10 +233,12 @@ may add an explicit geographical distribution limitation excluding
|
|||||||
those countries, so that distribution is permitted only in or among
|
those countries, so that distribution is permitted only in or among
|
||||||
countries not thus excluded. In such case, this License incorporates
|
countries not thus excluded. In such case, this License incorporates
|
||||||
the limitation as if written in the body of this License.
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
of the General Public License from time to time. Such new versions will
|
of the General Public License from time to time. Such new versions will
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
address new problems or concerns.
|
address new problems or concerns.
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
Each version is given a distinguishing version number. If the Program
|
||||||
specifies a version number of this License which applies to it and "any
|
specifies a version number of this License which applies to it and "any
|
||||||
later version", you have the option of following the terms and conditions
|
later version", you have the option of following the terms and conditions
|
||||||
@ -208,6 +246,7 @@ either of that version or of any later version published by the Free
|
|||||||
Software Foundation. If the Program does not specify a version number of
|
Software Foundation. If the Program does not specify a version number of
|
||||||
this License, you may choose any version ever published by the Free Software
|
this License, you may choose any version ever published by the Free Software
|
||||||
Foundation.
|
Foundation.
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
programs whose distribution conditions are different, write to the author
|
programs whose distribution conditions are different, write to the author
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
@ -215,7 +254,9 @@ Software Foundation, write to the Free Software Foundation; we sometimes
|
|||||||
make exceptions for this. Our decision will be guided by the two goals
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
of preserving the free status of all derivatives of our free software and
|
of preserving the free status of all derivatives of our free software and
|
||||||
of promoting the sharing and reuse of software generally.
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
NO WARRANTY
|
NO WARRANTY
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
@ -225,6 +266,7 @@ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
REPAIR OR CORRECTION.
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
@ -234,46 +276,63 @@ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
If you develop a new program, and you want it to be of the greatest
|
||||||
possible use to the public, the best way to achieve this is to make it
|
possible use to the public, the best way to achieve this is to make it
|
||||||
free software which everyone can redistribute and change under these terms.
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
To do so, attach the following notices to the program. It is safest
|
||||||
to attach them to the start of each source file to most effectively
|
to attach them to the start of each source file to most effectively
|
||||||
convey the exclusion of warranty; and each file should have at least
|
convey the exclusion of warranty; and each file should have at least
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
Copyright (C) <year> <name of author>
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
(at your option) any later version.
|
(at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
If the program is interactive, make it output a short notice like this
|
||||||
when it starts in an interactive mode:
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
parts of the General Public License. Of course, the commands you use may
|
parts of the General Public License. Of course, the commands you use may
|
||||||
be called something other than `show w' and `show c'; they could even be
|
be called something other than `show w' and `show c'; they could even be
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
You should also get your employer (if you work as a programmer) or your
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
necessary. Here is a sample; alter the names:
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
<signature of Ty Coon>, 1 April 1989
|
||||||
Ty Coon, President of Vice
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
This General Public License does not permit incorporating your program into
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
consider it more useful to permit linking proprietary applications with the
|
consider it more useful to permit linking proprietary applications with the
|
@ -1,760 +1,202 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include <extdll.h>
|
||||||
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
#include "CPlugin.h"
|
#include "CPlugin.h"
|
||||||
#include "CForward.h"
|
#include "CForward.h"
|
||||||
#include "amx.h"
|
#include "CFile.h"
|
||||||
#include "natives.h"
|
|
||||||
#include "debugger.h"
|
|
||||||
#include "libraries.h"
|
|
||||||
#include <amxmodx_version.h>
|
|
||||||
|
|
||||||
extern const char *no_function;
|
CPluginMngr::CPlugin* CPluginMngr::loadPlugin(const char* path, const char* name, char* error) {
|
||||||
|
|
||||||
CPluginMngr::CPlugin* CPluginMngr::loadPlugin(const char* path, const char* name, char* error, size_t maxLength, int debug)
|
|
||||||
{
|
|
||||||
CPlugin** a = &head;
|
CPlugin** a = &head;
|
||||||
|
while( *a ) a = &(*a)->next;
|
||||||
while (*a)
|
*a = new CPlugin( pCounter++ ,path,name,error);
|
||||||
a = &(*a)->next;
|
return *error ? 0 : *a;
|
||||||
|
|
||||||
*a = new CPlugin(pCounter++, path, name, error, maxLength, debug);
|
|
||||||
|
|
||||||
return (*a);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginMngr::unloadPlugin(CPlugin** a)
|
void CPluginMngr::unloadPlugin( CPlugin** a ) {
|
||||||
{
|
|
||||||
CPlugin* next = (*a)->next;
|
CPlugin* next = (*a)->next;
|
||||||
delete *a;
|
delete *a;
|
||||||
*a = next;
|
*a = next;
|
||||||
--pCounter;
|
--pCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginMngr::Finalize()
|
int CPluginMngr::loadPluginsFromFile( const char* filename )
|
||||||
{
|
{
|
||||||
if (m_Finalized)
|
File fp( build_pathname("%s",filename) , "r" );
|
||||||
return;
|
|
||||||
|
|
||||||
pNatives = BuildNativeTable();
|
|
||||||
CPlugin *a = head;
|
|
||||||
|
|
||||||
while (a)
|
|
||||||
{
|
|
||||||
if (a->getStatusCode() == ps_running)
|
|
||||||
{
|
|
||||||
amx_Register(a->getAMX(), pNatives, -1);
|
|
||||||
a->Finalize();
|
|
||||||
}
|
|
||||||
a = a->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Finalized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CPluginMngr::loadPluginsFromFile(const char* filename, bool warn)
|
|
||||||
{
|
|
||||||
char file[PLATFORM_MAX_PATH];
|
|
||||||
FILE *fp = fopen(build_pathname_r(file, sizeof(file), "%s", filename), "rt");
|
|
||||||
|
|
||||||
if ( !fp )
|
if ( !fp )
|
||||||
{
|
{
|
||||||
if (warn)
|
UTIL_Log( "[AMXX] Plugins list not found (file \"%s\")",filename);
|
||||||
{
|
|
||||||
AMXXLOG_Error("[AMXX] Plugins list not found (file \"%s\")", filename);
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find now folder
|
// Find now folder
|
||||||
char pluginName[256], error[256], debug[256];
|
char pluginName[256], line[256], error[256];
|
||||||
int debugFlag = 0;
|
const char pluginsDir[] = "addons/amxx/plugins"; // hardcoded; :TODO: make it localinfo
|
||||||
const char *pluginsDir = get_localinfo("amxx_pluginsdir", "addons/amxmodx/plugins");
|
|
||||||
|
|
||||||
char line[512];
|
|
||||||
|
|
||||||
List<ke::AString *>::iterator block_iter;
|
while ( fp.getline(line , 255 ) )
|
||||||
|
|
||||||
while (!feof(fp))
|
|
||||||
{
|
{
|
||||||
pluginName[0] = '\0';
|
*pluginName = 0;
|
||||||
|
sscanf(line,"%s",pluginName);
|
||||||
|
if (!isalnum(*pluginName)) continue;
|
||||||
|
|
||||||
debug[0] = '\0';
|
CPlugin* plugin = loadPlugin( pluginsDir , pluginName , error );
|
||||||
debugFlag = 0;
|
|
||||||
|
|
||||||
line[0] = '\0';
|
if ( plugin != 0 ) // load_amxscript fills it with info in case of error
|
||||||
fgets(line, sizeof(line), fp);
|
|
||||||
|
|
||||||
/** quick hack */
|
|
||||||
char *ptr = line;
|
|
||||||
while (*ptr)
|
|
||||||
{
|
{
|
||||||
if (*ptr == ';')
|
AMX* amx = plugin->getAMX();
|
||||||
{
|
int iFunc;
|
||||||
*ptr = '\0';
|
|
||||||
} else {
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sscanf(line, "%s %s", pluginName, debug);
|
|
||||||
|
|
||||||
if (!isalnum(*pluginName))
|
if(amx_FindPublic(amx, "client_command" , &iFunc) == AMX_ERR_NONE)
|
||||||
{
|
g_forwards.registerForward( plugin , iFunc , FF_ClientCommand);
|
||||||
continue;
|
if(amx_FindPublic(amx, "client_connect" , &iFunc) == AMX_ERR_NONE)
|
||||||
}
|
g_forwards.registerForward( plugin , iFunc , FF_ClientConnect);
|
||||||
|
if(amx_FindPublic(amx, "client_disconnect" , &iFunc) == AMX_ERR_NONE)
|
||||||
if (isalnum(*debug) && !strcmp(debug, "debug"))
|
g_forwards.registerForward( plugin , iFunc , FF_ClientDisconnect);
|
||||||
{
|
if(amx_FindPublic(amx, "client_infochanged" , &iFunc) == AMX_ERR_NONE)
|
||||||
debugFlag = 1;
|
g_forwards.registerForward( plugin , iFunc , FF_ClientInfoChanged);
|
||||||
}
|
if(amx_FindPublic(amx, "client_putinserver" , &iFunc) == AMX_ERR_NONE)
|
||||||
|
g_forwards.registerForward( plugin , iFunc , FF_ClientPutInServer);
|
||||||
bool skip = false;
|
if(amx_FindPublic(amx, "plugin_init" , &iFunc) == AMX_ERR_NONE)
|
||||||
for (block_iter = m_BlockList.begin();
|
g_forwards.registerForward( plugin , iFunc , FF_PluginInit);
|
||||||
block_iter != m_BlockList.end();
|
if(amx_FindPublic(amx, "plugin_cfg" , &iFunc) == AMX_ERR_NONE)
|
||||||
block_iter++)
|
g_forwards.registerForward( plugin , iFunc , FF_PluginCfg);
|
||||||
{
|
if(amx_FindPublic(amx, "plugin_precache" , &iFunc) == AMX_ERR_NONE)
|
||||||
if ((*block_iter)->compare(pluginName) == 0)
|
g_forwards.registerForward( plugin , iFunc , FF_PluginPrecache);
|
||||||
{
|
if(amx_FindPublic(amx, "plugin_log" , &iFunc) == AMX_ERR_NONE)
|
||||||
skip = true;
|
g_forwards.registerForward( plugin , iFunc , FF_PluginLog);
|
||||||
break;
|
if(amx_FindPublic(amx, "plugin_end" , &iFunc) == AMX_ERR_NONE)
|
||||||
}
|
g_forwards.registerForward( plugin , iFunc , FF_PluginEnd);
|
||||||
}
|
if(amx_FindPublic(amx, "inconsistent_file" , &iFunc) == AMX_ERR_NONE)
|
||||||
|
g_forwards.registerForward( plugin , iFunc , FF_InconsistentFile);
|
||||||
if (skip || !strcmp(debug, "disabled"))
|
if(amx_FindPublic(amx, "client_authorized" , &iFunc) == AMX_ERR_NONE)
|
||||||
{
|
g_forwards.registerForward( plugin , iFunc , FF_ClientAuthorized);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (findPlugin(pluginName) != NULL)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPlugin* plugin = loadPlugin(pluginsDir, pluginName, error, sizeof(error), debugFlag);
|
|
||||||
|
|
||||||
if (plugin->getStatusCode() == ps_bad_load)
|
|
||||||
{
|
|
||||||
char errorMsg[255];
|
|
||||||
sprintf(errorMsg, "%s (plugin \"%s\")", error, pluginName);
|
|
||||||
plugin->setError(errorMsg);
|
|
||||||
AMXXLOG_Error("[AMXX] %s", plugin->getError());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cell addr;
|
UTIL_Log("[AMXX] %s (plugin \"%s\")", error, pluginName );
|
||||||
if (amx_FindPubVar(plugin->getAMX(), "MaxClients", &addr) != AMX_ERR_NOTFOUND)
|
|
||||||
{
|
|
||||||
*get_amxaddr(plugin->getAMX(), addr) = gpGlobals->maxClients;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amx_FindPubVar(plugin->getAMX(), "NULL_STRING", &addr) != AMX_ERR_NOTFOUND)
|
|
||||||
{
|
|
||||||
plugin->m_pNullStringOfs = get_amxaddr(plugin->getAMX(), addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amx_FindPubVar(plugin->getAMX(), "NULL_VECTOR", &addr) != AMX_ERR_NOTFOUND)
|
|
||||||
{
|
|
||||||
plugin->m_pNullVectorOfs = get_amxaddr(plugin->getAMX(), addr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return pCounter;
|
return pCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginMngr::clear()
|
void CPluginMngr::clear() {
|
||||||
{
|
|
||||||
CPlugin**a = &head;
|
CPlugin**a = &head;
|
||||||
|
|
||||||
while ( *a )
|
while ( *a )
|
||||||
unloadPlugin(a);
|
unloadPlugin(a);
|
||||||
|
|
||||||
m_Finalized = false;
|
|
||||||
|
|
||||||
if (pNatives)
|
|
||||||
{
|
|
||||||
delete [] pNatives;
|
|
||||||
pNatives = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ke::AString *>::iterator iter = m_BlockList.begin();
|
CPluginMngr::CPlugin* CPluginMngr::findPluginFast(AMX *amx)
|
||||||
while (iter != m_BlockList.end())
|
|
||||||
{
|
{
|
||||||
delete (*iter);
|
return (CPlugin*)(amx->userdata[3]);
|
||||||
iter = m_BlockList.erase(iter);
|
/*CPlugin*a = head;
|
||||||
}
|
|
||||||
m_BlockList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
CPluginMngr::CPlugin* CPluginMngr::findPlugin(AMX *amx)
|
|
||||||
{
|
|
||||||
CPlugin*a = head;
|
|
||||||
|
|
||||||
while ( a && &a->amx != amx )
|
while ( a && &a->amx != amx )
|
||||||
a=a->next;
|
a=a->next;
|
||||||
|
return a;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
CPluginMngr::CPlugin* CPluginMngr::findPlugin(AMX *amx) {
|
||||||
|
CPlugin*a = head;
|
||||||
|
while ( a && &a->amx != amx )
|
||||||
|
a=a->next;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPluginMngr::CPlugin* CPluginMngr::findPlugin(int index)
|
CPluginMngr::CPlugin* CPluginMngr::findPlugin(int index){
|
||||||
{
|
|
||||||
CPlugin*a = head;
|
CPlugin*a = head;
|
||||||
|
|
||||||
while ( a && index--)
|
while ( a && index--)
|
||||||
a=a->next;
|
a=a->next;
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPluginMngr::CPlugin* CPluginMngr::findPlugin(const char* name)
|
CPluginMngr::CPlugin* CPluginMngr::findPlugin(const char* name) {
|
||||||
{
|
if (!name) return 0;
|
||||||
if (!name)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int len = strlen(name);
|
int len = strlen(name);
|
||||||
|
if (!len) return 0;
|
||||||
if (!len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CPlugin*a = head;
|
CPlugin*a = head;
|
||||||
|
while( a && strncmp(a->name.str(), name,len) )
|
||||||
while (a && strncmp(a->name.chars(), name, len))
|
|
||||||
a=a->next;
|
a=a->next;
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginMngr::CPlugin::AddToFailCounter(unsigned int i)
|
const char* CPluginMngr::CPlugin::getStatus() const {
|
||||||
{
|
switch(status){
|
||||||
failcounter += i;
|
case ps_running: return "running";
|
||||||
if ((failcounter >= 3)
|
|
||||||
&& (status ))
|
|
||||||
{
|
|
||||||
errorMsg = "This plugin is non-GPL which violates AMX Mod X's license.";
|
|
||||||
status = ps_bad_load;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* CPluginMngr::CPlugin::getStatus() const
|
|
||||||
{
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case ps_running:
|
|
||||||
{
|
|
||||||
if (m_Debug)
|
|
||||||
{
|
|
||||||
return "debug";
|
|
||||||
} else {
|
|
||||||
return "running";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ps_paused: return "paused";
|
case ps_paused: return "paused";
|
||||||
case ps_bad_load: return "bad load";
|
case ps_bad_load: return "bad load";
|
||||||
case ps_stopped: return "stopped";
|
case ps_stopped: return "stopped";
|
||||||
case ps_locked: return "locked";
|
case ps_locked: return "locked";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "error";
|
return "error";
|
||||||
}
|
}
|
||||||
|
|
||||||
CPluginMngr::CPlugin::CPlugin(int i, const char* p, const char* n, char* e, size_t m, int d) : name(n), title(n), m_pNullStringOfs(nullptr), m_pNullVectorOfs(nullptr)
|
CPluginMngr::CPlugin::CPlugin(int i, const char* p,const char* n, char* e) : name(n), title(n) {
|
||||||
{
|
|
||||||
const char* unk = "unknown";
|
const char* unk = "unknown";
|
||||||
|
title.set(unk);
|
||||||
failcounter = 0;
|
author.set(unk);
|
||||||
title = unk;
|
version.set(unk);
|
||||||
author = unk;
|
char* path = build_pathname("%s/%s",p,n);
|
||||||
version = unk;
|
|
||||||
|
|
||||||
char file[PLATFORM_MAX_PATH];
|
|
||||||
char* path = build_pathname_r(file, sizeof(file), "%s/%s", p, n);
|
|
||||||
code = 0;
|
code = 0;
|
||||||
memset(&amx, 0, sizeof(AMX));
|
int err = load_amxscript(&amx,&code,path,e );
|
||||||
int err = load_amxscript_ex(&amx, &code, path, e, m, d);
|
if ( err == AMX_ERR_NONE ) status = ps_running;
|
||||||
|
else status = ps_bad_load;
|
||||||
if (err == AMX_ERR_NONE)
|
amx.userdata[3] = this;
|
||||||
{
|
|
||||||
status = ps_running;
|
|
||||||
} else {
|
|
||||||
status = ps_bad_load;
|
|
||||||
}
|
|
||||||
|
|
||||||
amx.userdata[UD_FINDPLUGIN] = this;
|
|
||||||
paused_fun = 0;
|
paused_fun = 0;
|
||||||
next = 0;
|
next = 0;
|
||||||
id = i;
|
id = i;
|
||||||
|
|
||||||
if (status == ps_running)
|
|
||||||
{
|
|
||||||
m_PauseFwd = registerSPForwardByName(&amx, "plugin_pause", FP_DONE);
|
|
||||||
m_UnpauseFwd = registerSPForwardByName(&amx, "plugin_unpause", FP_DONE);
|
|
||||||
|
|
||||||
if (amx.flags & AMX_FLAG_DEBUG)
|
|
||||||
{
|
|
||||||
m_Debug = true;
|
|
||||||
} else {
|
|
||||||
m_Debug = false;
|
|
||||||
}
|
}
|
||||||
}
|
CPluginMngr::CPlugin::~CPlugin( ){
|
||||||
}
|
|
||||||
|
|
||||||
CPluginMngr::CPlugin::~CPlugin()
|
|
||||||
{
|
|
||||||
unload_amxscript( &amx, &code );
|
unload_amxscript( &amx, &code );
|
||||||
}
|
}
|
||||||
|
|
||||||
int AMXAPI native_handler(AMX *amx, int index)
|
void CPluginMngr::CPlugin::pauseFunction( int id ) {
|
||||||
{
|
if (isValid()){
|
||||||
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
|
paused_fun |= (1<<id);
|
||||||
|
g_commands.clearBufforedInfo();
|
||||||
char name[sNAMEMAX + 1];
|
|
||||||
amx_GetNative(amx, index, name);
|
|
||||||
|
|
||||||
return pHandler->HandleNative(name, index, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL invalid_native(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
//A script has accidentally called an invalid native! give them a
|
|
||||||
// first chance to block the resulting error.
|
|
||||||
|
|
||||||
Handler *pHandler = (Handler *)amx->userdata[UD_HANDLER];
|
|
||||||
|
|
||||||
//this should never happen
|
|
||||||
if (!pHandler)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_INVNATIVE, "Invalid native attempt");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//this should never happen because this native won't be called
|
|
||||||
// if the plugin isn't filtering.
|
|
||||||
if (!pHandler->IsNativeFiltering())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_INVNATIVE, "Invalid native attempt");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char name[sNAMEMAX + 1];
|
|
||||||
int native = (int)(_INT_PTR)(amx->usertags[UT_NATIVE]);
|
|
||||||
int err = amx_GetNative(amx, native, name);
|
|
||||||
|
|
||||||
if (err != AMX_ERR_NONE)
|
|
||||||
name[0] = '\0';
|
|
||||||
|
|
||||||
//1 - because we're trapping usage
|
|
||||||
if (!pHandler->HandleNative(name, native, 1))
|
|
||||||
{
|
|
||||||
amx->usertags[UT_NATIVE] = (void *)native;
|
|
||||||
LogError(amx, AMX_ERR_INVNATIVE, NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Someday maybe allow native filters to write their own return value?
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPluginMngr::CPlugin::Finalize()
|
|
||||||
{
|
|
||||||
char buffer[128];
|
|
||||||
int old_status = status;
|
|
||||||
|
|
||||||
if (CheckModules(&amx, buffer))
|
|
||||||
{
|
|
||||||
if (amx_Register(&amx, core_Natives, -1) != AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
Handler *pHandler = (Handler *)amx.userdata[UD_HANDLER];
|
|
||||||
int res = 0;
|
|
||||||
|
|
||||||
if (pHandler->IsNativeFiltering())
|
|
||||||
res = amx_CheckNatives(&amx, native_handler);
|
|
||||||
|
|
||||||
if (!res)
|
|
||||||
{
|
|
||||||
status = ps_bad_load;
|
|
||||||
sprintf(buffer, "Plugin uses an unknown function (name \"%s\") - check your modules.ini.", no_function);
|
|
||||||
errorMsg = buffer;
|
|
||||||
amx.error = AMX_ERR_NOTFOUND;
|
|
||||||
} else {
|
|
||||||
amx_RegisterToAny(&amx, invalid_native);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
status = ps_bad_load;
|
|
||||||
errorMsg = buffer;
|
|
||||||
amx.error = AMX_ERR_NOTFOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old_status != status)
|
|
||||||
{
|
|
||||||
AMXXLOG_Log("[AMXX] Plugin \"%s\" failed to load: %s", name.chars(), errorMsg.chars());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginMngr::CPlugin::pauseFunction(int id)
|
void CPluginMngr::CPlugin::unpauseFunction( int id ) {
|
||||||
{
|
if (isValid()) {
|
||||||
|
paused_fun &= ~(1<<id);
|
||||||
|
g_commands.clearBufforedInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPluginMngr::CPlugin::unpauseFunction(int id)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
void CPluginMngr::CPlugin::setStatus( int a ) {
|
||||||
void CPluginMngr::CPlugin::setStatus(int a)
|
|
||||||
{
|
|
||||||
status = a;
|
status = a;
|
||||||
g_commands.clearBufforedInfo(); // ugly way
|
g_commands.clearBufforedInfo(); // ugly way
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause a plugin
|
|
||||||
void CPluginMngr::CPlugin::pausePlugin()
|
|
||||||
{
|
|
||||||
if (isValid())
|
|
||||||
{
|
|
||||||
// call plugin_pause if provided
|
|
||||||
if (m_PauseFwd != -1)
|
|
||||||
executeForwards(m_PauseFwd);
|
|
||||||
|
|
||||||
setStatus(ps_paused);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unpause a plugin
|
|
||||||
void CPluginMngr::CPlugin::unpausePlugin()
|
|
||||||
{
|
|
||||||
if (isValid() && (getStatusCode() != ps_stopped))
|
|
||||||
{
|
|
||||||
// set status first so the function will be marked executable
|
|
||||||
setStatus(ps_running);
|
|
||||||
|
|
||||||
// call plugin_unpause if provided
|
|
||||||
if (m_UnpauseFwd != -1)
|
|
||||||
{
|
|
||||||
executeForwards(m_UnpauseFwd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPluginMngr::CPlugin::AddConfig(bool create, const char *name, const char *folder)
|
|
||||||
{
|
|
||||||
// Do a check for duplicates to prevent double-execution
|
|
||||||
for (size_t i = 0; i < m_configs.length(); ++i)
|
|
||||||
{
|
|
||||||
AutoConfig *config = m_configs[i];
|
|
||||||
|
|
||||||
if (config->autocfg.compare(name) == 0 && config->folder.compare(folder) == 0)
|
|
||||||
{
|
|
||||||
if (!config->create)
|
|
||||||
{
|
|
||||||
config->create = create;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto c = new AutoConfig;
|
|
||||||
|
|
||||||
c->autocfg = name;
|
|
||||||
c->folder = folder;
|
|
||||||
c->create = create;
|
|
||||||
|
|
||||||
m_configs.append(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CPluginMngr::CPlugin::GetConfigCount()
|
|
||||||
{
|
|
||||||
return m_configs.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoConfig *CPluginMngr::CPlugin::GetConfig(size_t i)
|
|
||||||
{
|
|
||||||
if (i >= GetConfigCount())
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_configs[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char *CPluginMngr::ReadIntoOrFromCache(const char *file, size_t &bufsize)
|
|
||||||
{
|
|
||||||
List<plcache_entry *>::iterator iter;
|
|
||||||
plcache_entry *pl;
|
|
||||||
|
|
||||||
for (iter=m_plcache.begin(); iter!=m_plcache.end(); iter++)
|
|
||||||
{
|
|
||||||
pl = (*iter);
|
|
||||||
if (pl->path.compare(file) == 0)
|
|
||||||
{
|
|
||||||
bufsize = pl->bufsize;
|
|
||||||
return pl->buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pl = new plcache_entry;
|
|
||||||
|
|
||||||
pl->file = new CAmxxReader(file, sizeof(cell));
|
|
||||||
pl->buffer = NULL;
|
|
||||||
if (pl->file->GetStatus() != CAmxxReader::Err_None)
|
|
||||||
{
|
|
||||||
delete pl->file;
|
|
||||||
delete pl;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pl->bufsize = pl->file->GetBufferSize();
|
|
||||||
if (pl->bufsize)
|
|
||||||
{
|
|
||||||
pl->buffer = new char[pl->bufsize];
|
|
||||||
pl->file->GetSection(pl->buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pl->buffer || pl->file->GetStatus() != CAmxxReader::Err_None)
|
|
||||||
{
|
|
||||||
delete [] pl->buffer;
|
|
||||||
delete pl->file;
|
|
||||||
delete pl;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pl->path = file;
|
|
||||||
|
|
||||||
bufsize = pl->bufsize;
|
|
||||||
|
|
||||||
m_plcache.push_back(pl);
|
|
||||||
|
|
||||||
return pl->buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPluginMngr::InvalidateCache()
|
|
||||||
{
|
|
||||||
List<plcache_entry *>::iterator iter;
|
|
||||||
plcache_entry *pl;
|
|
||||||
|
|
||||||
for (iter=m_plcache.begin(); iter!=m_plcache.end(); iter++)
|
|
||||||
{
|
|
||||||
pl = (*iter);
|
|
||||||
delete [] pl->buffer;
|
|
||||||
delete pl->file;
|
|
||||||
delete pl;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_plcache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPluginMngr::InvalidateFileInCache(const char *file, bool freebuf)
|
|
||||||
{
|
|
||||||
List<plcache_entry *>::iterator iter;
|
|
||||||
plcache_entry *pl;
|
|
||||||
|
|
||||||
for (iter=m_plcache.begin(); iter!=m_plcache.end(); iter++)
|
|
||||||
{
|
|
||||||
pl = (*iter);
|
|
||||||
if (pl->path.compare(file) == 0)
|
|
||||||
{
|
|
||||||
if (freebuf)
|
|
||||||
delete [] pl->buffer;
|
|
||||||
delete pl->file;
|
|
||||||
delete pl;
|
|
||||||
m_plcache.erase(iter);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPluginMngr::CacheAndLoadModules(const char *plugin)
|
|
||||||
{
|
|
||||||
size_t progsize;
|
|
||||||
char *prog = ReadIntoOrFromCache(plugin, progsize);
|
|
||||||
|
|
||||||
if (!prog)
|
|
||||||
return;
|
|
||||||
|
|
||||||
AMX_HEADER hdr;
|
|
||||||
memcpy(&hdr, prog, sizeof(AMX_HEADER));
|
|
||||||
|
|
||||||
uint16_t magic = hdr.magic;
|
|
||||||
amx_Align16(&magic);
|
|
||||||
|
|
||||||
if (magic != AMX_MAGIC)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hdr.file_version < MIN_FILE_VERSION ||
|
|
||||||
hdr.file_version > CUR_FILE_VERSION)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((hdr.defsize != sizeof(AMX_FUNCSTUB)) &&
|
|
||||||
(hdr.defsize != sizeof(AMX_FUNCSTUBNT)))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
amx_Align32((uint32_t*)&hdr.nametable);
|
|
||||||
uint16_t *namelength=(uint16_t*)((unsigned char*)prog + (unsigned)hdr.nametable);
|
|
||||||
amx_Align16(namelength);
|
|
||||||
if (*namelength>sNAMEMAX)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hdr.stp <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AMX amx;
|
|
||||||
memset(&amx, 0, sizeof(AMX));
|
|
||||||
amx.base = (unsigned char *)prog;
|
|
||||||
|
|
||||||
int num;
|
|
||||||
char name[sNAMEMAX+1];
|
|
||||||
|
|
||||||
num = amx_GetLibraries(&amx);
|
|
||||||
for (int i=0; i<num; i++)
|
|
||||||
{
|
|
||||||
amx_GetLibrary(&amx, i, name, sNAMEMAX);
|
|
||||||
if (stricmp(name, "Float")==0)
|
|
||||||
continue;
|
|
||||||
//awful backwards compat hack
|
|
||||||
if (stricmp(name, "socket")==0)
|
|
||||||
strcpy(name, "sockets");
|
|
||||||
//we don't want to report failed modules here...
|
|
||||||
LoadModule(name, PT_ANYTIME, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
cell tag_id;
|
|
||||||
amx_NumTags(&amx, &num);
|
|
||||||
|
|
||||||
ke::Vector<LibDecoder *> expects;
|
|
||||||
ke::Vector<LibDecoder *> defaults;
|
|
||||||
CStack<LibDecoder *> delstack;
|
|
||||||
for (int i=0; i<num; i++)
|
|
||||||
{
|
|
||||||
amx_GetTag(&amx, i, name, &tag_id);
|
|
||||||
if (name[0] == '?')
|
|
||||||
{
|
|
||||||
LibDecoder *dc = new LibDecoder;
|
|
||||||
delstack.push(dc);
|
|
||||||
if (DecodeLibCmdString(name, dc))
|
|
||||||
{
|
|
||||||
if (dc->cmd == LibCmd_ForceLib)
|
|
||||||
{
|
|
||||||
RunLibCommand(dc);
|
|
||||||
} else if ( (dc->cmd == LibCmd_ExpectClass) ||
|
|
||||||
(dc->cmd == LibCmd_ExpectLib) )
|
|
||||||
{
|
|
||||||
expects.append(dc);
|
|
||||||
} else if (dc->cmd == LibCmd_DefaultLib) {
|
|
||||||
defaults.append(dc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i=0; i<expects.length(); i++)
|
|
||||||
{
|
|
||||||
RunLibCommand(expects[i]);
|
|
||||||
}
|
|
||||||
for (size_t i=0; i<defaults.length(); i++)
|
|
||||||
{
|
|
||||||
RunLibCommand(defaults[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
expects.clear();
|
|
||||||
defaults.clear();
|
|
||||||
|
|
||||||
while (!delstack.empty())
|
|
||||||
{
|
|
||||||
delete delstack.front();
|
|
||||||
delstack.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPluginMngr::CALMFromFile(const char *file)
|
|
||||||
{
|
|
||||||
char filename[PLATFORM_MAX_PATH];
|
|
||||||
FILE *fp = fopen(build_pathname_r(filename, sizeof(filename), "%s", file), "rt");
|
|
||||||
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find now folder
|
|
||||||
char pluginName[256];
|
|
||||||
char line[256];
|
|
||||||
char rline[256];
|
|
||||||
|
|
||||||
while (!feof(fp))
|
|
||||||
{
|
|
||||||
fgets(line, sizeof(line)-1, fp);
|
|
||||||
if (line[0] == ';' || line[0] == '\n' || line[0] == '\0')
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** quick hack */
|
|
||||||
char *ptr = line;
|
|
||||||
while (*ptr)
|
|
||||||
{
|
|
||||||
if (*ptr == ';')
|
|
||||||
{
|
|
||||||
*ptr = '\0';
|
|
||||||
} else {
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strncopy(rline, line, sizeof(rline));
|
|
||||||
UTIL_TrimLeft(rline);
|
|
||||||
UTIL_TrimRight(rline);
|
|
||||||
|
|
||||||
pluginName[0] = '\0';
|
|
||||||
sscanf(rline, "%s", pluginName);
|
|
||||||
|
|
||||||
/* HACK: see if there's a 'disabled' coming up
|
|
||||||
* new block for scopying flexibility
|
|
||||||
*/
|
|
||||||
if (1)
|
|
||||||
{
|
|
||||||
const char *_ptr = rline + strlen(pluginName);
|
|
||||||
while (*_ptr != '\0' && isspace(*_ptr))
|
|
||||||
{
|
|
||||||
_ptr++;
|
|
||||||
}
|
|
||||||
if ((*_ptr != '\0') && !strcmp(_ptr, "disabled"))
|
|
||||||
{
|
|
||||||
ke::AString *pString = new ke::AString(pluginName);
|
|
||||||
m_BlockList.push_back(pString);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isalnum(*pluginName))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
build_pathname_r(filename, sizeof(filename), "%s/%s", get_localinfo("amxx_pluginsdir", "addons/amxmodx/plugins"), pluginName);
|
|
||||||
|
|
||||||
CacheAndLoadModules(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
@ -1,45 +1,53 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef PLUGIN_H
|
#ifndef PLUGIN_H
|
||||||
#define PLUGIN_H
|
#define PLUGIN_H
|
||||||
|
|
||||||
#include "sh_list.h"
|
|
||||||
#include "amx.h"
|
|
||||||
#include "amxxfile.h"
|
|
||||||
#include <amtl/am-string.h>
|
|
||||||
#include <amtl/am-vector.h>
|
|
||||||
#include <amtl/am-autoptr.h>
|
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class CPluginMngr
|
// class CPluginMngr
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
enum
|
enum {
|
||||||
{
|
ps_bad_load,
|
||||||
ps_bad_load, //Load failed
|
ps_error,
|
||||||
ps_error, //Erroneous state
|
ps_paused,
|
||||||
ps_locked, //UNUSED
|
ps_running,
|
||||||
ps_paused, //Plugin is temporarily paused
|
ps_stopped,
|
||||||
ps_stopped, //Plugin is ... more temporarily paused
|
ps_locked
|
||||||
ps_running, //Plugin is running
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AutoConfig
|
|
||||||
{
|
|
||||||
ke::AString autocfg;
|
|
||||||
ke::AString folder;
|
|
||||||
bool create;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPluginMngr
|
class CPluginMngr
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class iterator;
|
class iterator;
|
||||||
@ -51,92 +59,62 @@ public:
|
|||||||
|
|
||||||
AMX amx;
|
AMX amx;
|
||||||
void* code;
|
void* code;
|
||||||
|
String name;
|
||||||
ke::AString name;
|
String version;
|
||||||
ke::AString version;
|
String title;
|
||||||
ke::AString title;
|
String author;
|
||||||
ke::AString author;
|
|
||||||
ke::AString errorMsg;
|
|
||||||
|
|
||||||
unsigned int failcounter;
|
|
||||||
int m_PauseFwd;
|
|
||||||
int m_UnpauseFwd;
|
|
||||||
int paused_fun;
|
int paused_fun;
|
||||||
int status;
|
int status;
|
||||||
CPlugin* next;
|
CPlugin* next;
|
||||||
int id;
|
int id;
|
||||||
|
CPlugin(int i , const char* p,const char* n, char* e);
|
||||||
CPlugin(int i, const char* p, const char* n, char* e, size_t m, int d);
|
|
||||||
~CPlugin( );
|
~CPlugin( );
|
||||||
|
|
||||||
bool m_Debug;
|
|
||||||
cell* m_pNullStringOfs;
|
|
||||||
cell* m_pNullVectorOfs;
|
|
||||||
ke::Vector<ke::AutoPtr<AutoConfig>> m_configs;
|
|
||||||
public:
|
public:
|
||||||
inline const char* getName() { return name.chars();}
|
|
||||||
inline const char* getVersion() { return version.chars();}
|
inline const char* getName() const { return name.str();}
|
||||||
inline const char* getTitle() { return title.chars();}
|
inline const char* getVersion() const { return version.str();}
|
||||||
inline const char* getAuthor() { return author.chars();}
|
inline const char* getTitle() const { return title.str();}
|
||||||
inline const char* getError() { return errorMsg.chars();}
|
inline const char* getAuthor()const { return author.str();}
|
||||||
inline int getStatusCode() { return status; }
|
|
||||||
inline int getId() const { return id; }
|
inline int getId() const { return id; }
|
||||||
inline AMX* getAMX() { return &amx; }
|
inline AMX* getAMX() { return &amx; }
|
||||||
inline const AMX* getAMX() const { return &amx; }
|
inline void setTitle( const char* n ) { title.set(n); }
|
||||||
inline void setTitle(const char* n) { title = n; }
|
inline void setAuthor( const char* n ) { author.set(n); }
|
||||||
inline void setAuthor(const char* n) { author =n; }
|
inline void setVersion( const char* n ) { version.set(n); }
|
||||||
inline void setVersion(const char* n) { version = n; }
|
inline bool isValid() const { return ((status != ps_bad_load) && (status != ps_locked)); }
|
||||||
inline void setError(const char* n) { errorMsg = n; }
|
|
||||||
inline bool isValid() const { return (status >= ps_paused); }
|
|
||||||
inline bool isPaused() const { return ( (status == ps_paused) || (status == ps_stopped)); }
|
inline bool isPaused() const { return ( (status == ps_paused) || (status == ps_stopped)); }
|
||||||
inline bool isStopped() const { return (status == ps_stopped); }
|
inline bool isFunctionPaused( int id ) const { return (paused_fun & (1<<id)) ? true : false; }
|
||||||
inline bool isExecutable(int id) const { return (isValid() && !isPaused()); }
|
inline bool isExecutable(int id) const { return (isValid() && !isPaused() && !isFunctionPaused(id)); }
|
||||||
|
inline void pausePlugin( ) { if ( isValid() ) setStatus(ps_paused); }
|
||||||
void Finalize();
|
inline void unpausePlugin( ) { if ( isValid() ) setStatus(ps_running); }
|
||||||
void AddToFailCounter(unsigned int i);
|
|
||||||
void pausePlugin();
|
|
||||||
void unpausePlugin();
|
|
||||||
void pauseFunction( int id );
|
void pauseFunction( int id );
|
||||||
void unpauseFunction( int id );
|
void unpauseFunction( int id );
|
||||||
void setStatus( int a );
|
void setStatus( int a );
|
||||||
|
|
||||||
const char* getStatus() const;
|
const char* getStatus() const;
|
||||||
inline bool isDebug() const { return m_Debug; }
|
|
||||||
inline cell* getNullStringOfs() const { return m_pNullStringOfs; }
|
|
||||||
inline cell* getNullVectorOfs() const { return m_pNullVectorOfs; }
|
|
||||||
public:
|
|
||||||
void AddConfig(bool create, const char *name, const char *folder);
|
|
||||||
size_t GetConfigCount();
|
|
||||||
AutoConfig *GetConfig(size_t index);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CPlugin *head;
|
CPlugin *head;
|
||||||
int pCounter;
|
int pCounter;
|
||||||
public:
|
|
||||||
CPluginMngr() { head = 0; pCounter = 0; pNatives = NULL; m_Finalized=false;}
|
|
||||||
~CPluginMngr() { clear(); InvalidateCache(); }
|
|
||||||
|
|
||||||
bool m_Finalized;
|
|
||||||
AMX_NATIVE_INFO *pNatives;
|
public:
|
||||||
|
CPluginMngr() { head = 0; pCounter = 0; }
|
||||||
|
~CPluginMngr() { clear(); }
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
|
|
||||||
CPlugin* loadPlugin(const char* path, const char* name, char* error, size_t maxLength, int debug);
|
CPlugin* loadPlugin(const char* path, const char* name, char* error);
|
||||||
void unloadPlugin( CPlugin** a );
|
void unloadPlugin( CPlugin** a );
|
||||||
int loadPluginsFromFile(const char* filename, bool warn=true);
|
int loadPluginsFromFile( const char* filename );
|
||||||
|
CPlugin* findPluginFast(AMX *amx);
|
||||||
inline CPlugin* findPluginFast(AMX *amx) { return (CPlugin*)(amx->userdata[UD_FINDPLUGIN]); }
|
|
||||||
CPlugin* findPlugin(AMX *amx);
|
CPlugin* findPlugin(AMX *amx);
|
||||||
CPlugin* findPlugin(int index);
|
CPlugin* findPlugin(int index);
|
||||||
CPlugin* findPlugin(const char* name);
|
CPlugin* findPlugin(const char* name);
|
||||||
|
|
||||||
inline int getPluginsNum() const { return pCounter; }
|
inline int getPluginsNum() const { return pCounter; }
|
||||||
void Finalize();
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
class iterator
|
class iterator {
|
||||||
{
|
|
||||||
CPlugin *a;
|
CPlugin *a;
|
||||||
public:
|
public:
|
||||||
iterator(CPlugin*aa) : a(aa) {}
|
iterator(CPlugin*aa) : a(aa) {}
|
||||||
@ -146,25 +124,10 @@ public:
|
|||||||
operator bool () const { return a ? true : false; }
|
operator bool () const { return a ? true : false; }
|
||||||
CPlugin& operator*() { return *a; }
|
CPlugin& operator*() { return *a; }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline iterator begin() const { return iterator(head); }
|
inline iterator begin() const { return iterator(head); }
|
||||||
inline iterator end() const { return iterator(0); }
|
inline iterator end() const { return iterator(0); }
|
||||||
public:
|
|
||||||
struct plcache_entry
|
|
||||||
{
|
|
||||||
CAmxxReader *file;
|
|
||||||
size_t bufsize;
|
|
||||||
char *buffer;
|
|
||||||
ke::AString path;
|
|
||||||
};
|
|
||||||
char *ReadIntoOrFromCache(const char *file, size_t &bufsize);
|
|
||||||
void InvalidateCache();
|
|
||||||
void InvalidateFileInCache(const char *file, bool freebuf);
|
|
||||||
void CacheAndLoadModules(const char *plugin);
|
|
||||||
void CALMFromFile(const char *file);
|
|
||||||
private:
|
|
||||||
List<plcache_entry *> m_plcache;
|
|
||||||
List<ke::AString *> m_BlockList;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //PLUGIN_H
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
69
amxmodx/CString.cpp
Executable file
69
amxmodx/CString.cpp
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
/* AMX Mod X
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
* originally developed by OLO
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CString.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "CFile.h"
|
||||||
|
|
||||||
|
String::String()
|
||||||
|
{
|
||||||
|
len = 0;
|
||||||
|
napis = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
String::String( const char* n )
|
||||||
|
{
|
||||||
|
napis = 0;
|
||||||
|
set(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
String::~String()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::set( const char* n )
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
if ( n != 0 ){
|
||||||
|
len = strlen( n );
|
||||||
|
napis = new char[ len + 1 ];
|
||||||
|
if ( napis ) strcpy( napis , n );
|
||||||
|
else len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::clear() {
|
||||||
|
delete[] napis;
|
||||||
|
napis = 0;
|
||||||
|
len = 0;
|
||||||
|
}
|
||||||
|
|
58
amxmodx/CString.h
Executable file
58
amxmodx/CString.h
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
/* AMX Mod X
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
* originally developed by OLO
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STRING_CUSTOM_H
|
||||||
|
#define STRING_CUSTOM_H
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// class String
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
|
class String
|
||||||
|
{
|
||||||
|
char* napis;
|
||||||
|
short int len;
|
||||||
|
|
||||||
|
public:
|
||||||
|
String();
|
||||||
|
String( const char* n );
|
||||||
|
~String();
|
||||||
|
void set( const char* n );
|
||||||
|
inline bool empty() const { return (len == 0); }
|
||||||
|
inline const char* str() const { return napis ? napis : "(null)"; }
|
||||||
|
inline short int size() const { return len; }
|
||||||
|
void clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,286 +1,192 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include <extdll.h>
|
||||||
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
#include "CTask.h"
|
#include "CTask.h"
|
||||||
|
|
||||||
/*********************** CTask ***********************/
|
|
||||||
|
|
||||||
void CTaskMngr::CTask::set(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, cell iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat, float fCurrentTime)
|
CTaskMngr::CTask::CTask( CPluginMngr::CPlugin* p, int f, int flags,
|
||||||
|
int i, float base, float exec, int parlen ,
|
||||||
|
const cell* par, int r){
|
||||||
|
plugin = p;
|
||||||
|
func = f;
|
||||||
|
id = i;
|
||||||
|
next = 0;
|
||||||
|
prev = 0;
|
||||||
|
param_len = 0;
|
||||||
|
param = 0;
|
||||||
|
base_time = base;
|
||||||
|
exec_time = exec;
|
||||||
|
repeat = (flags & 1) ? r : 0;
|
||||||
|
loop = (flags & 2) ? true : false;
|
||||||
|
afterstart = (flags & 4) ? true : false;
|
||||||
|
beforeend = (flags & 8) ? true : false;
|
||||||
|
|
||||||
|
if ( parlen )
|
||||||
{
|
{
|
||||||
clear();
|
param = new cell[ parlen + 1 ];
|
||||||
m_bFree = false;
|
|
||||||
|
|
||||||
m_pPlugin = pPlugin;
|
if ( param ){
|
||||||
m_iFunc = iFunc;
|
param_len = parlen + 1;
|
||||||
m_iId = iId;
|
memcpy( param , par , sizeof( cell ) * parlen );
|
||||||
m_fBase = fBase;
|
param[ parlen ] = 0;
|
||||||
m_bInExecute = false;
|
|
||||||
|
|
||||||
if (iFlags & 2)
|
|
||||||
{
|
|
||||||
m_bLoop = true;
|
|
||||||
m_iRepeat = -1;
|
|
||||||
}
|
|
||||||
else if (iFlags & 1)
|
|
||||||
{
|
|
||||||
m_bLoop = true;
|
|
||||||
m_iRepeat = iRepeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_bAfterStart = (iFlags & 4) ? true : false;
|
|
||||||
m_bBeforeEnd = (iFlags & 8) ? true : false;
|
|
||||||
|
|
||||||
m_fNextExecTime = fCurrentTime + m_fBase;
|
|
||||||
|
|
||||||
if (iParamsLen)
|
|
||||||
{
|
|
||||||
m_iParamLen = iParamsLen + 1;
|
|
||||||
m_pParams = new cell[m_iParamLen];
|
|
||||||
memcpy(m_pParams, pParams, sizeof(cell)*iParamsLen);
|
|
||||||
m_pParams[iParamsLen] = 0;
|
|
||||||
} else {
|
|
||||||
m_iParamLen = 0;
|
|
||||||
m_pParams = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTaskMngr::CTask::clear()
|
|
||||||
{
|
|
||||||
m_bFree = true;
|
|
||||||
|
|
||||||
if (m_iFunc >= 0)
|
|
||||||
{
|
|
||||||
unregisterSPForward(m_iFunc);
|
|
||||||
m_iFunc = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_pParams)
|
|
||||||
{
|
|
||||||
delete [] m_pParams;
|
|
||||||
m_pParams = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_pPlugin = NULL;
|
|
||||||
m_iId = 0;
|
|
||||||
m_fBase = 0.0f;
|
|
||||||
|
|
||||||
m_iRepeat = 0;
|
|
||||||
m_bLoop = false;
|
|
||||||
m_bAfterStart = false;
|
|
||||||
m_bBeforeEnd = false;
|
|
||||||
|
|
||||||
m_fNextExecTime = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CTaskMngr::CTask::isFree() const
|
|
||||||
{
|
|
||||||
return m_bFree;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTaskMngr::CTask::changeBase(float fNewBase)
|
|
||||||
{
|
|
||||||
m_fBase = fNewBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTaskMngr::CTask::resetNextExecTime(float fCurrentTime)
|
|
||||||
{
|
|
||||||
// If we're here while we're executing we would add m_fBase twice
|
|
||||||
if (!m_bInExecute)
|
|
||||||
m_fNextExecTime = fCurrentTime + m_fBase;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTaskMngr::CTask::executeIfRequired(float fCurrentTime, float fTimeLimit, float fTimeLeft)
|
|
||||||
{
|
|
||||||
bool execute = false;
|
|
||||||
bool done = false;
|
|
||||||
|
|
||||||
if (m_bAfterStart)
|
|
||||||
{
|
|
||||||
if (fCurrentTime - fTimeLeft + 1.0f >= m_fBase)
|
|
||||||
execute = true;
|
|
||||||
}
|
|
||||||
else if (m_bBeforeEnd)
|
|
||||||
{
|
|
||||||
if (fTimeLimit != 0.0f && (fTimeLeft + fTimeLimit * 60.0f) - fCurrentTime - 1.0f <= m_fBase)
|
|
||||||
execute = true;
|
|
||||||
}
|
|
||||||
else if (m_fNextExecTime <= fCurrentTime)
|
|
||||||
{
|
|
||||||
execute = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (execute)
|
|
||||||
{
|
|
||||||
//only bother calling if we have something to call
|
|
||||||
if (!(m_bLoop && !m_iRepeat))
|
|
||||||
{
|
|
||||||
m_bInExecute = true;
|
|
||||||
if (m_iParamLen) // call with parameters
|
|
||||||
{
|
|
||||||
cell arr = prepareCellArray(m_pParams, m_iParamLen);
|
|
||||||
executeForwards(m_iFunc, arr, m_iId);
|
|
||||||
} else {
|
|
||||||
executeForwards(m_iFunc, m_iId);
|
|
||||||
}
|
|
||||||
m_bInExecute = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFree())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// set new exec time OR remove the task if needed
|
|
||||||
if (m_bLoop)
|
|
||||||
{
|
|
||||||
if (m_iRepeat != -1 && --m_iRepeat <= 0)
|
|
||||||
done = true;
|
|
||||||
} else {
|
|
||||||
done = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (done)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
} else {
|
|
||||||
m_fNextExecTime += m_fBase;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CTaskMngr::CTask::CTask()
|
CTaskMngr::CTask* CTaskMngr::getFirstValidTask(CTask* h){
|
||||||
{
|
CTask* a = h;
|
||||||
m_bFree = true;
|
while( a ) {
|
||||||
|
if ( a->isRemoved() ) {
|
||||||
m_pPlugin = NULL;
|
CTask* b = a->next;
|
||||||
m_iFunc = -1;
|
unlink( a );
|
||||||
m_iId = 0;
|
delete a;
|
||||||
m_fBase = 0.0f;
|
a = b;
|
||||||
|
|
||||||
m_iRepeat = 0;
|
|
||||||
m_bLoop = false;
|
|
||||||
m_bAfterStart = false;
|
|
||||||
m_bBeforeEnd = false;
|
|
||||||
m_bInExecute = false;
|
|
||||||
|
|
||||||
m_fNextExecTime = 0.0f;
|
|
||||||
|
|
||||||
m_iParamLen = 0;
|
|
||||||
m_pParams = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CTaskMngr::CTask::~CTask()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*********************** CTaskMngr ***********************/
|
|
||||||
|
|
||||||
CTaskMngr::CTaskMngr()
|
|
||||||
{
|
|
||||||
m_pTmr_CurrentTime = NULL;
|
|
||||||
m_pTmr_TimeLimit = NULL;
|
|
||||||
m_pTmr_TimeLeft = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
CTaskMngr::~CTaskMngr()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTaskMngr::registerTimers(float *pCurrentTime, float *pTimeLimit, float *pTimeLeft)
|
|
||||||
{
|
|
||||||
m_pTmr_CurrentTime = pCurrentTime;
|
|
||||||
m_pTmr_TimeLimit = pTimeLimit;
|
|
||||||
m_pTmr_TimeLeft = pTimeLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTaskMngr::registerTask(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, cell iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat)
|
|
||||||
{
|
|
||||||
// first, search for free tasks
|
|
||||||
for (auto &task : m_Tasks)
|
|
||||||
{
|
|
||||||
if (task->isFree() && !task->inExecute())
|
|
||||||
{
|
|
||||||
// found: reuse it
|
|
||||||
task->set(pPlugin, iFunc, iFlags, iId, fBase, iParamsLen, pParams, iRepeat, *m_pTmr_CurrentTime);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// not found: make a new one
|
|
||||||
auto task = ke::AutoPtr<CTask>(new CTask);
|
|
||||||
|
|
||||||
if (!task)
|
|
||||||
return;
|
|
||||||
|
|
||||||
task->set(pPlugin, iFunc, iFlags, iId, fBase, iParamsLen, pParams, iRepeat, *m_pTmr_CurrentTime);
|
|
||||||
m_Tasks.append(ke::Move(task));
|
|
||||||
}
|
|
||||||
|
|
||||||
int CTaskMngr::removeTasks(int iId, AMX *pAmx)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (auto &task : m_Tasks)
|
|
||||||
{
|
|
||||||
if (task->match(iId, pAmx))
|
|
||||||
{
|
|
||||||
task->clear();
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CTaskMngr::changeTasks(int iId, AMX *pAmx, float fNewBase)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (auto &task : m_Tasks)
|
|
||||||
{
|
|
||||||
if (task->match(iId, pAmx))
|
|
||||||
{
|
|
||||||
task->changeBase(fNewBase);
|
|
||||||
task->resetNextExecTime(*m_pTmr_CurrentTime);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CTaskMngr::taskExists(int iId, AMX *pAmx)
|
|
||||||
{
|
|
||||||
for (auto &task : m_Tasks)
|
|
||||||
{
|
|
||||||
if (task->match(iId, pAmx))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CTaskMngr::startFrame()
|
|
||||||
{
|
|
||||||
auto lastSize = m_Tasks.length();
|
|
||||||
for(auto i = 0u; i < lastSize; i++)
|
|
||||||
{
|
|
||||||
auto &task = m_Tasks[i];
|
|
||||||
|
|
||||||
if (task->isFree())
|
|
||||||
continue;
|
continue;
|
||||||
task->executeIfRequired(*m_pTmr_CurrentTime, *m_pTmr_TimeLimit, *m_pTmr_TimeLeft);
|
}
|
||||||
|
else if ( a->afterstart ){
|
||||||
|
if ( *m_timer - *m_timeleft + 1 < a->base_time ) {
|
||||||
|
a = a->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( a->beforeend ){
|
||||||
|
if ( *m_timelimit == 0 ){
|
||||||
|
a = a->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( (*m_timeleft + *m_timelimit * 60.0) - *m_timer - 1 >
|
||||||
|
a->base_time ){
|
||||||
|
a = a->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( a->exec_time > *m_timer ) {
|
||||||
|
a = a->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CTaskMngr::CTask* CTaskMngr::getNextTask(CTask* a) {
|
||||||
|
if ( a->isRemoved() )
|
||||||
|
return a->next;
|
||||||
|
if ( a->loop || a->isToReply() ){
|
||||||
|
a->exec_time = *m_timer + a->base_time;
|
||||||
|
return a->next;
|
||||||
|
}
|
||||||
|
a->setToRemove();
|
||||||
|
return a->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CTaskMngr::CTaskMngr() {
|
||||||
|
head = 0;
|
||||||
|
tail = 0;
|
||||||
|
m_timer = 0;
|
||||||
|
m_timelimit = 0;
|
||||||
|
m_timeleft = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CTaskMngr::~CTaskMngr() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTaskMngr::clear() {
|
||||||
|
while ( head ) {
|
||||||
|
tail = head->next;
|
||||||
|
delete head;
|
||||||
|
head = tail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTaskMngr::clear()
|
void CTaskMngr::registerTimers( float* timer , float* timelimit, float* timeleft ) {
|
||||||
{
|
m_timer = timer;
|
||||||
m_Tasks.clear();
|
m_timelimit = timelimit;
|
||||||
|
m_timeleft = timeleft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CTaskMngr::registerTask( CPluginMngr::CPlugin* plugin, int func,
|
||||||
|
int flags, int i, float base, float exec,
|
||||||
|
int parlen , const cell* par, int repeat ){
|
||||||
|
|
||||||
|
CTask* a = new CTask(plugin,func,flags,i,base,exec,parlen,par,repeat );
|
||||||
|
|
||||||
|
if ( a == 0 ) return;
|
||||||
|
|
||||||
|
if ( tail )
|
||||||
|
{
|
||||||
|
tail->next = a;
|
||||||
|
a->prev = tail;
|
||||||
|
tail = a;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
head = a;
|
||||||
|
tail = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CTaskMngr::CTask* CTaskMngr::findTask( int id , AMX* amx )
|
||||||
|
{
|
||||||
|
for (CTask* a = head; a ; a = a->next)
|
||||||
|
{
|
||||||
|
if ( !a->isRemoved() && (a->getTaskId() == id) && (!amx ||
|
||||||
|
(a->getPlugin()->getAMX() == amx)) )
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CTaskMngr::unlink(CTask* a){
|
||||||
|
if ( a->prev ) a->prev->next = a->next;
|
||||||
|
else head = a->next;
|
||||||
|
if ( a->next ) a->next->prev = a->prev;
|
||||||
|
else tail = a->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CTaskMngr::removeTasks( int id , AMX* amx )
|
||||||
|
{
|
||||||
|
CTask* a;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while ( (a = findTask(id, amx )) != 0 ) {
|
||||||
|
a->setToRemove();
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
163
amxmodx/CTask.h
163
amxmodx/CTask.h
@ -1,85 +1,128 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef CTASK_H
|
#ifndef CTASK_H
|
||||||
#define CTASK_H
|
#define CTASK_H
|
||||||
|
|
||||||
|
// *****************************************************
|
||||||
|
// class CTaskMngr
|
||||||
|
// *****************************************************
|
||||||
|
|
||||||
class CTaskMngr
|
class CTaskMngr
|
||||||
{
|
{
|
||||||
private:
|
public:
|
||||||
/*** class CTask ***/
|
|
||||||
|
class iterator;
|
||||||
|
|
||||||
class CTask
|
class CTask
|
||||||
{
|
{
|
||||||
// task settings
|
|
||||||
|
|
||||||
CPluginMngr::CPlugin *m_pPlugin;
|
friend class iterator;
|
||||||
cell m_iId;
|
friend class CTaskMngr;
|
||||||
int m_iFunc;
|
|
||||||
int m_iRepeat;
|
|
||||||
|
|
||||||
bool m_bInExecute;
|
CPluginMngr::CPlugin* plugin;
|
||||||
bool m_bLoop;
|
int id;
|
||||||
bool m_bAfterStart;
|
int func;
|
||||||
bool m_bBeforeEnd;
|
int repeat;
|
||||||
float m_fBase; // for normal tasks, stores the interval, for the others, stores the amount of time before start / after end
|
bool loop;
|
||||||
int m_iParamLen;
|
bool afterstart;
|
||||||
|
bool beforeend;
|
||||||
|
float base_time;
|
||||||
|
float exec_time;
|
||||||
|
int param_len;
|
||||||
|
cell* param;
|
||||||
|
CTask* next;
|
||||||
|
CTask* prev;
|
||||||
|
inline void setToRemove() { exec_time = -1.0f; }
|
||||||
|
inline bool isToReply() { return (repeat-- > 0); }
|
||||||
|
inline bool isRemoved() { return (exec_time == -1.0f); }
|
||||||
|
CTask( CPluginMngr::CPlugin* p, int f, int flags, int i,
|
||||||
|
float base, float exec, int parlen , const cell* par, int r );
|
||||||
|
~CTask() { if ( param_len ) delete[] param; }
|
||||||
|
|
||||||
cell *m_pParams;
|
|
||||||
bool m_bFree;
|
|
||||||
|
|
||||||
// execution
|
|
||||||
float m_fNextExecTime;
|
|
||||||
public:
|
public:
|
||||||
void set(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, cell iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat, float fCurrentTime);
|
|
||||||
void clear();
|
|
||||||
bool isFree() const;
|
|
||||||
|
|
||||||
inline CPluginMngr::CPlugin *getPlugin() const { return m_pPlugin; }
|
inline int getParamLen() { return param_len; }
|
||||||
inline AMX *getAMX() const { return m_pPlugin->getAMX(); }
|
inline int getTaskId() { return id; }
|
||||||
inline int getTaskId() const { return m_iId; }
|
inline int getFunction() { return func; }
|
||||||
|
cell* getParam() { return param; }
|
||||||
void executeIfRequired(float fCurrentTime, float fTimeLimit, float fTimeLeft); // also removes the task if needed
|
CPluginMngr::CPlugin* getPlugin() { return plugin; }
|
||||||
|
|
||||||
void changeBase(float fNewBase);
|
|
||||||
void resetNextExecTime(float fCurrentTime);
|
|
||||||
inline bool inExecute() const { return m_bInExecute; }
|
|
||||||
|
|
||||||
bool shouldRepeat();
|
|
||||||
|
|
||||||
inline bool match(int id, AMX *amx)
|
|
||||||
{
|
|
||||||
return (!m_bFree) && (amx ? getAMX() == amx : true) && (m_iId == id);
|
|
||||||
}
|
|
||||||
|
|
||||||
CTask();
|
|
||||||
~CTask();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*** CTaskMngr priv members ***/
|
|
||||||
ke::Vector<ke::AutoPtr<CTask>> m_Tasks;
|
|
||||||
|
|
||||||
float *m_pTmr_CurrentTime;
|
|
||||||
float *m_pTmr_TimeLimit;
|
private:
|
||||||
float *m_pTmr_TimeLeft;
|
|
||||||
|
friend class iterator;
|
||||||
|
CTask *head;
|
||||||
|
CTask *tail;
|
||||||
|
float* m_timer;
|
||||||
|
float* m_timelimit;
|
||||||
|
float* m_timeleft;
|
||||||
|
CTask* getFirstValidTask(CTask* a);
|
||||||
|
CTask* getNextTask(CTask* a);
|
||||||
|
CTask* findTask( int id , AMX* amx );
|
||||||
|
void unlink(CTask* a);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CTaskMngr();
|
CTaskMngr();
|
||||||
~CTaskMngr();
|
~CTaskMngr();
|
||||||
|
|
||||||
void registerTimers(float *pCurrentTime, float *pTimeLimit, float *pTimeLeft); // The timers will always point to the right value
|
// Interface
|
||||||
void registerTask(CPluginMngr::CPlugin *pPlugin, int iFunc, int iFlags, cell iId, float fBase, int iParamsLen, const cell *pParams, int iRepeat);
|
|
||||||
|
|
||||||
int removeTasks(int iId, AMX *pAmx); // remove all tasks that match the id and amx
|
|
||||||
int changeTasks(int iId, AMX *pAmx, float fNewBase); // change all tasks that match the id and amx
|
|
||||||
bool taskExists(int iId, AMX *pAmx);
|
|
||||||
|
|
||||||
void startFrame();
|
void registerTimers( float* timer , float* timelimit, float* timeleft );
|
||||||
|
void registerTask( CPluginMngr::CPlugin* plugin, int func, int flags, int i, float base, float exec, int parlen , const cell* par, int repeat );
|
||||||
|
inline int taskExists( int id ,AMX* amx) { return findTask(id,amx ) ? 1 : 0; }
|
||||||
|
int removeTasks( int id , AMX* amx );
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
class iterator {
|
||||||
|
CTaskMngr* b;
|
||||||
|
CTask* a;
|
||||||
|
public:
|
||||||
|
iterator(CTask*aa,CTaskMngr* bb) : a(aa), b(bb) {}
|
||||||
|
iterator& operator++() {
|
||||||
|
a = b->getNextTask( a );
|
||||||
|
a = b->getFirstValidTask( a );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
CTask& operator*() { return *a; }
|
||||||
|
operator bool ( ) const { return a ? true : false; }
|
||||||
|
};
|
||||||
|
inline iterator begin() { return iterator(getFirstValidTask(head),this); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //CTASK_H
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,89 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*
|
|
||||||
* Version: $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
|
|
||||||
#define _INCLUDE_SOURCEMOD_TEXTPARSERS_H_
|
|
||||||
|
|
||||||
#include <ITextParsers.h>
|
|
||||||
#include <amtl/am-vector.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param void * IN: Stream pointer
|
|
||||||
* @param char * IN/OUT: Stream buffer
|
|
||||||
* @param size_t IN: Maximum size of buffer
|
|
||||||
* @param unsigned int * OUT: Number of bytes read (0 = end of stream)
|
|
||||||
* @return True on success, false on failure
|
|
||||||
*/
|
|
||||||
typedef bool(*STREAMREADER)(void *, char *, size_t, unsigned int *);
|
|
||||||
|
|
||||||
class TextParsers : public ITextParsers
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TextParsers();
|
|
||||||
public:
|
|
||||||
bool ParseFile_INI(const char *file,
|
|
||||||
ITextListener_INI *ini_listener,
|
|
||||||
unsigned int *line,
|
|
||||||
unsigned int *col,
|
|
||||||
bool inline_comment);
|
|
||||||
|
|
||||||
SMCError ParseFile_SMC(const char *file,
|
|
||||||
ITextListener_SMC *smc_listener,
|
|
||||||
SMCStates *states);
|
|
||||||
|
|
||||||
SMCError ParseSMCFile(const char *file,
|
|
||||||
ITextListener_SMC *smc_listener,
|
|
||||||
SMCStates *states,
|
|
||||||
char *buffer,
|
|
||||||
size_t maxsize);
|
|
||||||
|
|
||||||
SMCError ParseSMCStream(const char *stream,
|
|
||||||
size_t length,
|
|
||||||
ITextListener_SMC *smc_listener,
|
|
||||||
SMCStates *states,
|
|
||||||
char *buffer,
|
|
||||||
size_t maxsize);
|
|
||||||
|
|
||||||
unsigned int GetUTF8CharBytes(const char *stream);
|
|
||||||
|
|
||||||
const char *GetSMCErrorString(SMCError err);
|
|
||||||
bool IsWhitespace(const char *stream);
|
|
||||||
private:
|
|
||||||
SMCError ParseStream_SMC(void *stream,
|
|
||||||
STREAMREADER srdr,
|
|
||||||
ITextListener_SMC *smc,
|
|
||||||
SMCStates *states);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern TextParsers g_TextParser;
|
|
||||||
|
|
||||||
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_H_
|
|
||||||
|
|
@ -1,23 +1,43 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CVault.h"
|
||||||
|
#include "CFile.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "CVault.h"
|
|
||||||
#include "CFileSystem.h"
|
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class Vault
|
// class Vault
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
|
|
||||||
bool Vault::exists( const char* k )
|
bool Vault::exists( const char* k )
|
||||||
{
|
{
|
||||||
if ( *k == 0 ) return false;
|
if ( *k == 0 ) return false;
|
||||||
@ -39,15 +59,15 @@ void Vault::put(const char* k, const char* v)
|
|||||||
|
|
||||||
if ( *a )
|
if ( *a )
|
||||||
{
|
{
|
||||||
(*a)->value = v;
|
(*a)->value.set(v);
|
||||||
(*a)->number = atoi( v );
|
(*a)->number = atoi( v );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*a = new Obj( k , v );
|
*a = new Obj( k , v );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vault::Obj::Obj(const char* k, const char* v): key(k), value(v), next(0)
|
Vault::Obj::Obj( const char* k, const char* v): key(k) , value(v) , next(0) {
|
||||||
{
|
|
||||||
number = atoi(v);
|
number = atoi(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +77,7 @@ Vault::Obj** Vault::find(const char* n)
|
|||||||
|
|
||||||
while( *a )
|
while( *a )
|
||||||
{
|
{
|
||||||
if (strcmp((*a)->key.chars(), n) == 0)
|
if ( strcmp((*a)->key.str(), n) == 0 )
|
||||||
return a;
|
return a;
|
||||||
|
|
||||||
a = &(*a)->next;
|
a = &(*a)->next;
|
||||||
@ -86,7 +106,7 @@ const char* Vault::get(const char* n)
|
|||||||
|
|
||||||
if ( b == 0 ) return "";
|
if ( b == 0 ) return "";
|
||||||
|
|
||||||
return b->value.chars();
|
return b->value.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vault::clear()
|
void Vault::clear()
|
||||||
@ -112,47 +132,29 @@ void Vault::remove(const char* n)
|
|||||||
|
|
||||||
void Vault::setSource( const char* n )
|
void Vault::setSource( const char* n )
|
||||||
{
|
{
|
||||||
path = n;
|
path.set(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Vault::loadVault( )
|
bool Vault::loadVault( )
|
||||||
{
|
{
|
||||||
if (!path.length())
|
if ( path.empty() ) return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
FILE *fp = fopen(path.chars(), "r");
|
File a( path.str() , "r" );
|
||||||
|
|
||||||
if (!fp)
|
if ( !a ) return false;
|
||||||
|
|
||||||
|
const int sz = 512;
|
||||||
|
char value[sz+1];
|
||||||
|
char key[sz+1];
|
||||||
|
|
||||||
|
while ( a >> key && a.skipWs() && a.getline( value , sz ) )
|
||||||
{
|
{
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char lineRead[512];
|
|
||||||
char key[sizeof(lineRead) + 1];
|
|
||||||
char value[sizeof(lineRead) + 1];
|
|
||||||
|
|
||||||
while (fgets(lineRead, sizeof(lineRead), fp))
|
|
||||||
{
|
|
||||||
UTIL_TrimLeft(lineRead);
|
|
||||||
|
|
||||||
if (!*lineRead || *lineRead == ';')
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
sscanf(lineRead, "%s%*[ \t]%[^\n]", key, value);
|
|
||||||
|
|
||||||
if ( isalpha ( *key ) )
|
if ( isalpha ( *key ) )
|
||||||
{
|
|
||||||
put( key, value );
|
put( key, value );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -160,26 +162,16 @@ bool Vault::loadVault()
|
|||||||
|
|
||||||
bool Vault::saveVault( )
|
bool Vault::saveVault( )
|
||||||
{
|
{
|
||||||
if (!path.length())
|
if ( path.empty() ) return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *fp = fopen(path.chars(), "w");
|
File a( path.str() , "w" );
|
||||||
|
|
||||||
if (!fp)
|
if ( !a ) return false;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs("; Don't modify!\n", fp);
|
a << "; Don't modify!" << '\n';
|
||||||
|
|
||||||
for (Obj* b = head; b ;b = b->next)
|
for (Obj* b = head; b ;b = b->next)
|
||||||
{
|
a << b->key << '\t' << b->value << '\n';
|
||||||
fprintf(fp, "%s\t%s\n", b->key.chars(), b->value.chars());
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,40 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef VAULT_CUSTOM_H
|
#ifndef VAULT_CUSTOM_H
|
||||||
#define VAULT_CUSTOM_H
|
#define VAULT_CUSTOM_H
|
||||||
|
|
||||||
|
#include "CString.h"
|
||||||
|
#include "CList.h"
|
||||||
|
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
// class Vault
|
// class Vault
|
||||||
// *****************************************************
|
// *****************************************************
|
||||||
@ -18,15 +43,14 @@ class Vault
|
|||||||
{
|
{
|
||||||
struct Obj
|
struct Obj
|
||||||
{
|
{
|
||||||
ke::AString key;
|
String key;
|
||||||
ke::AString value;
|
String value;
|
||||||
|
|
||||||
int number;
|
int number;
|
||||||
Obj *next;
|
Obj *next;
|
||||||
Obj( const char* k, const char* v);
|
Obj( const char* k, const char* v);
|
||||||
} *head;
|
} *head;
|
||||||
|
|
||||||
ke::AString path;
|
String path;
|
||||||
|
|
||||||
Obj** find( const char* n );
|
Obj** find( const char* n );
|
||||||
|
|
||||||
@ -38,33 +62,32 @@ public:
|
|||||||
// Interface
|
// Interface
|
||||||
|
|
||||||
bool exists( const char* k );
|
bool exists( const char* k );
|
||||||
|
|
||||||
void put(const char* k, const char* v);
|
void put(const char* k, const char* v);
|
||||||
void remove( const char* k );
|
void remove( const char* k );
|
||||||
|
|
||||||
const char* get( const char* n );
|
const char* get( const char* n );
|
||||||
int get_number( const char* n );
|
int get_number( const char* n );
|
||||||
void setSource( const char* n );
|
void setSource( const char* n );
|
||||||
|
|
||||||
bool loadVault( );
|
bool loadVault( );
|
||||||
bool saveVault( );
|
bool saveVault( );
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
class iterator
|
|
||||||
{
|
class iterator {
|
||||||
Obj * a;
|
Obj * a;
|
||||||
public:
|
public:
|
||||||
iterator(Obj*aa) : a(aa) {}
|
iterator(Obj*aa) : a(aa) {}
|
||||||
iterator& operator++() { if ( a ) a = a->next; return *this; }
|
iterator& operator++() { if ( a ) a = a->next; return *this; }
|
||||||
bool operator==(const iterator& b) const { return a == b.a; }
|
bool operator==(const iterator& b) const { return a == b.a; }
|
||||||
bool operator!=(const iterator& b) const { return !operator==(b); }
|
bool operator!=(const iterator& b) const { return !operator==(b); }
|
||||||
ke::AString& key() const { return a->key; }
|
String& key() const { return a->key; }
|
||||||
ke::AString& value() const { return a->value; }
|
String& value() const { return a->value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline iterator begin() const { return iterator(head); }
|
inline iterator begin() const { return iterator(head); }
|
||||||
inline iterator end() const { return iterator(0); }
|
inline iterator end() const { return iterator(0); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //VAULT_CUSTOM_H
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,333 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "CoreConfig.h"
|
|
||||||
#include "CLibrarySys.h"
|
|
||||||
#include <amxmodx_version.h>
|
|
||||||
|
|
||||||
CoreConfig CoreCfg;
|
|
||||||
|
|
||||||
const char *MainConfigFile = "amxx.cfg";
|
|
||||||
const char *AutoConfigDir = "/plugins";
|
|
||||||
const char *MapConfigDir = "/maps";
|
|
||||||
const char *CommandFormat = "exec %s\n";
|
|
||||||
|
|
||||||
CoreConfig::CoreConfig()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreConfig::~CoreConfig()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreConfig::OnAmxxInitialized()
|
|
||||||
{
|
|
||||||
m_ConfigsBufferedForward = registerForward("OnAutoConfigsBuffered", ET_IGNORE, FP_DONE);
|
|
||||||
m_ConfigsExecutedForward = registerForward("OnConfigsExecuted", ET_IGNORE, FP_DONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreConfig::Clear()
|
|
||||||
{
|
|
||||||
m_ConfigsExecuted = false;
|
|
||||||
m_PendingForwardPush = false;
|
|
||||||
m_LegacyMainConfigExecuted = false;
|
|
||||||
m_LegacyMapConfigsExecuted = false,
|
|
||||||
m_legacyMapConfigNextTime = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreConfig::ExecuteMainConfig()
|
|
||||||
{
|
|
||||||
if (m_LegacyMainConfigExecuted)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char path[PLATFORM_MAX_PATH];
|
|
||||||
char command[PLATFORM_MAX_PATH + sizeof(CommandFormat)];
|
|
||||||
|
|
||||||
ke::SafeSprintf(path, sizeof(path), "%s/%s/%s", g_mod_name.chars(), get_localinfo("amxx_configsdir", "addons/amxmodx/configs"), MainConfigFile);
|
|
||||||
ke::SafeSprintf(command, sizeof(command), CommandFormat, path);
|
|
||||||
|
|
||||||
SERVER_COMMAND(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreConfig::ExecuteAutoConfigs()
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < static_cast<size_t>(g_plugins.getPluginsNum()); ++i)
|
|
||||||
{
|
|
||||||
auto plugin = g_plugins.findPlugin(i);
|
|
||||||
|
|
||||||
bool can_create = true;
|
|
||||||
|
|
||||||
for (size_t j = 0; j < plugin->GetConfigCount(); ++j)
|
|
||||||
{
|
|
||||||
can_create = ExecuteAutoConfig(plugin, plugin->GetConfig(j), can_create);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
executeForwards(m_ConfigsBufferedForward);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CoreConfig::ExecuteAutoConfig(CPluginMngr::CPlugin *plugin, AutoConfig *config, bool can_create)
|
|
||||||
{
|
|
||||||
bool will_create = false;
|
|
||||||
|
|
||||||
const char *configsDir = get_localinfo("amxx_configsdir", "addons/amxmodx/configs");
|
|
||||||
|
|
||||||
if (can_create && config->create)
|
|
||||||
{
|
|
||||||
will_create = true;
|
|
||||||
|
|
||||||
const char *folder = config->folder.chars();
|
|
||||||
|
|
||||||
char path[PLATFORM_MAX_PATH];
|
|
||||||
char build[PLATFORM_MAX_PATH];
|
|
||||||
|
|
||||||
build_pathname_r(path, sizeof(path), "%s%s/%s", configsDir, AutoConfigDir, folder);
|
|
||||||
|
|
||||||
if (!g_LibSys.IsPathDirectory(path))
|
|
||||||
{
|
|
||||||
char *cur_ptr = path;
|
|
||||||
|
|
||||||
g_LibSys.PathFormat(path, sizeof(path), "%s", folder);
|
|
||||||
build_pathname_r(build, sizeof(build), "%s%s", configsDir, AutoConfigDir);
|
|
||||||
|
|
||||||
size_t length = strlen(build);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
char *next_ptr = cur_ptr;
|
|
||||||
|
|
||||||
while (*next_ptr != '\0')
|
|
||||||
{
|
|
||||||
if (*next_ptr == PLATFORM_SEP_CHAR)
|
|
||||||
{
|
|
||||||
*next_ptr = '\0';
|
|
||||||
next_ptr++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*next_ptr == '\0')
|
|
||||||
{
|
|
||||||
next_ptr = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
length += g_LibSys.PathFormat(&build[length], sizeof(build) - length, "/%s", cur_ptr);
|
|
||||||
|
|
||||||
if (!g_LibSys.CreateFolder(build))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_ptr = next_ptr;
|
|
||||||
|
|
||||||
} while (cur_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char file[PLATFORM_MAX_PATH];
|
|
||||||
|
|
||||||
if (config->folder.length())
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(file, sizeof(file), "%s/%s%s/%s/%s.cfg", g_mod_name.chars(), configsDir, AutoConfigDir, config->folder.chars(), config->autocfg.chars());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(file, sizeof(file), "%s/%s%s/%s.cfg", g_mod_name.chars(), configsDir, AutoConfigDir, config->autocfg.chars());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool file_exists = g_LibSys.IsPathFile(file);
|
|
||||||
|
|
||||||
if (!file_exists && will_create)
|
|
||||||
{
|
|
||||||
auto list = g_CvarManager.GetCvarsList();
|
|
||||||
|
|
||||||
if (list->empty())
|
|
||||||
{
|
|
||||||
return can_create;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *fp = fopen(file, "wt");
|
|
||||||
|
|
||||||
if (fp)
|
|
||||||
{
|
|
||||||
fprintf(fp, "// This file was auto-generated by AMX Mod X (v%s)\n", AMXX_VERSION);
|
|
||||||
|
|
||||||
if (*plugin->getTitle() && *plugin->getAuthor() && *plugin->getVersion())
|
|
||||||
{
|
|
||||||
fprintf(fp, "// Cvars for plugin \"%s\" by \"%s\" (%s, v%s)\n", plugin->getTitle(), plugin->getAuthor(), plugin->getName(), plugin->getVersion());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(fp, "// Cvars for plugin \"%s\"\n", plugin->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "\n\n");
|
|
||||||
|
|
||||||
for (auto iter = list->begin(); iter != list->end(); iter++)
|
|
||||||
{
|
|
||||||
auto info = (*iter);
|
|
||||||
|
|
||||||
if (info->pluginId == plugin->getId())
|
|
||||||
{
|
|
||||||
char description[255];
|
|
||||||
char *ptr = description;
|
|
||||||
|
|
||||||
// Print comments until there is no more
|
|
||||||
strncopy(description, info->description.chars(), sizeof(description));
|
|
||||||
|
|
||||||
while (*ptr != '\0')
|
|
||||||
{
|
|
||||||
// Find the next line
|
|
||||||
char *next_ptr = ptr;
|
|
||||||
|
|
||||||
while (*next_ptr != '\0')
|
|
||||||
{
|
|
||||||
if (*next_ptr == '\n')
|
|
||||||
{
|
|
||||||
*next_ptr = '\0';
|
|
||||||
next_ptr++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "// %s\n", ptr);
|
|
||||||
|
|
||||||
ptr = next_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "// -\n");
|
|
||||||
fprintf(fp, "// Default: \"%s\"\n", info->defaultval.chars());
|
|
||||||
|
|
||||||
if (info->bound.hasMin)
|
|
||||||
{
|
|
||||||
fprintf(fp, "// Minimum: \"%02f\"\n", info->bound.minVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->bound.hasMax)
|
|
||||||
{
|
|
||||||
fprintf(fp, "// Maximum: \"%02f\"\n", info->bound.maxVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "%s \"%s\"\n", info->var->name, info->defaultval.chars());
|
|
||||||
fprintf(fp, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(fp, "\n");
|
|
||||||
|
|
||||||
file_exists = true;
|
|
||||||
can_create = false;
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AMXXLOG_Error("Failed to auto generate config for %s, make sure the directory has write permission.", plugin->getName());
|
|
||||||
return can_create;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file_exists)
|
|
||||||
{
|
|
||||||
char command[PLATFORM_MAX_PATH + sizeof(CommandFormat)];
|
|
||||||
ke::SafeSprintf(command, sizeof(command), CommandFormat, file);
|
|
||||||
|
|
||||||
SERVER_COMMAND(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
return can_create;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreConfig::ExecuteMapConfig()
|
|
||||||
{
|
|
||||||
const char *configsDir = get_localinfo("amxx_configsdir", "addons/amxmodx/configs");
|
|
||||||
|
|
||||||
char cfgPath[PLATFORM_MAX_PATH];
|
|
||||||
char mapName[PLATFORM_MAX_PATH];
|
|
||||||
char command[PLATFORM_MAX_PATH + sizeof(CommandFormat)];
|
|
||||||
|
|
||||||
strncopy(mapName, STRING(gpGlobals->mapname), sizeof(mapName));
|
|
||||||
|
|
||||||
char *mapPrefix;
|
|
||||||
|
|
||||||
if ((mapPrefix = strtok(mapName, "_")))
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(cfgPath, sizeof(cfgPath), "%s/%s%s/prefix_%s.cfg", g_mod_name.chars(), configsDir, MapConfigDir, mapPrefix);
|
|
||||||
|
|
||||||
if (g_LibSys.IsPathFile(cfgPath))
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(command, sizeof(command), CommandFormat, cfgPath);
|
|
||||||
SERVER_COMMAND(command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
strncopy(mapName, STRING(gpGlobals->mapname), sizeof(mapName));
|
|
||||||
ke::SafeSprintf(cfgPath, sizeof(cfgPath), "%s/%s%s/%s.cfg", g_mod_name.chars(), configsDir, MapConfigDir, mapName);
|
|
||||||
|
|
||||||
if (g_LibSys.IsPathFile(cfgPath))
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(command, sizeof(command), CommandFormat, cfgPath);
|
|
||||||
SERVER_COMMAND(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consider all configs be executed to the next frame.
|
|
||||||
m_PendingForwardPush = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CoreConfig::OnMapConfigTimer()
|
|
||||||
{
|
|
||||||
if (m_ConfigsExecuted)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_PendingForwardPush)
|
|
||||||
{
|
|
||||||
m_PendingForwardPush = false;
|
|
||||||
m_ConfigsExecuted = true;
|
|
||||||
|
|
||||||
executeForwards(m_ConfigsExecutedForward);
|
|
||||||
}
|
|
||||||
else if (!m_LegacyMapConfigsExecuted && m_legacyMapConfigNextTime <= gpGlobals->time)
|
|
||||||
{
|
|
||||||
ExecuteMapConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreConfig::CheckLegacyBufferedCommand(char *command)
|
|
||||||
{
|
|
||||||
if (m_ConfigsExecuted)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_LegacyMainConfigExecuted && strstr(command, MainConfigFile))
|
|
||||||
{
|
|
||||||
m_LegacyMainConfigExecuted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_LegacyMapConfigsExecuted && strstr(command, MapConfigDir))
|
|
||||||
{
|
|
||||||
m_LegacyMapConfigsExecuted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CoreConfig::SetMapConfigTimer(float time)
|
|
||||||
{
|
|
||||||
m_legacyMapConfigNextTime = gpGlobals->time + time;
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _CORE_CONFIG_H_
|
|
||||||
#define _CORE_CONFIG_H_
|
|
||||||
|
|
||||||
#include "CPlugin.h"
|
|
||||||
|
|
||||||
class CoreConfig
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
CoreConfig();
|
|
||||||
~CoreConfig();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
void ExecuteMainConfig();
|
|
||||||
void ExecuteAutoConfigs();
|
|
||||||
bool ExecuteAutoConfig(CPluginMngr::CPlugin *plugin, AutoConfig *config, bool can_create);
|
|
||||||
void ExecuteMapConfig();
|
|
||||||
|
|
||||||
void OnAmxxInitialized();
|
|
||||||
void OnMapConfigTimer();
|
|
||||||
|
|
||||||
void CheckLegacyBufferedCommand(char *command);
|
|
||||||
void SetMapConfigTimer(float time);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
bool m_ConfigsExecuted; // Whether all configs have been executed
|
|
||||||
bool m_PendingForwardPush; // Whether OnConfigsExecuted forward should be triggered to the next frame
|
|
||||||
bool m_LegacyMainConfigExecuted; // Whether the old admin.sma is used and amxx.cfg was executed from there
|
|
||||||
bool m_LegacyMapConfigsExecuted; // Whether the old admin.sma is used and per-map config was executed from there
|
|
||||||
float m_legacyMapConfigNextTime; // Sets the next time that per-map configs should be executed
|
|
||||||
|
|
||||||
int m_ConfigsBufferedForward;
|
|
||||||
int m_ConfigsExecutedForward;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern CoreConfig CoreCfg;
|
|
||||||
|
|
||||||
#endif // _CORE_CONFIG_H_
|
|
@ -1,669 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "CvarManager.h"
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include <CDetour/detours.h>
|
|
||||||
#include <auto-string.h>
|
|
||||||
#include <resdk/mod_rehlds_api.h>
|
|
||||||
|
|
||||||
CvarManager g_CvarManager;
|
|
||||||
|
|
||||||
void (*Cvar_DirectSet_Actual)(struct cvar_s* var, const char *value) = nullptr;
|
|
||||||
|
|
||||||
void Cvar_DirectSet_Custom(struct cvar_s *var, const char *value, IRehldsHook_Cvar_DirectSet *chain = nullptr)
|
|
||||||
{
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
if (!var || !value // Sanity checks against bogus pointers.
|
|
||||||
|| strcmp(var->string, value) == 0 // Make sure old and new values are different to not trigger callbacks.
|
|
||||||
|| !g_CvarManager.CacheLookup(var->name, &info)) // No data in cache, nothing to do.
|
|
||||||
{
|
|
||||||
chain ? chain->callNext(var, value) : Cvar_DirectSet_Actual(var, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info->bound.hasMin || info->bound.hasMax) // cvar_s doesn't have min/max mechanism, so we check things here.
|
|
||||||
{
|
|
||||||
float fvalue = atof(value);
|
|
||||||
bool oob = false;
|
|
||||||
|
|
||||||
if (info->bound.hasMin && fvalue < info->bound.minVal)
|
|
||||||
{
|
|
||||||
oob = true;
|
|
||||||
fvalue = info->bound.minVal;
|
|
||||||
}
|
|
||||||
else if (info->bound.hasMax && fvalue > info->bound.maxVal)
|
|
||||||
{
|
|
||||||
oob = true;
|
|
||||||
fvalue = info->bound.maxVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oob) // Found value out of bound, set new value and block original call.
|
|
||||||
{
|
|
||||||
CVAR_SET_FLOAT(var->name, fvalue);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ke::AString oldValue; // We save old value since it will be likely changed after original function called.
|
|
||||||
|
|
||||||
if (!info->hooks.empty())
|
|
||||||
{
|
|
||||||
oldValue = var->string;
|
|
||||||
}
|
|
||||||
|
|
||||||
chain ? chain->callNext(var, value) : Cvar_DirectSet_Actual(var, value);
|
|
||||||
|
|
||||||
if (!info->binds.empty())
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < info->binds.length(); ++i)
|
|
||||||
{
|
|
||||||
CvarBind* bind = info->binds[i];
|
|
||||||
|
|
||||||
switch (bind->type)
|
|
||||||
{
|
|
||||||
case CvarBind::CvarType_Int:
|
|
||||||
{
|
|
||||||
*bind->varAddress = atoi(var->string);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CvarBind::CvarType_Float:
|
|
||||||
{
|
|
||||||
float fvalue = atof(var->string);
|
|
||||||
*bind->varAddress = amx_ftoc(fvalue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CvarBind::CvarType_String:
|
|
||||||
{
|
|
||||||
set_amxstring_simple(bind->varAddress, var->string, bind->varLength);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info->hooks.empty())
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < info->hooks.length(); ++i)
|
|
||||||
{
|
|
||||||
CvarHook* hook = info->hooks[i];
|
|
||||||
|
|
||||||
if (hook->forward->state == AutoForward::FSTATE_OK) // Our callback can be enable/disabled by natives.
|
|
||||||
{
|
|
||||||
executeForwards(hook->forward->id, reinterpret_cast<cvar_t*>(var), oldValue.chars(), var->string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cvar_DirectSet(struct cvar_s *var, const char *value)
|
|
||||||
{
|
|
||||||
Cvar_DirectSet_Custom(var, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Cvar_DirectSet_RH(IRehldsHook_Cvar_DirectSet *chain, cvar_t *var, const char *value)
|
|
||||||
{
|
|
||||||
Cvar_DirectSet_Custom(var, value, chain);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CvarManager::CvarManager() : m_AmxmodxCvars(0), m_HookDetour(nullptr), m_ReHookEnabled(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CvarManager::~CvarManager()
|
|
||||||
{
|
|
||||||
OnAmxxShutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::CreateCvarHook(void)
|
|
||||||
{
|
|
||||||
// void PF_Cvar_DirectSet(struct cvar_s *var, const char *value) // = pfnCvar_DirectSet
|
|
||||||
// {
|
|
||||||
// Cvar_DirectSet(var, value); // <- We want to hook this.
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (!RehldsHookchains)
|
|
||||||
{
|
|
||||||
void *functionAddress = nullptr;
|
|
||||||
|
|
||||||
if (CommonConfig && CommonConfig->GetMemSig("Cvar_DirectSet", &functionAddress) && functionAddress)
|
|
||||||
{
|
|
||||||
// Disabled by default.
|
|
||||||
m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, functionAddress);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AMXXLOG_Log("Binding/Hooking cvars have been disabled - %s.", RehldsApi ? "update ReHLDS" : "check your gamedata files");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::EnableHook()
|
|
||||||
{
|
|
||||||
if (RehldsHookchains)
|
|
||||||
{
|
|
||||||
if (!m_ReHookEnabled)
|
|
||||||
{
|
|
||||||
RehldsHookchains->Cvar_DirectSet()->registerHook(Cvar_DirectSet_RH);
|
|
||||||
m_ReHookEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_HookDetour)
|
|
||||||
{
|
|
||||||
m_HookDetour->EnableDetour();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::DisableHook()
|
|
||||||
{
|
|
||||||
if (RehldsHookchains)
|
|
||||||
{
|
|
||||||
if (m_ReHookEnabled)
|
|
||||||
{
|
|
||||||
RehldsHookchains->Cvar_DirectSet()->unregisterHook(Cvar_DirectSet_RH);
|
|
||||||
m_ReHookEnabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_HookDetour)
|
|
||||||
{
|
|
||||||
m_HookDetour->DisableDetour();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::DestroyHook()
|
|
||||||
{
|
|
||||||
DisableHook();
|
|
||||||
|
|
||||||
if (m_HookDetour)
|
|
||||||
{
|
|
||||||
m_HookDetour->Destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CvarInfo* CvarManager::CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, int flags,
|
|
||||||
const char* helpText)
|
|
||||||
{
|
|
||||||
cvar_t* var = nullptr;
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
if (!CacheLookup(name, &info))
|
|
||||||
{
|
|
||||||
// Not cached - Is cvar already exist?
|
|
||||||
var = CVAR_GET_POINTER(name);
|
|
||||||
|
|
||||||
// Whether it exists, we need to prepare a new entry.
|
|
||||||
info = new CvarInfo(name, helpText, plugin, pluginId);
|
|
||||||
|
|
||||||
if (var)
|
|
||||||
{
|
|
||||||
// Cvar already exists. Just copy.
|
|
||||||
// "string" will be set after. "value" and "next" are automatically set.
|
|
||||||
info->var = var;
|
|
||||||
info->defaultval = var->string;
|
|
||||||
info->amxmodx = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Registers a new cvar.
|
|
||||||
static cvar_t cvar_reg_helper;
|
|
||||||
|
|
||||||
// "string" will be set after. "value" and "next" are automatically set.
|
|
||||||
cvar_reg_helper.name = info->name.chars();
|
|
||||||
cvar_reg_helper.string = "";
|
|
||||||
cvar_reg_helper.flags = flags;
|
|
||||||
|
|
||||||
// Adds cvar to global list.
|
|
||||||
CVAR_REGISTER(&cvar_reg_helper);
|
|
||||||
|
|
||||||
// Registering can fail if name is already a registered command.
|
|
||||||
var = CVAR_GET_POINTER(name);
|
|
||||||
|
|
||||||
// If so, we can't go further.
|
|
||||||
if (!var)
|
|
||||||
{
|
|
||||||
delete info;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If ok, we got a valid pointer, we can copy.
|
|
||||||
info->var = var;
|
|
||||||
info->defaultval = value;
|
|
||||||
info->amxmodx = true;
|
|
||||||
|
|
||||||
// Keeps track count of cvars registered by AMXX.
|
|
||||||
++m_AmxmodxCvars;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a new entry in the caches.
|
|
||||||
m_Cvars.append(info);
|
|
||||||
m_Cache.insert(name, info);
|
|
||||||
|
|
||||||
// Make sure that whether an existing or new cvar is set to the given value.
|
|
||||||
CVAR_DIRECTSET(var, value);
|
|
||||||
}
|
|
||||||
else if (info->pluginId == -1)
|
|
||||||
{
|
|
||||||
// In situation where a plugin has been modified/recompiled
|
|
||||||
// or new added plugins, and a change map occurs. We want to keep data up to date.
|
|
||||||
info->bound.hasMin = false;
|
|
||||||
info->bound.minVal = 0;
|
|
||||||
info->bound.hasMax = false;
|
|
||||||
info->bound.maxVal = 0;
|
|
||||||
info->defaultval = value;
|
|
||||||
info->description = helpText;
|
|
||||||
info->pluginId = pluginId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detour is disabled on map change.
|
|
||||||
// Don't enable it unless there are things to do.
|
|
||||||
if ((info->bound.hasMin || info->bound.hasMax))
|
|
||||||
{
|
|
||||||
EnableHook();
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
CvarInfo* CvarManager::FindCvar(const char* name)
|
|
||||||
{
|
|
||||||
cvar_t* var = nullptr;
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
// Do we have already cvar in cache?
|
|
||||||
if (CacheLookup(name, &info))
|
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cvar doesn't exist.
|
|
||||||
if (!(var = CVAR_GET_POINTER(name)))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new entry.
|
|
||||||
info = new CvarInfo(name);
|
|
||||||
info->var = var;
|
|
||||||
|
|
||||||
// Add entry in the caches.
|
|
||||||
m_Cvars.append(info);
|
|
||||||
m_Cache.insert(name, info);
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
CvarInfo* CvarManager::FindCvar(size_t index)
|
|
||||||
{
|
|
||||||
// Used by get_plugins_cvar native.
|
|
||||||
// For compatibility, only cvars registered by AMXX are concerned.
|
|
||||||
|
|
||||||
size_t iter_id = 0;
|
|
||||||
|
|
||||||
for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++)
|
|
||||||
{
|
|
||||||
if (iter->amxmodx && iter_id++ == index)
|
|
||||||
{
|
|
||||||
return *(iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CvarManager::CacheLookup(const char* name, CvarInfo** info)
|
|
||||||
{
|
|
||||||
return m_Cache.retrieve(name, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoForward* CvarManager::HookCvarChange(cvar_t* var, AMX* amx, cell param, const char** callback)
|
|
||||||
{
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
// A cvar is guaranteed to be in cache if pointer is got from
|
|
||||||
// get_cvar_pointer and register_cvar natives. Though it might be
|
|
||||||
// provided by another way. If by any chance we run in such
|
|
||||||
// situation, we create a new entry right now.
|
|
||||||
|
|
||||||
if (!CacheLookup(var->name, &info))
|
|
||||||
{
|
|
||||||
// Create a new entry.
|
|
||||||
info = new CvarInfo(var->name);
|
|
||||||
info->var = var;
|
|
||||||
|
|
||||||
// Add entry in the caches.
|
|
||||||
m_Cvars.append(info);
|
|
||||||
m_Cache.insert(info->name.chars(), info);
|
|
||||||
}
|
|
||||||
|
|
||||||
int length;
|
|
||||||
*callback = get_amxstring(amx, param, 0, length);
|
|
||||||
|
|
||||||
int forwardId = registerSPForwardByName(amx, *callback, FP_CELL, FP_STRING, FP_STRING, FP_DONE);
|
|
||||||
|
|
||||||
// Invalid callback, it could be: not a public function, wrongly named, or simply missing.
|
|
||||||
if (forwardId == -1)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hook is disabled on map change.
|
|
||||||
EnableHook();
|
|
||||||
|
|
||||||
AutoForward* forward = new AutoForward(forwardId, *callback);
|
|
||||||
info->hooks.append(new CvarHook(g_plugins.findPlugin(amx)->getId(), forward));
|
|
||||||
|
|
||||||
return forward;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CvarManager::BindCvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs, size_t varlen)
|
|
||||||
{
|
|
||||||
if (varofs > amx->hlw) // If variable address is not inside global area, we can't bind it.
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Cvars can only be bound to global variables");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pluginId = g_plugins.findPluginFast(amx)->getId();
|
|
||||||
cell* address = get_amxaddr(amx, varofs);
|
|
||||||
|
|
||||||
// To avoid unexpected behavior, probably better to error such situations.
|
|
||||||
for (size_t i = 0; i < info->binds.length(); ++i)
|
|
||||||
{
|
|
||||||
CvarBind* bind = info->binds[i];
|
|
||||||
|
|
||||||
if (bind->pluginId == pluginId)
|
|
||||||
{
|
|
||||||
if (bind->varAddress == address)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "A global variable can not be bound to multiple Cvars");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CvarBind* bind = new CvarBind(pluginId, type, get_amxaddr(amx, varofs), varlen);
|
|
||||||
|
|
||||||
info->binds.append(bind);
|
|
||||||
|
|
||||||
// Update right away variable with current cvar value.
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case CvarBind::CvarType_Int:
|
|
||||||
*bind->varAddress = atoi(info->var->string);
|
|
||||||
break;
|
|
||||||
case CvarBind::CvarType_Float:
|
|
||||||
*bind->varAddress = amx_ftoc(info->var->value);
|
|
||||||
break;
|
|
||||||
case CvarBind::CvarType_String:
|
|
||||||
set_amxstring_simple(bind->varAddress, info->var->string, bind->varLength);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hook is disabled on map change.
|
|
||||||
EnableHook();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::SetCvarMin(CvarInfo* info, bool set, float value, int pluginId)
|
|
||||||
{
|
|
||||||
info->bound.hasMin = set;
|
|
||||||
info->bound.minPluginId = pluginId;
|
|
||||||
|
|
||||||
if (set)
|
|
||||||
{
|
|
||||||
// Hook is disabled on map change.
|
|
||||||
EnableHook();
|
|
||||||
|
|
||||||
info->bound.minVal = value;
|
|
||||||
|
|
||||||
// Current value is already in the allowed range.
|
|
||||||
if (info->var->value >= value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update if needed.
|
|
||||||
CVAR_SET_FLOAT(info->var->name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::SetCvarMax(CvarInfo* info, bool set, float value, int pluginId)
|
|
||||||
{
|
|
||||||
info->bound.hasMax = set;
|
|
||||||
info->bound.maxPluginId = pluginId;
|
|
||||||
|
|
||||||
if (set)
|
|
||||||
{
|
|
||||||
// Hook is disabled on map change.
|
|
||||||
EnableHook();
|
|
||||||
|
|
||||||
info->bound.maxVal = value;
|
|
||||||
|
|
||||||
// Current value is already in the allowed range.
|
|
||||||
if (info->var->value <= value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update if needed.
|
|
||||||
CVAR_SET_FLOAT(info->var->name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CvarManager::GetRegCvarsCount()
|
|
||||||
{
|
|
||||||
return m_AmxmodxCvars;
|
|
||||||
}
|
|
||||||
|
|
||||||
CvarsList* CvarManager::GetCvarsList()
|
|
||||||
{
|
|
||||||
return &m_Cvars;
|
|
||||||
}
|
|
||||||
|
|
||||||
ke::AutoString convertFlagsToString(int flags)
|
|
||||||
{
|
|
||||||
ke::AutoString flagsName;
|
|
||||||
|
|
||||||
if (flags > 0)
|
|
||||||
{
|
|
||||||
if (flags & FCVAR_ARCHIVE) flagsName = flagsName + "FCVAR_ARCHIVE ";
|
|
||||||
if (flags & FCVAR_USERINFO) flagsName = flagsName + "FCVAR_USERINFO ";
|
|
||||||
if (flags & FCVAR_SERVER) flagsName = flagsName + "FCVAR_SERVER ";
|
|
||||||
if (flags & FCVAR_EXTDLL) flagsName = flagsName + "FCVAR_EXTDLL ";
|
|
||||||
if (flags & FCVAR_CLIENTDLL) flagsName = flagsName + "FCVAR_CLIENTDLL ";
|
|
||||||
if (flags & FCVAR_PROTECTED) flagsName = flagsName + "FCVAR_PROTECTED ";
|
|
||||||
if (flags & FCVAR_SPONLY) flagsName = flagsName + "FCVAR_SPONLY ";
|
|
||||||
if (flags & FCVAR_PRINTABLEONLY) flagsName = flagsName + "FCVAR_PRINTABLEONLY ";
|
|
||||||
if (flags & FCVAR_UNLOGGED) flagsName = flagsName + "FCVAR_UNLOGGED ";
|
|
||||||
if (flags & FCVAR_NOEXTRAWHITEPACE) flagsName = flagsName + "FCVAR_NOEXTRAWHITEPACE ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!flagsName.length())
|
|
||||||
{
|
|
||||||
flagsName = "-";
|
|
||||||
}
|
|
||||||
|
|
||||||
return flagsName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::OnConsoleCommand()
|
|
||||||
{
|
|
||||||
size_t index = 0;
|
|
||||||
size_t indexToSearch = 0;
|
|
||||||
ke::AString partialName;
|
|
||||||
|
|
||||||
int argcount = CMD_ARGC();
|
|
||||||
|
|
||||||
// amxx cvars [partial plugin name] [index from listing]
|
|
||||||
// E.g.:
|
|
||||||
// amxx cvars test <- list all cvars from plugin name starting by "test"
|
|
||||||
// amxx cvars 2 <- show informations about cvar in position 2 from "amxx cvars" list
|
|
||||||
// amxx cvars test 2 <- show informations about cvar in position 2 from "amxx cvars test" list
|
|
||||||
|
|
||||||
if (argcount > 2)
|
|
||||||
{
|
|
||||||
const char* argument = CMD_ARGV(2);
|
|
||||||
|
|
||||||
indexToSearch = atoi(argument); // amxx cvars 2
|
|
||||||
|
|
||||||
if (!indexToSearch)
|
|
||||||
{
|
|
||||||
partialName = argument; // amxx cvars test
|
|
||||||
|
|
||||||
if (argcount > 3) // amxx cvars test 2
|
|
||||||
{
|
|
||||||
indexToSearch = atoi(CMD_ARGV(3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!indexToSearch)
|
|
||||||
{
|
|
||||||
print_srvconsole("\nManaged cvars:\n");
|
|
||||||
print_srvconsole(" %-24.23s %-24.23s %-18.17s %-8.7s %-8.7s %-8.7s\n", "NAME", "VALUE", "PLUGIN", "HOOKED", "MIN", "MAX");
|
|
||||||
print_srvconsole(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++)
|
|
||||||
{
|
|
||||||
CvarInfo* ci = (*iter);
|
|
||||||
|
|
||||||
// List any cvars having a status either created, hooked or bound by a plugin.
|
|
||||||
bool in_list = ci->amxmodx || !ci->binds.empty() || !ci->hooks.empty() || ci->bound.hasMin || ci->bound.hasMax;
|
|
||||||
|
|
||||||
if (in_list && (!partialName.length() || strncmp(ci->plugin.chars(), partialName.chars(), partialName.length()) == 0))
|
|
||||||
{
|
|
||||||
if (!indexToSearch)
|
|
||||||
{
|
|
||||||
print_srvconsole(" [%3d] %-24.23s %-24.23s %-18.17s %-8.7s ", ++index, ci->name.chars(), ci->var->string,
|
|
||||||
ci->plugin.length() ? ci->plugin.chars() : "-",
|
|
||||||
ci->hooks.empty() ? "no" : "yes");
|
|
||||||
|
|
||||||
(ci->bound.hasMin) ? print_srvconsole("%-8.2f ", ci->bound.minVal) : print_srvconsole("%-8.7s ", "-");
|
|
||||||
(ci->bound.hasMax) ? print_srvconsole("%-8.2f ", ci->bound.maxVal) : print_srvconsole("%-8.7s ", "-");
|
|
||||||
print_srvconsole("\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (++index != indexToSearch)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_srvconsole("\nCvar details :\n\n");
|
|
||||||
print_srvconsole(" Cvar name : %s\n", ci->var->name);
|
|
||||||
print_srvconsole(" Value : %s\n", ci->var->string);
|
|
||||||
print_srvconsole(" Def. value : %s\n", ci->defaultval.chars());
|
|
||||||
print_srvconsole(" Description : %s\n", ci->description.chars());
|
|
||||||
print_srvconsole(" Flags : %s\n\n", convertFlagsToString(ci->var->flags).ptr());
|
|
||||||
|
|
||||||
print_srvconsole(" %-12s %-26.25s %s\n", "STATUS", "PLUGIN", "INFOS");
|
|
||||||
print_srvconsole(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
|
|
||||||
|
|
||||||
if (ci->amxmodx)
|
|
||||||
{
|
|
||||||
print_srvconsole(" Registered %-26.25s %s\n", ci->plugin.chars(), "-");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ci->bound.hasMin)
|
|
||||||
{
|
|
||||||
print_srvconsole(" Min value %-26.25s %f\n", g_plugins.findPlugin(ci->bound.minPluginId)->getName(), ci->bound.minVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ci->bound.hasMax)
|
|
||||||
{
|
|
||||||
print_srvconsole(" Max value %-26.25s %f\n", g_plugins.findPlugin(ci->bound.maxPluginId)->getName(), ci->bound.maxVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ci->binds.empty())
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < ci->binds.length(); ++i)
|
|
||||||
{
|
|
||||||
print_srvconsole(" Bound %-26.25s %s\n", g_plugins.findPlugin(ci->binds[i]->pluginId)->getName(), "-");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ci->hooks.empty())
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < ci->hooks.length(); ++i)
|
|
||||||
{
|
|
||||||
CvarHook* hook = ci->hooks[i];
|
|
||||||
|
|
||||||
print_srvconsole(" Hooked %-26.25s %s (%s)\n", g_plugins.findPlugin(hook->pluginId)->getName(),
|
|
||||||
hook->forward->callback.chars(),
|
|
||||||
hook->forward->state == AutoForward::FSTATE_OK ? "active" : "inactive");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::OnPluginUnloaded()
|
|
||||||
{
|
|
||||||
// Clear only plugin hooks list.
|
|
||||||
for (CvarsList::iterator cvar = m_Cvars.begin(); cvar != m_Cvars.end(); cvar++)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < (*cvar)->binds.length(); ++i)
|
|
||||||
{
|
|
||||||
delete (*cvar)->binds[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < (*cvar)->hooks.length(); ++i)
|
|
||||||
{
|
|
||||||
delete (*cvar)->hooks[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*cvar)->amxmodx) // Mark registered cvars so we can refresh default datas at next map.
|
|
||||||
{
|
|
||||||
(*cvar)->pluginId = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*cvar)->binds.clear();
|
|
||||||
(*cvar)->hooks.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is no point to enable hook if at next map change
|
|
||||||
// no plugins hook cvars.
|
|
||||||
DisableHook();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CvarManager::OnAmxxShutdown()
|
|
||||||
{
|
|
||||||
// Free everything.
|
|
||||||
|
|
||||||
CvarsList::iterator iter = m_Cvars.begin();
|
|
||||||
|
|
||||||
while (iter != m_Cvars.end())
|
|
||||||
{
|
|
||||||
CvarInfo* cvar = (*iter);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < cvar->binds.length(); ++i)
|
|
||||||
{
|
|
||||||
delete cvar->binds[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < cvar->hooks.length(); ++i)
|
|
||||||
{
|
|
||||||
delete cvar->hooks[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
iter = m_Cvars.erase(iter);
|
|
||||||
|
|
||||||
delete cvar;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Cache.clear();
|
|
||||||
|
|
||||||
DestroyHook();
|
|
||||||
}
|
|
@ -1,177 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef CVARS_H
|
|
||||||
#define CVARS_H
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include <amtl/am-vector.h>
|
|
||||||
#include <amtl/am-inlinelist.h>
|
|
||||||
#include <sm_namehashset.h>
|
|
||||||
#include "CGameConfigs.h"
|
|
||||||
|
|
||||||
class CDetour;
|
|
||||||
|
|
||||||
enum CvarBounds
|
|
||||||
{
|
|
||||||
CvarBound_Upper = 0,
|
|
||||||
CvarBound_Lower
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AutoForward
|
|
||||||
{
|
|
||||||
enum fwdstate
|
|
||||||
{
|
|
||||||
FSTATE_INVALID = 0,
|
|
||||||
FSTATE_OK,
|
|
||||||
FSTATE_STOP,
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoForward(int id_, const char* handler) : id(id_), state(FSTATE_OK), callback(handler) {};
|
|
||||||
AutoForward() : id(-1) , state(FSTATE_INVALID) {};
|
|
||||||
|
|
||||||
~AutoForward()
|
|
||||||
{
|
|
||||||
unregisterSPForward(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
int id;
|
|
||||||
fwdstate state;
|
|
||||||
ke::AString callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CvarHook
|
|
||||||
{
|
|
||||||
CvarHook(int id, AutoForward* fwd) : pluginId(id), forward(fwd) {};
|
|
||||||
CvarHook(int id) : pluginId(id), forward(new AutoForward()) {};
|
|
||||||
|
|
||||||
int pluginId;
|
|
||||||
ke::AutoPtr<AutoForward> forward;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CvarBind
|
|
||||||
{
|
|
||||||
enum CvarType
|
|
||||||
{
|
|
||||||
CvarType_Int,
|
|
||||||
CvarType_Float,
|
|
||||||
CvarType_String,
|
|
||||||
};
|
|
||||||
|
|
||||||
CvarBind(int id_, CvarType type_, cell* varAddress_, size_t varLength_)
|
|
||||||
:
|
|
||||||
pluginId(id_),
|
|
||||||
type(type_),
|
|
||||||
varAddress(varAddress_),
|
|
||||||
varLength(varLength_) {};
|
|
||||||
|
|
||||||
int pluginId;
|
|
||||||
CvarType type;
|
|
||||||
cell* varAddress;
|
|
||||||
size_t varLength;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CvarBound
|
|
||||||
{
|
|
||||||
CvarBound()
|
|
||||||
:
|
|
||||||
hasMin(false), minVal(0),
|
|
||||||
hasMax(false), maxVal(0),
|
|
||||||
minPluginId(-1),
|
|
||||||
maxPluginId(-1) {};
|
|
||||||
|
|
||||||
bool hasMin;
|
|
||||||
float minVal;
|
|
||||||
bool hasMax;
|
|
||||||
float maxVal;
|
|
||||||
int minPluginId;
|
|
||||||
int maxPluginId;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef ke::Vector<CvarHook*> CvarsHook;
|
|
||||||
typedef ke::Vector<CvarBind*> CvarsBind;
|
|
||||||
|
|
||||||
struct CvarInfo : public ke::InlineListNode<CvarInfo>
|
|
||||||
{
|
|
||||||
CvarInfo(const char* name_, const char* helpText, const char* plugin_, int pluginId_)
|
|
||||||
:
|
|
||||||
name(name_), description(helpText),
|
|
||||||
plugin(plugin_), pluginId(pluginId_), bound() {};
|
|
||||||
|
|
||||||
CvarInfo(const char* name_)
|
|
||||||
:
|
|
||||||
name(name_), defaultval(""), description(""),
|
|
||||||
plugin(""), pluginId(-1), bound(), amxmodx(false) {};
|
|
||||||
|
|
||||||
cvar_t* var;
|
|
||||||
ke::AString name;
|
|
||||||
ke::AString defaultval;
|
|
||||||
ke::AString description;
|
|
||||||
|
|
||||||
ke::AString plugin;
|
|
||||||
int pluginId;
|
|
||||||
|
|
||||||
CvarBound bound;
|
|
||||||
CvarsBind binds;
|
|
||||||
CvarsHook hooks;
|
|
||||||
|
|
||||||
bool amxmodx;
|
|
||||||
|
|
||||||
static inline bool matches(const char *name, const CvarInfo* info)
|
|
||||||
{
|
|
||||||
return strcmp(name, info->var->name) == 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef NameHashSet<CvarInfo*> CvarsCache;
|
|
||||||
typedef ke::InlineList<CvarInfo> CvarsList;
|
|
||||||
|
|
||||||
class CvarManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
CvarManager();
|
|
||||||
~CvarManager();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
void CreateCvarHook();
|
|
||||||
void EnableHook();
|
|
||||||
void DisableHook();
|
|
||||||
void DestroyHook();
|
|
||||||
|
|
||||||
CvarInfo* CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, int flags = 0, const char* helpText = "");
|
|
||||||
CvarInfo* FindCvar(const char* name);
|
|
||||||
CvarInfo* FindCvar(size_t index);
|
|
||||||
bool CacheLookup(const char* name, CvarInfo** info);
|
|
||||||
|
|
||||||
AutoForward* HookCvarChange(cvar_t* var, AMX* amx, cell param, const char** callback);
|
|
||||||
bool BindCvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs, size_t varlen = 0);
|
|
||||||
void SetCvarMin(CvarInfo* info, bool set, float value, int pluginId);
|
|
||||||
void SetCvarMax(CvarInfo* info, bool set, float value, int pluginId);
|
|
||||||
|
|
||||||
size_t GetRegCvarsCount();
|
|
||||||
CvarsList* GetCvarsList();
|
|
||||||
|
|
||||||
void OnConsoleCommand();
|
|
||||||
void OnPluginUnloaded();
|
|
||||||
void OnAmxxShutdown();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
CvarsCache m_Cache;
|
|
||||||
CvarsList m_Cvars;
|
|
||||||
size_t m_AmxmodxCvars;
|
|
||||||
CDetour* m_HookDetour;
|
|
||||||
bool m_ReHookEnabled;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern CvarManager g_CvarManager;
|
|
||||||
|
|
||||||
#endif // CVARS_H
|
|
116
amxmodx/Makefile
Executable file
116
amxmodx/Makefile
Executable file
@ -0,0 +1,116 @@
|
|||||||
|
MODNAME = amx_mm
|
||||||
|
SRCFILES = meta_api.cpp CFile.cpp CString.cpp CVault.cpp vault.cpp\
|
||||||
|
float.cpp file.cpp modules.cpp CMisc.cpp CTask.cpp string.cpp\
|
||||||
|
amxmod.cpp CEvent.cpp CCmd.cpp CLogEvent.cpp srvcmd.cpp strptime.cpp\
|
||||||
|
CForward.cpp CPlugin.cpp CModule.cpp CMenu.cpp emsg.cpp util.cpp
|
||||||
|
CSRCFILES = amx.c amxcore.c amxtime.c power.c
|
||||||
|
|
||||||
|
EXTRA_LIBS_LINUX =
|
||||||
|
EXTRA_LIBS_WIN32 =
|
||||||
|
EXTRA_LIBDIRS_LINUX = -Lextra/lib_linux
|
||||||
|
EXTRA_LIBDIRS_WIN32 = -Lextra/lib_win32
|
||||||
|
|
||||||
|
EXTRA_INCLUDEDIRS = -Iextra/include
|
||||||
|
|
||||||
|
EXTRA_FLAGS = -Dstrcmpi=strcasecmp
|
||||||
|
|
||||||
|
SDKTOP=../hlsdk
|
||||||
|
METADIR=../metamodx
|
||||||
|
|
||||||
|
|
||||||
|
SDKSRC=$(SDKTOP)/SourceCode
|
||||||
|
OBJDIR_LINUX=obj.linux
|
||||||
|
OBJDIR_WIN32=obj.win32
|
||||||
|
SRCDIR=.
|
||||||
|
|
||||||
|
ifdef windir
|
||||||
|
OS=WIN32
|
||||||
|
else
|
||||||
|
OS=LINUX
|
||||||
|
endif
|
||||||
|
|
||||||
|
CC_LINUX=gcc-2.95
|
||||||
|
ifeq "$(OS)" "WIN32"
|
||||||
|
CC_WIN32=gcc
|
||||||
|
LD_WINDLL=dllwrap
|
||||||
|
DEFAULT=win32
|
||||||
|
CLEAN=clean_win32
|
||||||
|
else
|
||||||
|
CC_WIN32=/usr/local/cross-tools/i386-mingw32msvc/bin/gcc
|
||||||
|
LD_WINDLL=/usr/local/cross-tools/bin/i386-mingw32msvc-dllwrap
|
||||||
|
DEFAULT=linux win32
|
||||||
|
CLEAN=clean_both
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LIBFILE_LINUX = $(MODNAME)_i386.so
|
||||||
|
LIBFILE_WIN32 = $(MODNAME).dll
|
||||||
|
TARGET_LINUX = $(OBJDIR_LINUX)/$(LIBFILE_LINUX)
|
||||||
|
TARGET_WIN32 = $(OBJDIR_WIN32)/$(LIBFILE_WIN32)
|
||||||
|
|
||||||
|
FILES_ALL = *.cpp *.h [A-Z]* *.rc
|
||||||
|
ifeq "$(OS)" "LINUX"
|
||||||
|
ASRCFILES := $(shell ls -t $(SRCFILES))
|
||||||
|
else
|
||||||
|
ASRCFILES := $(shell dir /b)
|
||||||
|
endif
|
||||||
|
OBJ_LINUX := $(SRCFILES:%.cpp=$(OBJDIR_LINUX)/%.o)
|
||||||
|
OBJC_LINUX := $(CSRCFILES:%.c=$(OBJDIR_LINUX)/%.o)
|
||||||
|
OBJ_WIN32 := $(SRCFILES:%.cpp=$(OBJDIR_WIN32)/%.o)
|
||||||
|
OBJC_WIN32 := $(CSRCFILES:%.c=$(OBJDIR_WIN32)/%.o)
|
||||||
|
|
||||||
|
|
||||||
|
CCOPT = -O2 -march=i686 -ffast-math -funroll-loops \
|
||||||
|
-fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \
|
||||||
|
-malign-jumps=2 -malign-functions=2 -s -DNDEBUG
|
||||||
|
|
||||||
|
INCLUDEDIRS=-I../curl/include -I$(SRCDIR) -I$(METADIR) -I$(SDKSRC)/engine -I$(SDKSRC)/common -I$(SDKSRC)/pm_shared -I$(SDKSRC)/dlls -I$(SDKSRC) $(EXTRA_INCLUDEDIRS)
|
||||||
|
CFLAGS=-Wall -Wno-unknown-pragmas
|
||||||
|
ODEF = -DOPT_TYPE=\"optimized\"
|
||||||
|
CFLAGS:=$(CCOPT) $(CFLAGS) $(ODEF) $(EXTRA_FLAGS)
|
||||||
|
|
||||||
|
DO_CC_LINUX=$(CC_LINUX) $(CFLAGS) -fPIC $(INCLUDEDIRS) -o $@ -c $<
|
||||||
|
DO_CC_WIN32=$(CC_WIN32) $(CFLAGS) $(INCLUDEDIRS) -o $@ -c $<
|
||||||
|
LINK_LINUX=$(CC_LINUX) $(CFLAGS) -shared -ldl -lm $(OBJ_LINUX) $(OBJC_LINUX) $(EXTRA_LIBDIRS_LINUX) $(EXTRA_LIBS_LINUX) -o $@
|
||||||
|
LINK_WIN32=$(LD_WINDLL) -mwindows --def $(MODNAME).def --add-stdcall-alias $(OBJ_WIN32) $(OBJC_WIN32) $(EXTRA_LIBDIRS_WIN32) $(EXTRA_LIBS_WIN32) -o $@
|
||||||
|
|
||||||
|
$(OBJDIR_LINUX)/%.o: $(SRCDIR)/%.c
|
||||||
|
$(DO_CC_LINUX)
|
||||||
|
|
||||||
|
$(OBJDIR_LINUX)/%.o: $(SRCDIR)/%.cpp
|
||||||
|
$(DO_CC_LINUX)
|
||||||
|
|
||||||
|
$(OBJDIR_WIN32)/%.o: $(SRCDIR)/%.c
|
||||||
|
$(DO_CC_WIN32)
|
||||||
|
|
||||||
|
$(OBJDIR_WIN32)/%.o: $(SRCDIR)/%.cpp
|
||||||
|
$(DO_CC_WIN32)
|
||||||
|
|
||||||
|
default: $(DEFAULT)
|
||||||
|
|
||||||
|
$(TARGET_LINUX): $(OBJDIR_LINUX) $(OBJ_LINUX) $(OBJC_LINUX)
|
||||||
|
$(LINK_LINUX)
|
||||||
|
|
||||||
|
$(TARGET_WIN32): $(OBJDIR_WIN32) $(OBJ_WIN32) $(OBJC_WIN32)
|
||||||
|
$(LINK_WIN32)
|
||||||
|
|
||||||
|
$(OBJDIR_LINUX):
|
||||||
|
mkdir $@
|
||||||
|
|
||||||
|
$(OBJDIR_WIN32):
|
||||||
|
mkdir $@
|
||||||
|
|
||||||
|
win32: $(TARGET_WIN32)
|
||||||
|
|
||||||
|
linux: $(TARGET_LINUX)
|
||||||
|
|
||||||
|
clean: $(CLEAN)
|
||||||
|
|
||||||
|
clean_both:
|
||||||
|
-rm -f $(OBJDIR_LINUX)/*
|
||||||
|
-rm -f $(OBJDIR_WIN32)/*
|
||||||
|
|
||||||
|
clean_win32:
|
||||||
|
del /q $(OBJDIR_WIN32)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
4175
amxmodx/amx.cpp
4175
amxmodx/amx.cpp
File diff suppressed because it is too large
Load Diff
317
amxmodx/amx.h
317
amxmodx/amx.h
@ -1,6 +1,6 @@
|
|||||||
/* Pawn Abstract Machine (for the Pawn language)
|
/* Abstract Machine for the Small compiler
|
||||||
*
|
*
|
||||||
* Copyright (c) ITB CompuPhase, 1997-2005
|
* Copyright (c) ITB CompuPhase, 1997-2003
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty.
|
* This software is provided "as-is", without any express or implied warranty.
|
||||||
* In no event will the authors be held liable for any damages arising from
|
* In no event will the authors be held liable for any damages arising from
|
||||||
@ -10,44 +10,18 @@
|
|||||||
* including commercial applications, and to alter it and redistribute it
|
* including commercial applications, and to alter it and redistribute it
|
||||||
* freely, subject to the following restrictions:
|
* freely, subject to the following restrictions:
|
||||||
*
|
*
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software in
|
|
||||||
* a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
* 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
*/
|
||||||
|
#if defined __linux__
|
||||||
#if defined FREEBSD && !defined __FreeBSD__
|
|
||||||
#define __FreeBSD__
|
|
||||||
#endif
|
|
||||||
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
|
|
||||||
#include <sclinux.h>
|
#include <sclinux.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __AMX_H
|
||||||
#ifndef AMX_H_INCLUDED
|
#define __AMX_H
|
||||||
#define AMX_H_INCLUDED
|
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||||
|
|
||||||
#if defined HAVE_STDINT_H
|
|
||||||
#include <stdint.h>
|
|
||||||
#else
|
|
||||||
#if defined __LCC__ || defined __DMC__ || defined LINUX || defined __APPLE__
|
|
||||||
#if defined HAVE_INTTYPES_H
|
|
||||||
#include <inttypes.h>
|
|
||||||
#else
|
|
||||||
#include <stdint.h>
|
|
||||||
#endif
|
|
||||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
|
||||||
/* The ISO C99 defines the int16_t and int_32t types. If the compiler got
|
/* The ISO C99 defines the int16_t and int_32t types. If the compiler got
|
||||||
* here, these types are probably undefined.
|
* here, these types are probably undefined.
|
||||||
*/
|
*/
|
||||||
#if defined __MACH__
|
#if defined __LCC__ || defined __linux__
|
||||||
#include <ppc/types.h>
|
#include <stdint.h>
|
||||||
typedef unsigned short int uint16_t;
|
|
||||||
typedef unsigned long int uint32_t;
|
|
||||||
#elif defined __FreeBSD__
|
|
||||||
#include <inttypes.h>
|
|
||||||
#else
|
#else
|
||||||
typedef short int int16_t;
|
typedef short int int16_t;
|
||||||
typedef unsigned short int uint16_t;
|
typedef unsigned short int uint16_t;
|
||||||
@ -58,42 +32,16 @@
|
|||||||
typedef long int int32_t;
|
typedef long int int32_t;
|
||||||
typedef unsigned long int uint32_t;
|
typedef unsigned long int uint32_t;
|
||||||
#endif
|
#endif
|
||||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
|
||||||
typedef __int64 int64_t;
|
|
||||||
typedef unsigned __int64 uint64_t;
|
|
||||||
#define HAVE_I64
|
|
||||||
#elif defined __GNUC__
|
|
||||||
typedef long long int64_t;
|
|
||||||
typedef unsigned long long uint64_t;
|
|
||||||
#define HAVE_I64
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
|
||||||
#define HAVE_STDINT_H
|
#if !defined alloca
|
||||||
#endif
|
#define alloca(n) _alloca(n)
|
||||||
#if defined _LP64 || defined WIN64 || defined _WIN64
|
|
||||||
#if !defined __64BIT__
|
|
||||||
#define __64BIT__
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined arraysize
|
|
||||||
#define arraysize(array) (sizeof(array) / sizeof((array)[0]))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined PAWN_DLL
|
|
||||||
#if !defined AMX_NATIVE_CALL
|
|
||||||
#define AMX_NATIVE_CALL __stdcall
|
|
||||||
#endif
|
|
||||||
#if !defined AMXAPI
|
|
||||||
#define AMXAPI __stdcall
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* calling convention for native functions */
|
/* calling convention for native functions */
|
||||||
#if !defined AMX_NATIVE_CALL
|
#if !defined AMX_NATIVE_CALL
|
||||||
#define AMX_NATIVE_CALL
|
#define AMX_NATIVE_CALL
|
||||||
@ -104,8 +52,6 @@ extern "C" {
|
|||||||
#define AMXAPI __stdcall
|
#define AMXAPI __stdcall
|
||||||
#elif defined CDECL
|
#elif defined CDECL
|
||||||
#define AMXAPI __cdecl
|
#define AMXAPI __cdecl
|
||||||
#elif defined GCC_HASCLASSVISIBILITY
|
|
||||||
#define AMXAPI __attribute__ ((visibility("default")))
|
|
||||||
#else
|
#else
|
||||||
#define AMXAPI
|
#define AMXAPI
|
||||||
#endif
|
#endif
|
||||||
@ -113,7 +59,6 @@ extern "C" {
|
|||||||
#if !defined AMXEXPORT
|
#if !defined AMXEXPORT
|
||||||
#define AMXEXPORT
|
#define AMXEXPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* File format version Required AMX version
|
/* File format version Required AMX version
|
||||||
* 0 (original version) 0
|
* 0 (original version) 0
|
||||||
* 1 (opcodes JUMP.pri, SWITCH and CASETBL) 1
|
* 1 (opcodes JUMP.pri, SWITCH and CASETBL) 1
|
||||||
@ -123,75 +68,47 @@ extern "C" {
|
|||||||
* 5 (tagnames table) 4
|
* 5 (tagnames table) 4
|
||||||
* 6 (reformatted header) 6
|
* 6 (reformatted header) 6
|
||||||
* 7 (name table, opcodes SYMTAG & SYSREQ.D) 7
|
* 7 (name table, opcodes SYMTAG & SYSREQ.D) 7
|
||||||
* 8 (opcode STMT, renewed debug interface) 8
|
|
||||||
*/
|
*/
|
||||||
#define CUR_FILE_VERSION 8 /* current file version; also the current AMX version */
|
#define CUR_FILE_VERSION 7 /* current file version; also the current AMX version */
|
||||||
#define MIN_FILE_VERSION 6 /* lowest supported file format version for the current AMX version */
|
#define MIN_FILE_VERSION 6 /* lowest supported file format version for the current AMX version */
|
||||||
#define MIN_AMX_VERSION 8 /* minimum AMX version needed to support the current file format */
|
#define MIN_AMX_VERSION 7 /* minimum AMX version needed to support the current file format */
|
||||||
|
#if !defined CELL_TYPE
|
||||||
#if !defined PAWN_CELL_SIZE
|
#define CELL_TYPE
|
||||||
#define PAWN_CELL_SIZE 32 /* by default, use 32-bit cells */
|
#if defined(BIT16)
|
||||||
#endif
|
typedef uint16_t ucell; /* only for type casting */
|
||||||
#if PAWN_CELL_SIZE==16
|
|
||||||
typedef uint16_t ucell;
|
|
||||||
typedef int16_t cell;
|
typedef int16_t cell;
|
||||||
#elif PAWN_CELL_SIZE==32
|
#else
|
||||||
typedef uint32_t ucell;
|
typedef uint32_t ucell;
|
||||||
typedef int32_t cell;
|
typedef int32_t cell;
|
||||||
#define REAL float
|
|
||||||
#elif PAWN_CELL_SIZE==64
|
|
||||||
typedef uint64_t ucell;
|
|
||||||
typedef int64_t cell;
|
|
||||||
#define REAL double
|
|
||||||
#else
|
|
||||||
#error Unsupported cell size (PAWN_CELL_SIZE)
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
#define UNPACKEDMAX ((1L << (sizeof(cell)-1)*8) - 1)
|
|
||||||
#define UNLIMITED (~1u >> 1)
|
|
||||||
|
|
||||||
struct tagAMX;
|
struct tagAMX;
|
||||||
typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, cell *params);
|
typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, cell *params);
|
||||||
typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index,
|
typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index,
|
||||||
cell *result, cell *params);
|
cell *result, cell *params);
|
||||||
typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx);
|
typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx);
|
||||||
typedef int (AMXAPI *AMX_NATIVE_FILTER)(struct tagAMX *amx, int index);
|
|
||||||
#if !defined _FAR
|
#if !defined _FAR
|
||||||
#define _FAR
|
#define _FAR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined _MSC_VER
|
#if defined _MSC_VER
|
||||||
#pragma warning(disable:4103) /* disable warning message 4103 that complains
|
#pragma warning(disable:4103) /* disable warning message 4103 that complains
|
||||||
* about pragma pack in a header file */
|
* about pragma pack in a header file */
|
||||||
#pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */
|
#pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */
|
||||||
|
|
||||||
#if _MSC_VER >= 1400
|
|
||||||
// MSVC8 - Replace POSIX stricmp with ISO C++ conformant one as it is deprecated
|
|
||||||
#define stricmp _stricmp
|
|
||||||
|
|
||||||
// Need this because of some stupid bug
|
|
||||||
#pragma warning (disable : 4996)
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Some compilers do not support the #pragma align, which should be fine. Some
|
/* Some compilers do not support the #pragma align, which should be fine. Some
|
||||||
* compilers give a warning on unknown #pragmas, which is not so fine...
|
* compilers give a warning on unknown #pragmas, which is not so fine...
|
||||||
*/
|
*/
|
||||||
#if (defined SN_TARGET_PS2 || defined __GNUC__) && !defined AMX_NO_ALIGN
|
#if defined SN_TARGET_PS2 || defined __GNUC__
|
||||||
#define AMX_NO_ALIGN
|
#define AMX_NO_ALIGN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined __GNUC__
|
#if defined __GNUC__
|
||||||
#define PACKED __attribute__((packed))
|
#define PACKED __attribute__((packed))
|
||||||
#else
|
#else
|
||||||
#define PACKED
|
#define PACKED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined AMX_NO_ALIGN
|
#if !defined AMX_NO_ALIGN
|
||||||
#if defined LINUX || defined __FreeBSD__ || defined __APPLE__
|
#if defined __linux__
|
||||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
||||||
#elif defined MACOS && defined __MWERKS__
|
|
||||||
#pragma options align=mac68k
|
|
||||||
#else
|
#else
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
||||||
@ -200,31 +117,22 @@ typedef int (AMXAPI *AMX_NATIVE_FILTER)(struct tagAMX *amx, int index);
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
typedef struct {
|
||||||
typedef struct tagAMX_NATIVE_INFO {
|
char _FAR *name PACKED;
|
||||||
const char _FAR *name PACKED;
|
|
||||||
AMX_NATIVE func PACKED;
|
AMX_NATIVE func PACKED;
|
||||||
} PACKED AMX_NATIVE_INFO;
|
} AMX_NATIVE_INFO PACKED;
|
||||||
|
|
||||||
#define AMX_USERNUM 4
|
#define AMX_USERNUM 4
|
||||||
#define sEXPMAX 19 /* maximum name length for file version <= 6 */
|
#define sEXPMAX 19 /* maximum name length for file version <= 6 */
|
||||||
#define sNAMEMAX 63 /* maximum name length of symbol name */
|
#define sNAMEMAX 31 /* maximum name length of symbol name */
|
||||||
|
|
||||||
typedef struct tagAMX_FUNCSTUB {
|
typedef struct tagAMX_FUNCSTUB {
|
||||||
ucell address PACKED;
|
uint32_t address PACKED;
|
||||||
char name[sEXPMAX+1];
|
char name[sEXPMAX+1] PACKED;
|
||||||
} PACKED AMX_FUNCSTUB;
|
} AMX_FUNCSTUB PACKED;
|
||||||
|
|
||||||
typedef struct tagFUNCSTUBNT {
|
|
||||||
ucell address PACKED;
|
|
||||||
ucell nameofs PACKED; //we need this for amxx to be backwards comaptible
|
|
||||||
} PACKED AMX_FUNCSTUBNT;
|
|
||||||
|
|
||||||
/* The AMX structure is the internal structure for many functions. Not all
|
/* The AMX structure is the internal structure for many functions. Not all
|
||||||
* fields are valid at all times; many fields are cached in local variables.
|
* fields are valid at all times; many fields are cached in local variables.
|
||||||
*/
|
*/
|
||||||
typedef struct tagAMX {
|
typedef struct tagAMX {
|
||||||
unsigned char _FAR *base PACKED; /* points to the AMX header plus the code, optionally also the data */
|
unsigned char _FAR *base PACKED; /* points to the AMX header ("amxhdr") plus the code, optionally also the data */
|
||||||
unsigned char _FAR *data PACKED; /* points to separate data+stack+heap, may be NULL */
|
unsigned char _FAR *data PACKED; /* points to separate data+stack+heap, may be NULL */
|
||||||
AMX_CALLBACK callback PACKED;
|
AMX_CALLBACK callback PACKED;
|
||||||
AMX_DEBUG debug PACKED; /* debug callback */
|
AMX_DEBUG debug PACKED; /* debug callback */
|
||||||
@ -236,35 +144,38 @@ typedef struct tagAMX {
|
|||||||
cell stk PACKED; /* stack pointer: relative to base + amxhdr->dat */
|
cell stk PACKED; /* stack pointer: relative to base + amxhdr->dat */
|
||||||
cell stp PACKED; /* top of the stack: relative to base + amxhdr->dat */
|
cell stp PACKED; /* top of the stack: relative to base + amxhdr->dat */
|
||||||
int flags PACKED; /* current status, see amx_Flags() */
|
int flags PACKED; /* current status, see amx_Flags() */
|
||||||
|
/* for assertions and debug hook */
|
||||||
|
cell curline PACKED;
|
||||||
|
cell curfile PACKED;
|
||||||
|
int dbgcode PACKED;
|
||||||
|
cell dbgaddr PACKED;
|
||||||
|
cell dbgparam PACKED;
|
||||||
|
char _FAR *dbgname PACKED;
|
||||||
/* user data */
|
/* user data */
|
||||||
void _FAR *usertags[AMX_USERNUM] PACKED;
|
long usertags[AMX_USERNUM] PACKED;
|
||||||
//okay userdata[3] in AMX Mod X is for the CPlugin * pointer
|
|
||||||
//we're also gonna set userdata[2] to a special debug structure
|
|
||||||
//lastly, userdata[1] is for opcode_list from amx_BrowseRelocate
|
|
||||||
void _FAR *userdata[AMX_USERNUM] PACKED;
|
void _FAR *userdata[AMX_USERNUM] PACKED;
|
||||||
/* native functions can raise an error */
|
/* native functions can raise an error */
|
||||||
int error PACKED;
|
int error PACKED;
|
||||||
/* passing parameters requires a "count" field */
|
|
||||||
int paramcount;
|
|
||||||
/* the sleep opcode needs to store the full AMX status */
|
/* the sleep opcode needs to store the full AMX status */
|
||||||
cell pri PACKED;
|
cell pri PACKED;
|
||||||
cell alt PACKED;
|
cell alt PACKED;
|
||||||
cell reset_stk PACKED;
|
cell reset_stk PACKED;
|
||||||
cell reset_hea PACKED;
|
cell reset_hea PACKED;
|
||||||
cell sysreq_d PACKED; /* relocated address/value for the SYSREQ.D opcode */
|
cell _FAR *syscall_d PACKED; /* relocated value/address for the SYSCALL.D opcode */
|
||||||
|
#if defined JIT
|
||||||
/* support variables for the JIT */
|
/* support variables for the JIT */
|
||||||
int reloc_size PACKED; /* required temporary buffer for relocations */
|
int reloc_size PACKED; /* required temporary buffer for relocations */
|
||||||
long code_size PACKED; /* estimated memory footprint of the native code */
|
long code_size PACKED; /* estimated memory footprint of the native code */
|
||||||
} PACKED AMX;
|
#endif
|
||||||
|
} AMX PACKED;
|
||||||
/* The AMX_HEADER structure is both the memory format as the file format. The
|
/* The AMX_HEADER structure is both the memory format as the file format. The
|
||||||
* structure is used internaly.
|
* structure is used internaly.
|
||||||
*/
|
*/
|
||||||
typedef struct tagAMX_HEADER {
|
typedef struct tagAMX_HEADER {
|
||||||
int32_t size PACKED; /* size of the "file" */
|
int32_t size PACKED; /* size of the "file" */
|
||||||
uint16_t magic PACKED; /* signature */
|
uint16_t magic PACKED; /* signature */
|
||||||
char file_version; /* file format version */
|
char file_version PACKED; /* file format version */
|
||||||
char amx_version; /* required version of the AMX */
|
char amx_version PACKED; /* required version of the AMX */
|
||||||
int16_t flags PACKED;
|
int16_t flags PACKED;
|
||||||
int16_t defsize PACKED; /* size of a definition record */
|
int16_t defsize PACKED; /* size of a definition record */
|
||||||
int32_t cod PACKED; /* initial value of COD - code block */
|
int32_t cod PACKED; /* initial value of COD - code block */
|
||||||
@ -277,12 +188,9 @@ typedef struct tagAMX_HEADER {
|
|||||||
int32_t libraries PACKED; /* offset to the table of libraries */
|
int32_t libraries PACKED; /* offset to the table of libraries */
|
||||||
int32_t pubvars PACKED; /* the "public variables" table */
|
int32_t pubvars PACKED; /* the "public variables" table */
|
||||||
int32_t tags PACKED; /* the "public tagnames" table */
|
int32_t tags PACKED; /* the "public tagnames" table */
|
||||||
int32_t nametable PACKED; /* name table */
|
int32_t nametable PACKED; /* name table, file version 7 only */
|
||||||
} PACKED AMX_HEADER;
|
} AMX_HEADER PACKED;
|
||||||
|
|
||||||
//This is always the same for us
|
|
||||||
#define AMX_MAGIC 0xf1e0
|
#define AMX_MAGIC 0xf1e0
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
AMX_ERR_NONE,
|
AMX_ERR_NONE,
|
||||||
/* reserve the first 15 error codes for exit codes of the abstract machine */
|
/* reserve the first 15 error codes for exit codes of the abstract machine */
|
||||||
@ -298,9 +206,6 @@ enum {
|
|||||||
AMX_ERR_NATIVE, /* native function failed */
|
AMX_ERR_NATIVE, /* native function failed */
|
||||||
AMX_ERR_DIVIDE, /* divide by zero */
|
AMX_ERR_DIVIDE, /* divide by zero */
|
||||||
AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */
|
AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */
|
||||||
AMX_ERR_INVSTATE, /* invalid state for this access */
|
|
||||||
AMX_ERR_INVNATIVE, /* invalid native was used */
|
|
||||||
|
|
||||||
AMX_ERR_MEMORY = 16, /* out of memory */
|
AMX_ERR_MEMORY = 16, /* out of memory */
|
||||||
AMX_ERR_FORMAT, /* invalid file format */
|
AMX_ERR_FORMAT, /* invalid file format */
|
||||||
AMX_ERR_VERSION, /* file is for a newer version of the AMX */
|
AMX_ERR_VERSION, /* file is for a newer version of the AMX */
|
||||||
@ -312,154 +217,92 @@ enum {
|
|||||||
AMX_ERR_INIT_JIT, /* cannot initialize the JIT */
|
AMX_ERR_INIT_JIT, /* cannot initialize the JIT */
|
||||||
AMX_ERR_PARAMS, /* parameter error */
|
AMX_ERR_PARAMS, /* parameter error */
|
||||||
AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */
|
AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */
|
||||||
AMX_ERR_GENERAL, /* general error (unknown or unspecific error) */
|
|
||||||
};
|
};
|
||||||
|
enum {
|
||||||
/* AMX_FLAG_CHAR16 0x01 no longer used */
|
DBG_INIT, /* query/initialize */
|
||||||
|
DBG_FILE, /* file number in curfile, filename in name */
|
||||||
|
DBG_LINE, /* line number in curline, file number in curfile */
|
||||||
|
DBG_SYMBOL, /* address in dbgaddr, class/type in dbgparam */
|
||||||
|
DBG_CLRSYM, /* stack address below which locals should be removed. stack address in stk */
|
||||||
|
DBG_CALL, /* function call, address jumped to in dbgaddr */
|
||||||
|
DBG_RETURN, /* function returns */
|
||||||
|
DBG_TERMINATE, /* program ends, code address in dbgaddr, reason in dbgparam */
|
||||||
|
DBG_SRANGE, /* symbol size and dimensions (arrays); level in dbgaddr (!); length in dbgparam */
|
||||||
|
DBG_SYMTAG, /* tag of the most recent symbol (if non-zero), tag in dbgparam */
|
||||||
|
};
|
||||||
|
#define AMX_FLAG_CHAR16 0x01 /* characters are 16-bit */
|
||||||
#define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */
|
#define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */
|
||||||
#define AMX_FLAG_COMPACT 0x04 /* compact encoding */
|
#define AMX_FLAG_COMPACT 0x04 /* compact encoding */
|
||||||
#define AMX_FLAG_BYTEOPC 0x08 /* opcode is a byte (not a cell) */
|
#define AMX_FLAG_BIGENDIAN 0x08 /* big endian encoding */
|
||||||
#define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking; no STMT opcode */
|
#define AMX_FLAG_NOCHECKS 0x10 /* no array bounds checking */
|
||||||
/* AMX_FLAG_OLDFILE 0x20 Old AMX Mod plugin */
|
#define AMX_FLAG_BROWSE 0x4000 /* browsing/relocating or executing */
|
||||||
#define AMX_FLAG_PRENIT 0x100 /* pre-initialized, do not check natives */
|
|
||||||
#define AMX_FLAG_NTVREG 0x1000 /* all native functions are registered */
|
|
||||||
#define AMX_FLAG_JITC 0x2000 /* abstract machine is JIT compiled */
|
|
||||||
#define AMX_FLAG_BROWSE 0x4000 /* busy browsing */
|
|
||||||
#define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */
|
#define AMX_FLAG_RELOC 0x8000 /* jump/call addresses relocated */
|
||||||
|
|
||||||
#define AMX_EXEC_MAIN -1 /* start at program entry point */
|
#define AMX_EXEC_MAIN -1 /* start at program entry point */
|
||||||
#define AMX_EXEC_CONT -2 /* continue from last address */
|
#define AMX_EXEC_CONT -2 /* continue from last address */
|
||||||
|
|
||||||
#define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24))
|
#define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24))
|
||||||
|
#define AMX_EXPANDMARGIN 64
|
||||||
#if !defined AMX_COMPACTMARGIN
|
|
||||||
#define AMX_COMPACTMARGIN 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define UD_FINDPLUGIN 3
|
|
||||||
#define UD_DEBUGGER 2
|
|
||||||
#define UD_OPCODELIST 1
|
|
||||||
#define UD_HANDLER 0
|
|
||||||
#define UT_NATIVE 3
|
|
||||||
#define UT_OPTIMIZER 2
|
|
||||||
#define UT_BROWSEHOOK 1
|
|
||||||
#define UT_BINLOGS 0
|
|
||||||
|
|
||||||
typedef void (*BROWSEHOOK)(AMX *amx, cell *oplist, cell *cip);
|
|
||||||
|
|
||||||
/* for native functions that use floating point parameters, the following
|
/* for native functions that use floating point parameters, the following
|
||||||
* two macros are convenient for casting a "cell" into a "float" type _without_
|
* two macros are convenient for casting a "cell" into a "float" type _without_
|
||||||
* changing the bit pattern
|
* changing the bit pattern
|
||||||
*/
|
*/
|
||||||
#if PAWN_CELL_SIZE==32
|
|
||||||
#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
|
#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
|
||||||
#define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */
|
#define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */
|
||||||
#elif PAWN_CELL_SIZE==64
|
#define amx_StrParam(amx,param,result) { \
|
||||||
#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
|
|
||||||
#define amx_ctof(c) ( * ((double*)&c) ) /* cell to float */
|
|
||||||
#else
|
|
||||||
#error Unsupported cell size
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define amx_StrParam(amx,param,result) \
|
|
||||||
do { \
|
|
||||||
cell *amx_cstr_; int amx_length_; \
|
cell *amx_cstr_; int amx_length_; \
|
||||||
amx_GetAddr((amx), (param), &amx_cstr_); \
|
amx_GetAddr((amx), (param), &amx_cstr_); \
|
||||||
amx_StrLen(amx_cstr_, &amx_length_); \
|
amx_StrLen(amx_cstr_, &amx_length_); \
|
||||||
if (amx_length_ > 0 && \
|
if (amx_length_ > 0 && \
|
||||||
((result) = (void*)alloca((amx_length_ + 1) * sizeof(*(result)))) != NULL) \
|
((result) = (char*)alloca(amx_length_ + 1)) != NULL) \
|
||||||
amx_GetString((char*)(result), amx_cstr_, sizeof(*(result))>1, amx_length_); \
|
amx_GetString((result), amx_cstr_); \
|
||||||
else (result) = NULL; \
|
else (result) = NULL; \
|
||||||
} while (0)
|
}
|
||||||
|
|
||||||
uint16_t * AMXAPI amx_Align16(uint16_t *v);
|
uint16_t * AMXAPI amx_Align16(uint16_t *v);
|
||||||
uint32_t * AMXAPI amx_Align32(uint32_t *v);
|
uint32_t * AMXAPI amx_Align32(uint32_t *v);
|
||||||
#if defined _I64_MAX || defined HAVE_I64
|
|
||||||
uint64_t * AMXAPI amx_Align64(uint64_t *v);
|
|
||||||
#endif
|
|
||||||
int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr);
|
int AMXAPI amx_Allot(AMX *amx, int cells, cell *amx_addr, cell **phys_addr);
|
||||||
int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params);
|
int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, cell *params);
|
||||||
int AMXAPI amx_CheckNatives(AMX *amx, AMX_NATIVE_FILTER nf);
|
|
||||||
int AMXAPI amx_Cleanup(AMX *amx);
|
int AMXAPI amx_Cleanup(AMX *amx);
|
||||||
int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data);
|
int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data);
|
||||||
int AMXAPI amx_Exec(AMX *amx, cell *retval, int index);
|
int AMXAPI amx_Debug(AMX *amx); /* default debug procedure, does nothing */
|
||||||
int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index);
|
int AMXAPI amx_Exec(AMX *amx, cell *retval, int index, int numparams, ...);
|
||||||
int AMXAPI amx_FindPublic(AMX *amx, const char *funcname, int *index);
|
int AMXAPI amx_Execv(AMX *amx, cell *retval, int index, int numparams, cell params[]);
|
||||||
int AMXAPI amx_FindPubVar(AMX *amx, const char *varname, cell *amx_addr);
|
int AMXAPI amx_FindNative(AMX *amx, char *name, int *index);
|
||||||
|
int AMXAPI amx_FindPublic(AMX *amx, char *funcname, int *index);
|
||||||
|
int AMXAPI amx_FindPubVar(AMX *amx, char *varname, cell *amx_addr);
|
||||||
int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname);
|
int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname);
|
||||||
int AMXAPI amx_Flags(AMX *amx,uint16_t *flags);
|
int AMXAPI amx_Flags(AMX *amx,uint16_t *flags);
|
||||||
int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr);
|
int AMXAPI amx_GetAddr(AMX *amx,cell amx_addr,cell **phys_addr);
|
||||||
int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname);
|
int AMXAPI amx_GetNative(AMX *amx, int index, char *funcname);
|
||||||
int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname);
|
int AMXAPI amx_GetPublic(AMX *amx, int index, char *funcname);
|
||||||
int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr);
|
int AMXAPI amx_GetPubVar(AMX *amx, int index, char *varname, cell *amx_addr);
|
||||||
int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size);
|
int AMXAPI amx_GetString(char *dest,cell *source);
|
||||||
int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id);
|
int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id);
|
||||||
int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr);
|
int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr);
|
||||||
int AMXAPI amx_Init(AMX *amx, void *program);
|
int AMXAPI amx_Init(AMX *amx, void *program);
|
||||||
int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code);
|
int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code);
|
||||||
int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap);
|
int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap);
|
||||||
int AMXAPI amx_NameLength(AMX *amx, int *length);
|
int AMXAPI amx_NameLength(AMX *amx, int *length);
|
||||||
AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func);
|
AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(char *name,AMX_NATIVE func);
|
||||||
int AMXAPI amx_NumNatives(AMX *amx, int *number);
|
int AMXAPI amx_NumNatives(AMX *amx, int *number);
|
||||||
int AMXAPI amx_NumPublics(AMX *amx, int *number);
|
int AMXAPI amx_NumPublics(AMX *amx, int *number);
|
||||||
int AMXAPI amx_NumPubVars(AMX *amx, int *number);
|
int AMXAPI amx_NumPubVars(AMX *amx, int *number);
|
||||||
int AMXAPI amx_NumTags(AMX *amx, int *number);
|
int AMXAPI amx_NumTags(AMX *amx, int *number);
|
||||||
int AMXAPI amx_Push(AMX *amx, cell value);
|
|
||||||
int AMXAPI amx_PushArray(AMX *amx, cell *amx_addr, cell **phys_addr, const cell array[], int numcells);
|
|
||||||
int AMXAPI amx_PushString(AMX *amx, cell *amx_addr, cell **phys_addr, const char *string, int pack, int use_wchar);
|
|
||||||
int AMXAPI amx_RaiseError(AMX *amx, int error);
|
int AMXAPI amx_RaiseError(AMX *amx, int error);
|
||||||
int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number);
|
int AMXAPI amx_Register(AMX *amx, AMX_NATIVE_INFO *nativelist, int number);
|
||||||
int AMXAPI amx_Reregister(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number);
|
|
||||||
int AMXAPI amx_RegisterToAny(AMX *amx, AMX_NATIVE f);
|
|
||||||
int AMXAPI amx_Release(AMX *amx, cell amx_addr);
|
int AMXAPI amx_Release(AMX *amx, cell amx_addr);
|
||||||
int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback);
|
int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback);
|
||||||
int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug);
|
int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug);
|
||||||
int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size);
|
int AMXAPI amx_SetString(cell *dest, char *source, int pack);
|
||||||
int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr);
|
int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr);
|
||||||
int AMXAPI amx_StrLen(const cell *cstring, int *length);
|
char * AMXAPI amx_StrError(int errnum);
|
||||||
int AMXAPI amx_UTF8Check(const char *string, int *length);
|
int AMXAPI amx_StrLen(cell *cstring, int *length);
|
||||||
int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value);
|
|
||||||
int AMXAPI amx_UTF8Len(const cell *cstr, int *length);
|
|
||||||
int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value);
|
|
||||||
int AMXAPI amx_GetLibraries(AMX *amx);
|
|
||||||
const char *AMXAPI amx_GetLibrary(AMX *amx, int index, char *buffer, int len);
|
|
||||||
int AMXAPI amx_SetStringOld(cell *dest,const char *source,int pack,int use_wchar);
|
|
||||||
int AMXAPI amx_GetStringOld(char *dest,const cell *source,int use_wchar);
|
|
||||||
|
|
||||||
#if PAWN_CELL_SIZE==16
|
|
||||||
#define amx_AlignCell(v) amx_Align16(v)
|
|
||||||
#elif PAWN_CELL_SIZE==32
|
|
||||||
#define amx_AlignCell(v) amx_Align32(v)
|
|
||||||
#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64)
|
|
||||||
#define amx_AlignCell(v) amx_Align64(v)
|
|
||||||
#else
|
|
||||||
#error Unsupported cell size
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define amx_RegisterFunc(amx, name, func) \
|
|
||||||
amx_Register((amx), amx_NativeInfo((name),(func)), 1);
|
|
||||||
|
|
||||||
#if !defined AMX_NO_ALIGN
|
#if !defined AMX_NO_ALIGN
|
||||||
#if defined LINUX || defined __FreeBSD__ || defined __APPLE__
|
#if defined __linux__
|
||||||
#pragma pack() /* reset default packing */
|
#pragma pack() /* reset default packing */
|
||||||
#elif defined MACOS && defined __MWERKS__
|
|
||||||
#pragma options align=reset
|
|
||||||
#else
|
#else
|
||||||
#pragma pack(pop) /* reset previous packing */
|
#pragma pack(pop) /* reset previous packing */
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined BINLOG_ENABLED
|
|
||||||
typedef struct tagBINLOG
|
|
||||||
{
|
|
||||||
void (*pfnLogNative)(AMX *amx, int native, int params);
|
|
||||||
void (*pfnLogReturn)(AMX *amx, cell retval);
|
|
||||||
void (*pfnLogParams)(AMX *amx, cell *params);
|
|
||||||
} binlogfuncs_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* __AMX_H */
|
||||||
#endif /* AMX_H_INCLUDED */
|
|
||||||
|
11
amxmodx/amx_mm.def
Executable file
11
amxmodx/amx_mm.def
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
; /usr/local/cross-tools/bin/i386-mingw32msvc-dlltool --base-file /tmp/cc4kB6s0.base --output-exp amx_mm.exp --dllname amx_mm.dll --output-def amx_mm.def --add-stdcall-alias --exclude-symbol=DllMainCRTStartup@12 --def /tmp/ccyI7I7K.def
|
||||||
|
EXPORTS
|
||||||
|
GetEngineFunctions @ 1 ;
|
||||||
|
GetEngineFunctions_Post @ 2 ;
|
||||||
|
GetEntityAPI2 @ 3 ;
|
||||||
|
GetEntityAPI2_Post @ 4 ;
|
||||||
|
GiveFnptrsToDll = GiveFnptrsToDll@8 @ 5 ;
|
||||||
|
GiveFnptrsToDll@8 @ 6 ;
|
||||||
|
Meta_Attach @ 7 ;
|
||||||
|
Meta_Detach @ 8 ;
|
||||||
|
Meta_Query @ 9 ;
|
@ -1,73 +1,36 @@
|
|||||||
/* Core module for the Pawn AMX
|
/* Core module for the Small AMX
|
||||||
*
|
*
|
||||||
* Copyright (c) ITB CompuPhase, 1997-2005
|
* Copyright (c) ITB CompuPhase, 1997-2002
|
||||||
|
* This file may be freely used. No warranties of any kind.
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty.
|
* Version: $Id$
|
||||||
* In no event will the authors be held liable for any damages arising from
|
|
||||||
* the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software in
|
|
||||||
* a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
* 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
|
|
||||||
# if !defined UNICODE /* for Windows */
|
|
||||||
# define UNICODE
|
|
||||||
# endif
|
|
||||||
# if !defined _UNICODE /* for C library */
|
|
||||||
# define _UNICODE
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "amx.h"
|
#include "amx.h"
|
||||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
|
|
||||||
#include <windows.h>
|
#define NOPROPLIST
|
||||||
#endif
|
|
||||||
|
|
||||||
/* A few compilers do not provide the ANSI C standard "time" functions */
|
/* A few compilers do not provide the ANSI C standard "time" functions */
|
||||||
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE
|
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined _UNICODE
|
|
||||||
# include <tchar.h>
|
|
||||||
#elif !defined __T
|
|
||||||
typedef char TCHAR;
|
|
||||||
# define __T(string) string
|
|
||||||
# define _tcschr strchr
|
|
||||||
# define _tcscpy strcpy
|
|
||||||
# define _tcsdup strdup
|
|
||||||
# define _tcslen strlen
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define CHARBITS (8*sizeof(char))
|
#define CHARBITS (8*sizeof(char))
|
||||||
typedef unsigned char uchar;
|
typedef unsigned char uchar;
|
||||||
|
|
||||||
#if !defined AMX_NOPROPLIST
|
#if !defined NOPROPLIST
|
||||||
typedef struct _property_list {
|
typedef struct _property_list {
|
||||||
struct _property_list *next;
|
struct _property_list *next;
|
||||||
cell id;
|
cell id;
|
||||||
char *name;
|
char *name;
|
||||||
cell value;
|
cell value;
|
||||||
//??? safe AMX (owner of the property)
|
|
||||||
} proplist;
|
} proplist;
|
||||||
|
|
||||||
static proplist proproot = { NULL, 0, NULL, 0 };
|
static proplist proproot = { NULL };
|
||||||
|
|
||||||
static proplist *list_additem(proplist *root)
|
static proplist *list_additem(proplist *root)
|
||||||
{
|
{
|
||||||
@ -133,15 +96,17 @@ static proplist *list_finditem(proplist *root,cell id,char *name,cell value,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
|
#pragma argsused
|
||||||
|
#endif
|
||||||
static cell AMX_NATIVE_CALL numargs(AMX *amx, cell *params)
|
static cell AMX_NATIVE_CALL numargs(AMX *amx, cell *params)
|
||||||
{
|
{
|
||||||
AMX_HEADER *hdr;
|
AMX_HEADER *hdr;
|
||||||
uchar *data;
|
uchar *data;
|
||||||
cell bytes;
|
cell bytes;
|
||||||
|
|
||||||
(void)params;
|
|
||||||
hdr=(AMX_HEADER *)amx->base;
|
hdr=(AMX_HEADER *)amx->base;
|
||||||
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
|
data=amx->base+(int)hdr->dat;
|
||||||
/* the number of bytes is on the stack, at "frm + 2*cell" */
|
/* the number of bytes is on the stack, at "frm + 2*cell" */
|
||||||
bytes= * (cell *)(data+(int)amx->frm+2*sizeof(cell));
|
bytes= * (cell *)(data+(int)amx->frm+2*sizeof(cell));
|
||||||
/* the number of arguments is the number of bytes divided
|
/* the number of arguments is the number of bytes divided
|
||||||
@ -156,7 +121,7 @@ static cell AMX_NATIVE_CALL getarg(AMX *amx, cell *params)
|
|||||||
cell value;
|
cell value;
|
||||||
|
|
||||||
hdr=(AMX_HEADER *)amx->base;
|
hdr=(AMX_HEADER *)amx->base;
|
||||||
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
|
data=amx->base+(int)hdr->dat;
|
||||||
/* get the base value */
|
/* get the base value */
|
||||||
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
|
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
|
||||||
/* adjust the address in "value" in case of an array access */
|
/* adjust the address in "value" in case of an array access */
|
||||||
@ -173,22 +138,24 @@ static cell AMX_NATIVE_CALL setarg(AMX *amx, cell *params)
|
|||||||
cell value;
|
cell value;
|
||||||
|
|
||||||
hdr=(AMX_HEADER *)amx->base;
|
hdr=(AMX_HEADER *)amx->base;
|
||||||
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
|
data=amx->base+(int)hdr->dat;
|
||||||
/* get the base value */
|
/* get the base value */
|
||||||
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
|
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
|
||||||
/* adjust the address in "value" in case of an array access */
|
/* adjust the address in "value" in case of an array access */
|
||||||
value+=params[2]*sizeof(cell);
|
value+=params[2]*sizeof(cell);
|
||||||
/* verify the address */
|
/* verify the address */
|
||||||
if (value<0 || (value>=amx->hea && value<amx->stk))
|
if (value<0 || value>=amx->hea && value<amx->stk)
|
||||||
return 0;
|
return 0;
|
||||||
/* set the value indirectly */
|
/* set the value indirectly */
|
||||||
* (cell *)(data+(int)value) = params[3];
|
* (cell *)(data+(int)value) = params[3];
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
|
#pragma argsused
|
||||||
|
#endif
|
||||||
static cell AMX_NATIVE_CALL heapspace(AMX *amx,cell *params)
|
static cell AMX_NATIVE_CALL heapspace(AMX *amx,cell *params)
|
||||||
{
|
{
|
||||||
(void)params;
|
|
||||||
return amx->stk - amx->hea;
|
return amx->stk - amx->hea;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,95 +174,191 @@ static cell AMX_NATIVE_CALL funcidx(AMX *amx,cell *params)
|
|||||||
return 0;
|
return 0;
|
||||||
} /* if */
|
} /* if */
|
||||||
|
|
||||||
amx_GetString(name,cstr,0,UNLIMITED);
|
amx_GetString(name,cstr);
|
||||||
err=amx_FindPublic(amx,name,&index);
|
err=amx_FindPublic(amx,name,&index);
|
||||||
if (err!=AMX_ERR_NONE)
|
if (err!=AMX_ERR_NONE)
|
||||||
index=-1; /* this is not considered a fatal error */
|
index=-1; /* this is not considered a fatal error */
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int amx_StrPack(cell *dest,cell *source)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
amx_StrLen(source,&len);
|
||||||
|
if ((ucell)*source>UCHAR_MAX) {
|
||||||
|
/* source string is already packed */
|
||||||
|
while (len >= 0) {
|
||||||
|
*dest++ = *source++;
|
||||||
|
len-=sizeof(cell);
|
||||||
|
} /* while */
|
||||||
|
} else {
|
||||||
|
/* pack string, from bottom up */
|
||||||
|
cell c;
|
||||||
|
int i;
|
||||||
|
for (c=0,i=0; i<len; i++) {
|
||||||
|
assert((*source & ~0xffL)==0);
|
||||||
|
c=(c<<CHARBITS) | *source++;
|
||||||
|
if (i%sizeof(cell) == sizeof(cell)-1) {
|
||||||
|
*dest++=c;
|
||||||
|
c=0;
|
||||||
|
} /* if */
|
||||||
|
} /* for */
|
||||||
|
if (i%sizeof(cell) != 0) /* store remaining packed characters */
|
||||||
|
*dest=c << (sizeof(cell)-i%sizeof(cell))*CHARBITS;
|
||||||
|
else
|
||||||
|
*dest=0; /* store full cell of zeros */
|
||||||
|
} /* if */
|
||||||
|
return AMX_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amx_StrUnpack(cell *dest,cell *source)
|
||||||
|
{
|
||||||
|
if ((ucell)*source>UCHAR_MAX) {
|
||||||
|
/* unpack string, from top down (so string can be unpacked in place) */
|
||||||
|
cell c;
|
||||||
|
int i,len;
|
||||||
|
amx_StrLen(source,&len);
|
||||||
|
dest[len]=0;
|
||||||
|
for (i=len-1; i>=0; i--) {
|
||||||
|
c=source[i/sizeof(cell)] >> (sizeof(cell)-i%sizeof(cell)-1)*CHARBITS;
|
||||||
|
dest[i]=c & UCHAR_MAX;
|
||||||
|
} /* for */
|
||||||
|
} else {
|
||||||
|
/* source string is already unpacked */
|
||||||
|
while ((*dest++ = *source++) != 0)
|
||||||
|
/* nothing */;
|
||||||
|
} /* if */
|
||||||
|
return AMX_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int verify_addr(AMX *amx,cell addr)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
cell *cdest;
|
||||||
|
|
||||||
|
err=amx_GetAddr(amx,addr,&cdest);
|
||||||
|
if (err!=AMX_ERR_NONE)
|
||||||
|
amx_RaiseError(amx,err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell AMX_NATIVE_CALL core_strlen(AMX *amx,cell *params)
|
||||||
|
{
|
||||||
|
cell *cptr;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
|
||||||
|
amx_StrLen(cptr,&len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell AMX_NATIVE_CALL strpack(AMX *amx,cell *params)
|
||||||
|
{
|
||||||
|
cell *cdest,*csrc;
|
||||||
|
int len,needed,lastaddr,err;
|
||||||
|
|
||||||
|
/* calculate number of cells needed for (packed) destination */
|
||||||
|
amx_GetAddr(amx,params[2],&csrc);
|
||||||
|
amx_StrLen(csrc,&len);
|
||||||
|
needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */
|
||||||
|
assert(needed>0);
|
||||||
|
lastaddr=params[1]+sizeof(cell)*needed-1;
|
||||||
|
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
amx_GetAddr(amx,params[1],&cdest);
|
||||||
|
err=amx_StrPack(cdest,csrc);
|
||||||
|
if (err!=AMX_ERR_NONE)
|
||||||
|
return amx_RaiseError(amx,err);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell AMX_NATIVE_CALL strunpack(AMX *amx,cell *params)
|
||||||
|
{
|
||||||
|
cell *cdest,*csrc;
|
||||||
|
int len,err,lastaddr;
|
||||||
|
|
||||||
|
/* calculate number of cells needed for (packed) destination */
|
||||||
|
amx_GetAddr(amx,params[2],&csrc);
|
||||||
|
amx_StrLen(csrc,&len);
|
||||||
|
assert(len>=0);
|
||||||
|
lastaddr=params[1]+sizeof(cell)*(len+1)-1;
|
||||||
|
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
amx_GetAddr(amx,params[1],&cdest);
|
||||||
|
err=amx_StrUnpack(cdest,csrc);
|
||||||
|
if (err!=AMX_ERR_NONE)
|
||||||
|
return amx_RaiseError(amx,err);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
|
#pragma argsused
|
||||||
|
#endif
|
||||||
static cell AMX_NATIVE_CALL swapchars(AMX *amx,cell *params)
|
static cell AMX_NATIVE_CALL swapchars(AMX *amx,cell *params)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
cell c;
|
cell c;
|
||||||
#if PAWN_CELL_SIZE==16
|
#if defined BIT16
|
||||||
uchar b[2];
|
uchar b[2];
|
||||||
#elif PAWN_CELL_SIZE==32
|
|
||||||
uchar b[4];
|
|
||||||
#elif PAWN_CELL_SIZE==64
|
|
||||||
uchar b[8];
|
|
||||||
#else
|
#else
|
||||||
#error Unsupported cell size
|
uchar b[4];
|
||||||
#endif
|
#endif
|
||||||
} value;
|
} value;
|
||||||
uchar t;
|
uchar t;
|
||||||
|
|
||||||
(void)amx;
|
|
||||||
assert((size_t)params[0]==sizeof(cell));
|
assert((size_t)params[0]==sizeof(cell));
|
||||||
value.c = params[1];
|
value.c = params[1];
|
||||||
#if PAWN_CELL_SIZE==16
|
#if defined BIT16
|
||||||
t = value.b[0];
|
t = value.b[0];
|
||||||
value.b[0] = value.b[1];
|
value.b[0] = value.b[1];
|
||||||
value.b[1] = t;
|
value.b[1] = t;
|
||||||
#elif PAWN_CELL_SIZE==32
|
#else
|
||||||
t = value.b[0];
|
t = value.b[0];
|
||||||
value.b[0] = value.b[3];
|
value.b[0] = value.b[3];
|
||||||
value.b[3] = t;
|
value.b[3] = t;
|
||||||
t = value.b[1];
|
t = value.b[1];
|
||||||
value.b[1] = value.b[2];
|
value.b[1] = value.b[2];
|
||||||
value.b[2] = t;
|
value.b[2] = t;
|
||||||
#elif PAWN_CELL_SIZE==64
|
|
||||||
t = value.b[0];
|
|
||||||
value.b[0] = value.b[7];
|
|
||||||
value.b[7] = t;
|
|
||||||
t = value.b[1];
|
|
||||||
value.b[1] = value.b[6];
|
|
||||||
value.b[6] = t;
|
|
||||||
t = value.b[2];
|
|
||||||
value.b[2] = value.b[5];
|
|
||||||
value.b[5] = t;
|
|
||||||
t = value.b[3];
|
|
||||||
value.b[3] = value.b[4];
|
|
||||||
value.b[4] = t;
|
|
||||||
#else
|
|
||||||
#error Unsupported cell size
|
|
||||||
#endif
|
#endif
|
||||||
return value.c;
|
return value.c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
|
#pragma argsused
|
||||||
|
#endif
|
||||||
static cell AMX_NATIVE_CALL core_tolower(AMX *amx,cell *params)
|
static cell AMX_NATIVE_CALL core_tolower(AMX *amx,cell *params)
|
||||||
{
|
{
|
||||||
(void)amx;
|
assert((size_t)params[0]==sizeof(cell));
|
||||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
|
||||||
return (cell)CharLower((LPTSTR)params[1]);
|
|
||||||
#elif defined _Windows
|
|
||||||
return (cell)AnsiLower((LPSTR)params[1]);
|
|
||||||
#else
|
|
||||||
return tolower((int)params[1]);
|
return tolower((int)params[1]);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
|
#pragma argsused
|
||||||
|
#endif
|
||||||
static cell AMX_NATIVE_CALL core_toupper(AMX *amx,cell *params)
|
static cell AMX_NATIVE_CALL core_toupper(AMX *amx,cell *params)
|
||||||
{
|
{
|
||||||
(void)amx;
|
assert((size_t)params[0]==sizeof(cell));
|
||||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
|
||||||
return (cell)CharUpper((LPTSTR)params[1]);
|
|
||||||
#elif defined _Windows
|
|
||||||
return (cell)AnsiUpper((LPSTR)params[1]);
|
|
||||||
#else
|
|
||||||
return toupper((int)params[1]);
|
return toupper((int)params[1]);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
|
#pragma argsused
|
||||||
|
#endif
|
||||||
static cell AMX_NATIVE_CALL core_min(AMX *amx,cell *params)
|
static cell AMX_NATIVE_CALL core_min(AMX *amx,cell *params)
|
||||||
{
|
{
|
||||||
(void)amx;
|
|
||||||
return params[1] <= params[2] ? params[1] : params[2];
|
return params[1] <= params[2] ? params[1] : params[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
|
#pragma argsused
|
||||||
|
#endif
|
||||||
static cell AMX_NATIVE_CALL core_max(AMX *amx,cell *params)
|
static cell AMX_NATIVE_CALL core_max(AMX *amx,cell *params)
|
||||||
{
|
{
|
||||||
(void)amx;
|
|
||||||
return params[1] >= params[2] ? params[1] : params[2];
|
return params[1] >= params[2] ? params[1] : params[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +374,7 @@ static cell AMX_NATIVE_CALL core_clamp(AMX *amx,cell *params)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined AMX_NOPROPLIST
|
#if !defined NOPROPLIST
|
||||||
static char *MakePackedString(cell *cptr)
|
static char *MakePackedString(cell *cptr)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
@ -319,21 +382,10 @@ static char *MakePackedString(cell *cptr)
|
|||||||
|
|
||||||
amx_StrLen(cptr,&len);
|
amx_StrLen(cptr,&len);
|
||||||
dest=(char *)malloc(len+sizeof(cell));
|
dest=(char *)malloc(len+sizeof(cell));
|
||||||
amx_GetString(dest,cptr,0,UNLIMITED);
|
amx_GetString(dest,cptr);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verify_addr(AMX *amx,cell addr)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
cell *cdest;
|
|
||||||
|
|
||||||
err=amx_GetAddr(amx,addr,&cdest);
|
|
||||||
if (err!=AMX_ERR_NONE)
|
|
||||||
amx_RaiseError(amx,err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL getproperty(AMX *amx,cell *params)
|
static cell AMX_NATIVE_CALL getproperty(AMX *amx,cell *params)
|
||||||
{
|
{
|
||||||
cell *cstr;
|
cell *cstr;
|
||||||
@ -351,7 +403,7 @@ static cell AMX_NATIVE_CALL getproperty(AMX *amx,cell *params)
|
|||||||
return 0;
|
return 0;
|
||||||
} /* if */
|
} /* if */
|
||||||
amx_GetAddr(amx,params[4],&cstr);
|
amx_GetAddr(amx,params[4],&cstr);
|
||||||
amx_SetString(cstr,item->name,1,0,UNLIMITED);
|
amx_SetString(cstr,item->name,1);
|
||||||
} /* if */
|
} /* if */
|
||||||
free(name);
|
free(name);
|
||||||
return (item!=NULL) ? item->value : 0;
|
return (item!=NULL) ? item->value : 0;
|
||||||
@ -416,14 +468,12 @@ static cell AMX_NATIVE_CALL existproperty(AMX *amx,cell *params)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined AMX_NORANDOM
|
|
||||||
/* This routine comes from the book "Inner Loops" by Rick Booth, Addison-Wesley
|
/* This routine comes from the book "Inner Loops" by Rick Booth, Addison-Wesley
|
||||||
* (ISBN 0-201-47960-5). This is a "multiplicative congruential random number
|
* (ISBN 0-201-47960-5). This is a "multiplicative congruential random number
|
||||||
* generator" that has been extended to 31-bits (the standard C version returns
|
* generator" that has been extended to 31-bits (the standard C version returns
|
||||||
* only 15-bits).
|
* only 15-bits).
|
||||||
*/
|
*/
|
||||||
#define INITIAL_SEED 0xcaa938dbL
|
static unsigned long IL_StandardRandom_seed = 0L;
|
||||||
static unsigned long IL_StandardRandom_seed = INITIAL_SEED; /* always use a non-zero seed */
|
|
||||||
#define IL_RMULT 1103515245L
|
#define IL_RMULT 1103515245L
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
#pragma argsused
|
#pragma argsused
|
||||||
@ -435,7 +485,7 @@ static cell AMX_NATIVE_CALL core_random(AMX *amx,cell *params)
|
|||||||
|
|
||||||
/* one-time initialization (or, mostly one-time) */
|
/* one-time initialization (or, mostly one-time) */
|
||||||
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE
|
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE
|
||||||
if (IL_StandardRandom_seed == INITIAL_SEED)
|
if (IL_StandardRandom_seed == 0L)
|
||||||
IL_StandardRandom_seed=(unsigned long)time(NULL);
|
IL_StandardRandom_seed=(unsigned long)time(NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -452,8 +502,23 @@ static cell AMX_NATIVE_CALL core_random(AMX *amx,cell *params)
|
|||||||
result %= params[1];
|
result %= params[1];
|
||||||
return (cell)result;
|
return (cell)result;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
void core_Init(void)
|
||||||
|
{
|
||||||
|
/* reduced to a do-nothing routine */
|
||||||
|
}
|
||||||
|
|
||||||
|
void core_Exit(void)
|
||||||
|
{
|
||||||
|
#if !defined NOPROPLIST
|
||||||
|
while (proproot.next!=NULL)
|
||||||
|
list_delete(&proproot,proproot.next);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
AMX_NATIVE_INFO core_Natives[] = {
|
AMX_NATIVE_INFO core_Natives[] = {
|
||||||
{ "numargs", numargs },
|
{ "numargs", numargs },
|
||||||
@ -461,28 +526,23 @@ AMX_NATIVE_INFO core_Natives[] = {
|
|||||||
{ "setarg", setarg },
|
{ "setarg", setarg },
|
||||||
{ "heapspace", heapspace },
|
{ "heapspace", heapspace },
|
||||||
{ "funcidx", funcidx },
|
{ "funcidx", funcidx },
|
||||||
|
{ "strlen", core_strlen },
|
||||||
|
{ "strpack", strpack },
|
||||||
|
{ "strunpack", strunpack },
|
||||||
{ "swapchars", swapchars },
|
{ "swapchars", swapchars },
|
||||||
{ "tolower", core_tolower },
|
{ "tolower", core_tolower },
|
||||||
{ "toupper", core_toupper },
|
{ "toupper", core_toupper },
|
||||||
|
{ "random", core_random },
|
||||||
{ "min", core_min },
|
{ "min", core_min },
|
||||||
{ "max", core_max },
|
{ "max", core_max },
|
||||||
{ "clamp", core_clamp },
|
{ "clamp", core_clamp },
|
||||||
{ "random", core_random },
|
#if !defined NOPROPLIST
|
||||||
|
{ "getproperty", getproperty },
|
||||||
|
{ "setproperty", setproperty },
|
||||||
|
{ "deleteproperty",delproperty },
|
||||||
|
{ "existproperty", existproperty },
|
||||||
|
#endif
|
||||||
{ NULL, NULL } /* terminator */
|
{ NULL, NULL } /* terminator */
|
||||||
};
|
};
|
||||||
|
|
||||||
int AMXEXPORT amx_CoreInit(AMX *amx)
|
|
||||||
{
|
|
||||||
return amx_Register(amx, core_Natives, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXEXPORT amx_CoreCleanup(AMX *amx)
|
|
||||||
{
|
|
||||||
(void)amx;
|
|
||||||
#if !defined AMX_NOPROPLIST
|
|
||||||
//??? delete only the properties owned by the AMX
|
|
||||||
while (proproot.next!=NULL)
|
|
||||||
list_delete(&proproot,proproot.next);
|
|
||||||
#endif
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
@ -1,497 +0,0 @@
|
|||||||
/* Pawn debugger interface
|
|
||||||
*
|
|
||||||
* Support functions for debugger applications
|
|
||||||
*
|
|
||||||
* Copyright (c) ITB CompuPhase, 2005
|
|
||||||
*
|
|
||||||
* This software is provided "as-is", without any express or implied warranty.
|
|
||||||
* In no event will the authors be held liable for any damages arising from
|
|
||||||
* the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software in
|
|
||||||
* a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
* 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "osdefs.h" /* for _MAX_PATH */
|
|
||||||
#include "amx.h"
|
|
||||||
#include "amxdbg.h"
|
|
||||||
|
|
||||||
// this file does not include amxmodx.h, so we have to include the memory manager here
|
|
||||||
#ifdef MEMORY_TEST
|
|
||||||
#include "mmgr/mmgr.h"
|
|
||||||
#endif // MEMORY_TEST
|
|
||||||
|
|
||||||
int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg)
|
|
||||||
{
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
if (amxdbg->hdr != NULL)
|
|
||||||
free(amxdbg->hdr);
|
|
||||||
if (amxdbg->filetbl != NULL)
|
|
||||||
free(amxdbg->filetbl);
|
|
||||||
if (amxdbg->symboltbl != NULL)
|
|
||||||
free(amxdbg->symboltbl);
|
|
||||||
if (amxdbg->tagtbl != NULL)
|
|
||||||
free(amxdbg->tagtbl);
|
|
||||||
if (amxdbg->automatontbl != NULL)
|
|
||||||
free(amxdbg->automatontbl);
|
|
||||||
if (amxdbg->statetbl != NULL)
|
|
||||||
free(amxdbg->statetbl);
|
|
||||||
memset(amxdbg, 0, sizeof(AMX_DBG));
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void memread(void *dest, char **src, size_t size)
|
|
||||||
{
|
|
||||||
void *ptr = *src;
|
|
||||||
memcpy(dest, ptr, size);
|
|
||||||
*src += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *ClipFileName(const char *inp)
|
|
||||||
{
|
|
||||||
static char buffer[256];
|
|
||||||
size_t len = strlen(inp);
|
|
||||||
const char *ptr = inp;
|
|
||||||
|
|
||||||
for (size_t i=0; i<len; i++)
|
|
||||||
{
|
|
||||||
if ((inp[i] == '\\' || inp[i] == '/') && (i != len-1))
|
|
||||||
ptr = inp + i + 1;
|
|
||||||
}
|
|
||||||
strcpy(buffer, ptr);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Note - I changed this function to read from memory instead.
|
|
||||||
// -- BAILOPAN
|
|
||||||
int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, void *dbg_addr)
|
|
||||||
{
|
|
||||||
AMX_DBG_HDR dbghdr;
|
|
||||||
unsigned char *ptr;
|
|
||||||
int index, dim;
|
|
||||||
AMX_DBG_SYMDIM *symdim;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
|
|
||||||
char *addr = (char *)(dbg_addr);
|
|
||||||
|
|
||||||
memset(&dbghdr, 0, sizeof(AMX_DBG_HDR));
|
|
||||||
memread(&dbghdr, &addr, sizeof(AMX_DBG_HDR));
|
|
||||||
|
|
||||||
//brabbby graa gragghty graaahhhh
|
|
||||||
#if BYTE_ORDER==BIG_ENDIAN
|
|
||||||
amx_Align32((uint32_t*)&dbghdr.size);
|
|
||||||
amx_Align16(&dbghdr.magic);
|
|
||||||
amx_Align16(&dbghdr.flags);
|
|
||||||
amx_Align16(&dbghdr.files);
|
|
||||||
amx_Align16(&dbghdr.lines);
|
|
||||||
amx_Align16(&dbghdr.symbols);
|
|
||||||
amx_Align16(&dbghdr.tags);
|
|
||||||
amx_Align16(&dbghdr.automatons);
|
|
||||||
amx_Align16(&dbghdr.states);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (dbghdr.magic != AMX_DBG_MAGIC)
|
|
||||||
return AMX_ERR_FORMAT;
|
|
||||||
|
|
||||||
/* allocate all memory */
|
|
||||||
memset(amxdbg, 0, sizeof(AMX_DBG));
|
|
||||||
amxdbg->hdr = (AMX_DBG_HDR *)malloc((size_t)dbghdr.size);
|
|
||||||
if (dbghdr.files > 0)
|
|
||||||
amxdbg->filetbl = (AMX_DBG_FILE **)malloc(dbghdr.files * sizeof(AMX_DBG_FILE *));
|
|
||||||
if (dbghdr.symbols > 0)
|
|
||||||
amxdbg->symboltbl = (AMX_DBG_SYMBOL **)malloc(dbghdr.symbols * sizeof(AMX_DBG_SYMBOL *));
|
|
||||||
if (dbghdr.tags > 0)
|
|
||||||
amxdbg->tagtbl = (AMX_DBG_TAG **)malloc(dbghdr.tags * sizeof(AMX_DBG_TAG *));
|
|
||||||
if (dbghdr.automatons > 0)
|
|
||||||
amxdbg->automatontbl = (AMX_DBG_MACHINE **)malloc(dbghdr.automatons * sizeof(AMX_DBG_MACHINE *));
|
|
||||||
if (dbghdr.states > 0)
|
|
||||||
amxdbg->statetbl = (AMX_DBG_STATE **)malloc(dbghdr.states * sizeof(AMX_DBG_STATE *));
|
|
||||||
if (amxdbg->hdr == NULL
|
|
||||||
|| (dbghdr.files > 0 && amxdbg->filetbl == NULL)
|
|
||||||
|| (dbghdr.symbols > 0 && amxdbg->symboltbl == NULL)
|
|
||||||
|| (dbghdr.tags > 0 && amxdbg->tagtbl == NULL)
|
|
||||||
|| (dbghdr.states > 0 && amxdbg->statetbl == NULL)
|
|
||||||
|| (dbghdr.automatons > 0 && amxdbg->automatontbl == NULL))
|
|
||||||
{
|
|
||||||
dbg_FreeInfo(amxdbg);
|
|
||||||
return AMX_ERR_MEMORY;
|
|
||||||
} /* if */
|
|
||||||
|
|
||||||
/* load the entire symbolic information block into memory */
|
|
||||||
memcpy(amxdbg->hdr, &dbghdr, sizeof dbghdr);
|
|
||||||
ptr = (unsigned char *)(amxdbg->hdr + 1);
|
|
||||||
memread(ptr, &addr, (size_t)(dbghdr.size-sizeof(dbghdr)));
|
|
||||||
|
|
||||||
/* file table */
|
|
||||||
for (index = 0; index < dbghdr.files; index++) {
|
|
||||||
assert(amxdbg->filetbl != NULL);
|
|
||||||
amxdbg->filetbl[index] = (AMX_DBG_FILE *)ptr;
|
|
||||||
#if BYTE_ORDER==BIG_ENDIAN
|
|
||||||
amx_AlignCell(&amxdbg->filetbl[index]->address);
|
|
||||||
#endif
|
|
||||||
for (ptr = ptr + sizeof(AMX_DBG_FILE); *ptr != '\0'; ptr++)
|
|
||||||
/* nothing */;
|
|
||||||
ptr++; /* skip '\0' too */
|
|
||||||
} /* for */
|
|
||||||
|
|
||||||
//debug("Files: %d\n", amxdbg->hdr->files);
|
|
||||||
for (index=0;index<amxdbg->hdr->files; index++)
|
|
||||||
{
|
|
||||||
strcpy((char *)amxdbg->filetbl[index]->name, ClipFileName(amxdbg->filetbl[index]->name));
|
|
||||||
//debug(" [%d] %s\n", index, amxdbg->filetbl[index]->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* line table */
|
|
||||||
amxdbg->linetbl = (AMX_DBG_LINE*)ptr;
|
|
||||||
#if BYTE_ORDER==BIG_ENDIAN
|
|
||||||
for (index = 0; index < dbghdr.lines; index++) {
|
|
||||||
amx_AlignCell(&amxdbg->linetbl[index].address);
|
|
||||||
amx_Align32((uint32_t*)&amxdbg->linetbl[index].line);
|
|
||||||
} /* for */
|
|
||||||
#endif
|
|
||||||
ptr += dbghdr.lines * sizeof(AMX_DBG_LINE);
|
|
||||||
|
|
||||||
/* symbol table (plus index tags) */
|
|
||||||
for (index = 0; index < dbghdr.symbols; index++) {
|
|
||||||
assert(amxdbg->symboltbl != NULL);
|
|
||||||
amxdbg->symboltbl[index] = (AMX_DBG_SYMBOL *)ptr;
|
|
||||||
#if BYTE_ORDER==BIG_ENDIAN
|
|
||||||
amx_AlignCell(&amxdbg->symboltbl[index]->address);
|
|
||||||
amx_Align16((uint16_t*)&amxdbg->symboltbl[index]->tag);
|
|
||||||
amx_AlignCell(&amxdbg->symboltbl[index]->codestart);
|
|
||||||
amx_AlignCell(&amxdbg->symboltbl[index]->codeend);
|
|
||||||
amx_Align16((uint16_t*)&amxdbg->symboltbl[index]->dim);
|
|
||||||
#endif
|
|
||||||
for (ptr = ptr + sizeof(AMX_DBG_SYMBOL); *ptr != '\0'; ptr++)
|
|
||||||
/* nothing */;
|
|
||||||
ptr++; /* skip '\0' too */
|
|
||||||
for (dim = 0; dim < amxdbg->symboltbl[index]->dim; dim++) {
|
|
||||||
symdim = (AMX_DBG_SYMDIM *)ptr;
|
|
||||||
amx_Align16((uint16_t*)&symdim->tag);
|
|
||||||
amx_AlignCell(&symdim->size);
|
|
||||||
ptr += sizeof(AMX_DBG_SYMDIM);
|
|
||||||
} /* for */
|
|
||||||
} /* for */
|
|
||||||
|
|
||||||
/* tag name table */
|
|
||||||
for (index = 0; index < dbghdr.tags; index++) {
|
|
||||||
assert(amxdbg->tagtbl != NULL);
|
|
||||||
amxdbg->tagtbl[index] = (AMX_DBG_TAG *)ptr;
|
|
||||||
#if BYTE_ORDER==BIG_ENDIAN
|
|
||||||
amx_Align16(&amxdbg->tagtbl[index]->tag);
|
|
||||||
#endif
|
|
||||||
for (ptr = ptr + sizeof(AMX_DBG_TAG) - 1; *ptr != '\0'; ptr++)
|
|
||||||
/* nothing */;
|
|
||||||
ptr++; /* skip '\0' too */
|
|
||||||
} /* for */
|
|
||||||
|
|
||||||
/* automaton name table */
|
|
||||||
for (index = 0; index < dbghdr.automatons; index++) {
|
|
||||||
assert(amxdbg->automatontbl != NULL);
|
|
||||||
amxdbg->automatontbl[index] = (AMX_DBG_MACHINE *)ptr;
|
|
||||||
#if BYTE_ORDER==BIG_ENDIAN
|
|
||||||
amx_Align16(&amxdbg->automatontbl[index]->automaton);
|
|
||||||
amx_AlignCell(&amxdbg->automatontbl[index]->address);
|
|
||||||
#endif
|
|
||||||
for (ptr = ptr + sizeof(AMX_DBG_MACHINE) - 1; *ptr != '\0'; ptr++)
|
|
||||||
/* nothing */;
|
|
||||||
ptr++; /* skip '\0' too */
|
|
||||||
} /* for */
|
|
||||||
|
|
||||||
/* state name table */
|
|
||||||
for (index = 0; index < dbghdr.states; index++) {
|
|
||||||
assert(amxdbg->statetbl != NULL);
|
|
||||||
amxdbg->statetbl[index] = (AMX_DBG_STATE *)ptr;
|
|
||||||
#if BYTE_ORDER==BIG_ENDIAN
|
|
||||||
amx_Align16(&amxdbg->statetbl[index]->state);
|
|
||||||
amx_Align16(&amxdbg->automatontbl[index]->automaton);
|
|
||||||
#endif
|
|
||||||
for (ptr = ptr + sizeof(AMX_DBG_STATE) - 1; *ptr != '\0'; ptr++)
|
|
||||||
/* nothing */;
|
|
||||||
ptr++; /* skip '\0' too */
|
|
||||||
} /* for */
|
|
||||||
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename)
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(filename != NULL);
|
|
||||||
*filename = NULL;
|
|
||||||
/* this is a simple linear look-up; a binary search would be possible too */
|
|
||||||
for (index = 0; index < amxdbg->hdr->files && amxdbg->filetbl[index]->address <= address; index++)
|
|
||||||
/* nothing */;
|
|
||||||
/* reset for overrun */
|
|
||||||
if (--index < 0)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
|
|
||||||
*filename = amxdbg->filetbl[index]->name;
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line)
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(line != NULL);
|
|
||||||
*line = 0;
|
|
||||||
/* this is a simple linear look-up; a binary search would be possible too */
|
|
||||||
for (index = 0; index < amxdbg->hdr->lines && amxdbg->linetbl[index].address <= address; index++)
|
|
||||||
/* nothing */;
|
|
||||||
/* reset for overrun */
|
|
||||||
if (--index < 0)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
|
|
||||||
*line = (long)amxdbg->linetbl[index].line;
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname)
|
|
||||||
{
|
|
||||||
/* dbg_LookupFunction() finds the function a code address is in. It can be
|
|
||||||
* used for stack walking, and for stepping through a function while stepping
|
|
||||||
* over sub-functions
|
|
||||||
*/
|
|
||||||
int index;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(funcname != NULL);
|
|
||||||
*funcname = NULL;
|
|
||||||
for (index = 0; index < amxdbg->hdr->symbols; index++) {
|
|
||||||
if (amxdbg->symboltbl[index]->ident == iFUNCTN
|
|
||||||
&& amxdbg->symboltbl[index]->codestart <= address
|
|
||||||
&& amxdbg->symboltbl[index]->codeend > address)
|
|
||||||
break;
|
|
||||||
} /* for */
|
|
||||||
if (index >= amxdbg->hdr->symbols)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
|
|
||||||
*funcname = amxdbg->symboltbl[index]->name;
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name)
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(name != NULL);
|
|
||||||
*name = NULL;
|
|
||||||
for (index = 0; index < amxdbg->hdr->tags && amxdbg->tagtbl[index]->tag != tag; index++)
|
|
||||||
/* nothing */;
|
|
||||||
if (index >= amxdbg->hdr->tags)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
|
|
||||||
*name = amxdbg->tagtbl[index]->name;
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name)
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(name != NULL);
|
|
||||||
*name = NULL;
|
|
||||||
for (index = 0; index < amxdbg->hdr->automatons && amxdbg->automatontbl[index]->automaton != automaton; index++)
|
|
||||||
/* nothing */;
|
|
||||||
if (index >= amxdbg->hdr->automatons)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
|
|
||||||
*name = amxdbg->automatontbl[index]->name;
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name)
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(name != NULL);
|
|
||||||
*name = NULL;
|
|
||||||
for (index = 0; index < amxdbg->hdr->states && amxdbg->statetbl[index]->state != state; index++)
|
|
||||||
/* nothing */;
|
|
||||||
if (index >= amxdbg->hdr->states)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
|
|
||||||
*name = amxdbg->statetbl[index]->name;
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address)
|
|
||||||
{
|
|
||||||
/* Find a suitable "breakpoint address" close to the indicated line (and in
|
|
||||||
* the specified file). The address is moved up to the next "breakable" line
|
|
||||||
* if no "breakpoint" is available on the specified line. You can use function
|
|
||||||
* dbg_LookupLine() to find out at which precise line the breakpoint was set.
|
|
||||||
*
|
|
||||||
* The filename comparison is strict (case sensitive and path sensitive); the
|
|
||||||
* "filename" parameter should point into the "filetbl" of the AMX_DBG
|
|
||||||
* structure.
|
|
||||||
*/
|
|
||||||
int file, index;
|
|
||||||
ucell bottomaddr,topaddr;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(filename != NULL);
|
|
||||||
assert(address != NULL);
|
|
||||||
*address = 0;
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
for (file = 0; file < amxdbg->hdr->files; file++) {
|
|
||||||
/* find the (next) mathing instance of the file */
|
|
||||||
if (strcmp(amxdbg->filetbl[file]->name, filename) != 0)
|
|
||||||
continue;
|
|
||||||
/* get address range for the current file */
|
|
||||||
bottomaddr = amxdbg->filetbl[file]->address;
|
|
||||||
topaddr = (file + 1 < amxdbg->hdr->files) ? amxdbg->filetbl[file+1]->address : (ucell)(cell)-1;
|
|
||||||
/* go to the starting address in the line table */
|
|
||||||
while (index < amxdbg->hdr->lines && amxdbg->linetbl[index].address < bottomaddr)
|
|
||||||
index++;
|
|
||||||
/* browse until the line is found or until the top address is exceeded */
|
|
||||||
while (index < amxdbg->hdr->lines
|
|
||||||
&& amxdbg->linetbl[index].line < line
|
|
||||||
&& amxdbg->linetbl[index].address < topaddr)
|
|
||||||
index++;
|
|
||||||
if (index >= amxdbg->hdr->lines)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
if (amxdbg->linetbl[index].line >= line)
|
|
||||||
break;
|
|
||||||
/* if not found (and the line table is not yet exceeded) try the next
|
|
||||||
* instance of the same file (a file may appear twice in the file table)
|
|
||||||
*/
|
|
||||||
} /* for */
|
|
||||||
|
|
||||||
if (strcmp(amxdbg->filetbl[file]->name, filename) != 0)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
|
|
||||||
assert(index < amxdbg->hdr->lines);
|
|
||||||
*address = amxdbg->linetbl[index].address;
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address)
|
|
||||||
{
|
|
||||||
/* Find a suitable "breakpoint address" close to the indicated line (and in
|
|
||||||
* the specified file). The address is moved up to the first "breakable" line
|
|
||||||
* in the function. You can use function dbg_LookupLine() to find out at which
|
|
||||||
* precise line the breakpoint was set.
|
|
||||||
*
|
|
||||||
* The filename comparison is strict (case sensitive and path sensitive); the
|
|
||||||
* "filename" parameter should point into the "filetbl" of the AMX_DBG
|
|
||||||
* structure. The function name comparison is case sensitive too.
|
|
||||||
*/
|
|
||||||
int index, err;
|
|
||||||
const char *tgtfile;
|
|
||||||
ucell funcaddr;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(funcname != NULL);
|
|
||||||
assert(filename != NULL);
|
|
||||||
assert(address != NULL);
|
|
||||||
*address = 0;
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
for ( ;; ) {
|
|
||||||
/* find (next) matching function */
|
|
||||||
while (index < amxdbg->hdr->symbols
|
|
||||||
&& (amxdbg->symboltbl[index]->ident != iFUNCTN || strcmp(amxdbg->symboltbl[index]->name, funcname) != 0))
|
|
||||||
index++;
|
|
||||||
if (index >= amxdbg->hdr->symbols)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
/* verify that this line falls in the appropriate file */
|
|
||||||
err = dbg_LookupFile(amxdbg, amxdbg->symboltbl[index]->address, &tgtfile);
|
|
||||||
if (err == AMX_ERR_NONE || strcmp(filename, tgtfile) == 0)
|
|
||||||
break;
|
|
||||||
index++; /* line is the wrong file, search further */
|
|
||||||
} /* for */
|
|
||||||
|
|
||||||
/* now find the first line in the function where we can "break" on */
|
|
||||||
assert(index < amxdbg->hdr->symbols);
|
|
||||||
funcaddr = amxdbg->symboltbl[index]->address;
|
|
||||||
for (index = 0; index < amxdbg->hdr->lines && amxdbg->linetbl[index].address < funcaddr; index++)
|
|
||||||
/* nothing */;
|
|
||||||
|
|
||||||
if (index >= amxdbg->hdr->lines)
|
|
||||||
return AMX_ERR_NOTFOUND;
|
|
||||||
*address = amxdbg->linetbl[index].address;
|
|
||||||
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym)
|
|
||||||
{
|
|
||||||
ucell codestart,codeend;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(symname != NULL);
|
|
||||||
assert(sym != NULL);
|
|
||||||
*sym = NULL;
|
|
||||||
|
|
||||||
codestart = codeend = 0;
|
|
||||||
index = 0;
|
|
||||||
for ( ;; ) {
|
|
||||||
/* find (next) matching variable */
|
|
||||||
while (index < amxdbg->hdr->symbols
|
|
||||||
&& (amxdbg->symboltbl[index]->ident == iFUNCTN || strcmp(amxdbg->symboltbl[index]->name, symname) != 0)
|
|
||||||
&& (amxdbg->symboltbl[index]->codestart > scopeaddr || amxdbg->symboltbl[index]->codeend < scopeaddr))
|
|
||||||
index++;
|
|
||||||
if (index >= amxdbg->hdr->symbols)
|
|
||||||
break;
|
|
||||||
/* check the range, keep a pointer to the symbol with the smallest range */
|
|
||||||
if (strcmp(amxdbg->symboltbl[index]->name, symname) == 0
|
|
||||||
&& ((codestart == 0 && codeend == 0)
|
|
||||||
|| (amxdbg->symboltbl[index]->codestart >= codestart && amxdbg->symboltbl[index]->codeend <= codeend)))
|
|
||||||
{
|
|
||||||
*sym = amxdbg->symboltbl[index];
|
|
||||||
codestart = amxdbg->symboltbl[index]->codestart;
|
|
||||||
codeend = amxdbg->symboltbl[index]->codeend;
|
|
||||||
} /* if */
|
|
||||||
index++;
|
|
||||||
} /* for */
|
|
||||||
|
|
||||||
return (*sym == NULL) ? AMX_ERR_NOTFOUND : AMX_ERR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim)
|
|
||||||
{
|
|
||||||
/* retrieves a pointer to the array dimensions structures of an array symbol */
|
|
||||||
const char *ptr;
|
|
||||||
|
|
||||||
assert(amxdbg != NULL);
|
|
||||||
assert(sym != NULL);
|
|
||||||
assert(symdim != NULL);
|
|
||||||
*symdim = NULL;
|
|
||||||
|
|
||||||
if (sym->ident != iARRAY && sym->ident != iREFARRAY)
|
|
||||||
return AMX_ERR_PARAMS;
|
|
||||||
assert(sym->dim > 0); /* array must have at least one dimension */
|
|
||||||
|
|
||||||
/* find the end of the symbol name */
|
|
||||||
for (ptr = sym->name; *ptr != '\0'; ptr++)
|
|
||||||
/* nothing */;
|
|
||||||
*symdim = (AMX_DBG_SYMDIM *)(ptr + 1);/* skip '\0' too */
|
|
||||||
|
|
||||||
return AMX_ERR_NONE;
|
|
||||||
}
|
|
170
amxmodx/amxdbg.h
170
amxmodx/amxdbg.h
@ -1,170 +0,0 @@
|
|||||||
/* Abstract Machine for the Pawn compiler, debugger support
|
|
||||||
*
|
|
||||||
* This file contains extra definitions that are convenient for debugger
|
|
||||||
* support.
|
|
||||||
*
|
|
||||||
* Copyright (c) ITB CompuPhase, 2005
|
|
||||||
*
|
|
||||||
* This software is provided "as-is", without any express or implied warranty.
|
|
||||||
* In no event will the authors be held liable for any damages arising from
|
|
||||||
* the use of this software.
|
|
||||||
*
|
|
||||||
* Permission is granted to anyone to use this software for any purpose,
|
|
||||||
* including commercial applications, and to alter it and redistribute it
|
|
||||||
* freely, subject to the following restrictions:
|
|
||||||
*
|
|
||||||
* 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
* claim that you wrote the original software. If you use this software in
|
|
||||||
* a product, an acknowledgment in the product documentation would be
|
|
||||||
* appreciated but is not required.
|
|
||||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
* misrepresented as being the original software.
|
|
||||||
* 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef AMXDBG_H_INCLUDED
|
|
||||||
#define AMXDBG_H_INCLUDED
|
|
||||||
|
|
||||||
#ifndef AMX_H_INCLUDED
|
|
||||||
#include "amx.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Some compilers do not support the #pragma align, which should be fine. Some
|
|
||||||
* compilers give a warning on unknown #pragmas, which is not so fine...
|
|
||||||
*/
|
|
||||||
#if defined SN_TARGET_PS2 || defined __GNUC__
|
|
||||||
#define AMX_NO_ALIGN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined __GNUC__
|
|
||||||
#define PACKED __attribute__((packed))
|
|
||||||
#else
|
|
||||||
#define PACKED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined AMX_NO_ALIGN
|
|
||||||
#if defined LINUX || defined __FreeBSD__ || defined __APPLE__
|
|
||||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
|
||||||
#elif defined MACOS && defined __MWERKS__
|
|
||||||
#pragma options align=mac68k
|
|
||||||
#else
|
|
||||||
#pragma pack(push)
|
|
||||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
|
||||||
#if defined __TURBOC__
|
|
||||||
#pragma option -a- /* "pack" pragma for older Borland compilers */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG_HDR {
|
|
||||||
int32_t size PACKED; /* size of the debug information chunk */
|
|
||||||
uint16_t magic PACKED; /* signature, must be 0xf1ef */
|
|
||||||
char file_version; /* file format version */
|
|
||||||
char amx_version; /* required version of the AMX */
|
|
||||||
int16_t flags PACKED; /* currently unused */
|
|
||||||
int16_t files PACKED; /* number of entries in the "file" table */
|
|
||||||
int16_t lines PACKED; /* number of entries in the "line" table */
|
|
||||||
int16_t symbols PACKED; /* number of entries in the "symbol" table */
|
|
||||||
int16_t tags PACKED; /* number of entries in the "tag" table */
|
|
||||||
int16_t automatons PACKED; /* number of entries in the "automaton" table */
|
|
||||||
int16_t states PACKED; /* number of entries in the "state" table */
|
|
||||||
} PACKED AMX_DBG_HDR;
|
|
||||||
#define AMX_DBG_MAGIC 0xf1ef
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG_FILE {
|
|
||||||
ucell address PACKED; /* address in the code segment where generated code (for this file) starts */
|
|
||||||
const char name[1]; /* ASCII string, zero-terminated */
|
|
||||||
} PACKED AMX_DBG_FILE;
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG_LINE {
|
|
||||||
ucell address PACKED; /* address in the code segment where generated code (for this line) starts */
|
|
||||||
int32_t line PACKED; /* line number */
|
|
||||||
} PACKED AMX_DBG_LINE;
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG_SYMBOL {
|
|
||||||
ucell address PACKED; /* address in the data segment or relative to the frame */
|
|
||||||
int16_t tag PACKED; /* tag for the symbol */
|
|
||||||
ucell codestart PACKED; /* address in the code segment from which this symbol is valid (in scope) */
|
|
||||||
ucell codeend PACKED; /* address in the code segment until which this symbol is valid (in scope) */
|
|
||||||
char ident; /* kind of symbol (function/variable) */
|
|
||||||
char vclass; /* class of symbol (global/local) */
|
|
||||||
int16_t dim PACKED; /* number of dimensions */
|
|
||||||
const char name[1]; /* ASCII string, zero-terminated */
|
|
||||||
} PACKED AMX_DBG_SYMBOL;
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG_SYMDIM {
|
|
||||||
int16_t tag PACKED; /* tag for the array dimension */
|
|
||||||
ucell size PACKED; /* size of the array dimension */
|
|
||||||
} PACKED AMX_DBG_SYMDIM;
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG_TAG {
|
|
||||||
int16_t tag PACKED; /* tag id */
|
|
||||||
const char name[1]; /* ASCII string, zero-terminated */
|
|
||||||
} PACKED AMX_DBG_TAG;
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG_MACHINE {
|
|
||||||
int16_t automaton PACKED; /* automaton id */
|
|
||||||
ucell address PACKED; /* address of state variable */
|
|
||||||
const char name[1]; /* ASCII string, zero-terminated */
|
|
||||||
} PACKED AMX_DBG_MACHINE;
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG_STATE {
|
|
||||||
int16_t state PACKED; /* state id */
|
|
||||||
int16_t automaton PACKED; /* automaton id */
|
|
||||||
const char name[1]; /* ASCII string, zero-terminated */
|
|
||||||
} PACKED AMX_DBG_STATE;
|
|
||||||
|
|
||||||
typedef struct tagAMX_DBG {
|
|
||||||
AMX_DBG_HDR _FAR *hdr PACKED; /* points to the AMX_DBG header */
|
|
||||||
AMX_DBG_FILE _FAR **filetbl PACKED;
|
|
||||||
AMX_DBG_LINE _FAR *linetbl PACKED;
|
|
||||||
AMX_DBG_SYMBOL _FAR **symboltbl PACKED;
|
|
||||||
AMX_DBG_TAG _FAR **tagtbl PACKED;
|
|
||||||
AMX_DBG_MACHINE _FAR **automatontbl PACKED;
|
|
||||||
AMX_DBG_STATE _FAR **statetbl PACKED;
|
|
||||||
} PACKED AMX_DBG;
|
|
||||||
|
|
||||||
#if !defined iVARIABLE
|
|
||||||
#define iVARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */
|
|
||||||
#define iREFERENCE 2 /* iVARIABLE, but must be dereferenced */
|
|
||||||
#define iARRAY 3
|
|
||||||
#define iREFARRAY 4 /* an array passed by reference (i.e. a pointer) */
|
|
||||||
#define iFUNCTN 9
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg);
|
|
||||||
int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, void *dbg_addr);
|
|
||||||
|
|
||||||
int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename);
|
|
||||||
int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname);
|
|
||||||
int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line);
|
|
||||||
|
|
||||||
int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address);
|
|
||||||
int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address);
|
|
||||||
int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name);
|
|
||||||
int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name);
|
|
||||||
int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name);
|
|
||||||
int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym);
|
|
||||||
int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim);
|
|
||||||
|
|
||||||
|
|
||||||
#if !defined AMX_NO_ALIGN
|
|
||||||
#if defined LINUX || defined __FreeBSD__ || defined __APPLE__
|
|
||||||
#pragma pack() /* reset default packing */
|
|
||||||
#elif defined MACOS && defined __MWERKS__
|
|
||||||
#pragma options align=reset
|
|
||||||
#else
|
|
||||||
#pragma pack(pop) /* reset previous packing */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* AMXDBG_H_INCLUDED */
|
|
@ -1,86 +0,0 @@
|
|||||||
; Definition of the AMX structure for assembler syntax (NASM)
|
|
||||||
|
|
||||||
struc amx_s
|
|
||||||
_base: resd 1
|
|
||||||
_dataseg: resd 1
|
|
||||||
_callback: resd 1
|
|
||||||
_debug: resd 1
|
|
||||||
_cip: resd 1
|
|
||||||
_frm: resd 1
|
|
||||||
_hea: resd 1
|
|
||||||
_hlw: resd 1
|
|
||||||
_stk: resd 1
|
|
||||||
_stp: resd 1
|
|
||||||
_flags: resd 1
|
|
||||||
_usertags: resd 4 ; 4 = AMX_USERNUM (#define'd in amx.h)
|
|
||||||
_userdata: resd 4 ; 4 = AMX_USERNUM (#define'd in amx.h)
|
|
||||||
_error: resd 1
|
|
||||||
_paramcount: resd 1
|
|
||||||
_pri: resd 1
|
|
||||||
_alt: resd 1
|
|
||||||
_reset_stk: resd 1
|
|
||||||
_reset_hea: resd 1
|
|
||||||
_syscall_d: resd 1
|
|
||||||
%ifdef JIT
|
|
||||||
; the two fields below are for the JIT; they do not exist in
|
|
||||||
; the non-JIT version of the abstract machine
|
|
||||||
_reloc_size: resd 1 ; memory block for relocations
|
|
||||||
_code_size: resd 1 ; memory size of the native code
|
|
||||||
%endif
|
|
||||||
endstruc
|
|
||||||
|
|
||||||
struc amxhead_s
|
|
||||||
_size: resd 1 ; size of the "file"
|
|
||||||
_magic: resw 1 ; signature
|
|
||||||
_file_version: resb 1; file format version
|
|
||||||
_amx_version: resb 1 ; required version of the AMX
|
|
||||||
_h_flags: resw 1
|
|
||||||
_defsize: resw 1 ; size of one public/native function entry
|
|
||||||
_cod: resd 1 ; initial value of COD - code block
|
|
||||||
_dat: resd 1 ; initial value of DAT - data block
|
|
||||||
_h_hea: resd 1 ; initial value of HEA - start of the heap
|
|
||||||
_h_stp: resd 1 ; initial value of STP - stack top
|
|
||||||
_h_cip: resd 1 ; initial value of CIP - the instruction pointer
|
|
||||||
_publics: resd 1 ; offset to the "public functions" table
|
|
||||||
_natives: resd 1 ; offset to the "native functions" table
|
|
||||||
_libraries: resd 1 ; offset to the "library" table
|
|
||||||
_pubvars: resd 1 ; offset to the "public variables" table
|
|
||||||
_tags: resd 1 ; offset to the "public tagnames" table
|
|
||||||
_nametable: resd 1 ; offset to the name table, file version 7 only
|
|
||||||
endstruc
|
|
||||||
|
|
||||||
|
|
||||||
AMX_ERR_NONE EQU 0
|
|
||||||
AMX_ERR_EXIT EQU 1
|
|
||||||
AMX_ERR_ASSERT EQU 2
|
|
||||||
AMX_ERR_STACKERR EQU 3
|
|
||||||
AMX_ERR_BOUNDS EQU 4
|
|
||||||
AMX_ERR_MEMACCESS EQU 5
|
|
||||||
AMX_ERR_INVINSTR EQU 6
|
|
||||||
AMX_ERR_STACKLOW EQU 7
|
|
||||||
AMX_ERR_HEAPLOW EQU 8
|
|
||||||
AMX_ERR_CALLBACK EQU 9
|
|
||||||
AMX_ERR_NATIVE EQU 10
|
|
||||||
AMX_ERR_DIVIDE EQU 11 ; for catching divide errors
|
|
||||||
AMX_ERR_SLEEP EQU 12
|
|
||||||
|
|
||||||
AMX_ERR_MEMORY EQU 16
|
|
||||||
AMX_ERR_FORMAT EQU 17
|
|
||||||
AMX_ERR_VERSION EQU 18
|
|
||||||
AMX_ERR_NOTFOUND EQU 19
|
|
||||||
AMX_ERR_INDEX EQU 20
|
|
||||||
AMX_ERR_DEBUG EQU 21
|
|
||||||
AMX_ERR_INIT EQU 22
|
|
||||||
AMX_ERR_USERDATA EQU 23
|
|
||||||
AMX_ERR_INIT_JIT EQU 24
|
|
||||||
AMX_ERR_PARAMS EQU 25
|
|
||||||
AMX_ERR_DOMAIN EQU 26
|
|
||||||
AMX_ERR_GENERAL EQU 27
|
|
||||||
|
|
||||||
AMX_FLAG_DEBUG EQU 0002h ; symbolic info. available
|
|
||||||
AMX_FLAG_COMPACT EQU 0004h
|
|
||||||
AMX_FLAG_BYTEOPC EQU 0008h
|
|
||||||
AMX_FLAG_NOCHECKS EQU 0010h
|
|
||||||
AMX_FLAG_BROWSE EQU 4000h
|
|
||||||
AMX_FLAG_RELOC EQU 8000h ; jump/call addresses relocated
|
|
||||||
|
|
1785
amxmodx/amxexecn.asm
1785
amxmodx/amxexecn.asm
File diff suppressed because it is too large
Load Diff
2621
amxmodx/amxjitsn.asm
2621
amxmodx/amxjitsn.asm
File diff suppressed because it is too large
Load Diff
2562
amxmodx/amxmod.cpp
Executable file
2562
amxmodx/amxmod.cpp
Executable file
File diff suppressed because it is too large
Load Diff
240
amxmodx/amxmod.h
Executable file
240
amxmodx/amxmod.h
Executable file
@ -0,0 +1,240 @@
|
|||||||
|
/* AMX Mod X
|
||||||
|
*
|
||||||
|
* by the AMX Mod X Development Team
|
||||||
|
* originally developed by OLO
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AMXMOD_H
|
||||||
|
#define AMXMOD_H
|
||||||
|
|
||||||
|
#include "modules.h"
|
||||||
|
#include "CString.h"
|
||||||
|
#include "CList.h"
|
||||||
|
#include "CPlugin.h"
|
||||||
|
#include "CMisc.h"
|
||||||
|
#include "CVault.h"
|
||||||
|
#include "CModule.h"
|
||||||
|
#include "CTask.h"
|
||||||
|
#include "CLogEvent.h"
|
||||||
|
#include "CForward.h"
|
||||||
|
#include "CCmd.h"
|
||||||
|
#include "CMenu.h"
|
||||||
|
#include "CEvent.h"
|
||||||
|
|
||||||
|
#define AMX_VERSION "0.15"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
extern AMX_NATIVE_INFO core_Natives[];
|
||||||
|
extern AMX_NATIVE_INFO time_Natives[];
|
||||||
|
extern AMX_NATIVE_INFO power_Natives[];
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
extern AMX_NATIVE_INFO amxmod_Natives[];
|
||||||
|
extern AMX_NATIVE_INFO file_Natives[];
|
||||||
|
extern AMX_NATIVE_INFO float_Natives[];
|
||||||
|
extern AMX_NATIVE_INFO string_Natives[];
|
||||||
|
extern AMX_NATIVE_INFO vault_Natives[];
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __linux__
|
||||||
|
#define DLLOAD(path) (DLHANDLE)LoadLibrary(path);
|
||||||
|
#define DLPROC(m,func) GetProcAddress(m,func);
|
||||||
|
#define DLFREE(m) FreeLibrary(m);
|
||||||
|
#else
|
||||||
|
#define DLLOAD(path) (DLHANDLE)dlopen(path, RTLD_NOW);
|
||||||
|
#define DLPROC(m,func) dlsym(m,func);
|
||||||
|
#define DLFREE(m) dlclose(m);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __linux__
|
||||||
|
typedef HINSTANCE DLHANDLE;
|
||||||
|
#else
|
||||||
|
typedef void* DLHANDLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GETPLAYERAUTHID
|
||||||
|
#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId)
|
||||||
|
#endif
|
||||||
|
#define ANGLEVECTORS (*g_engfuncs.pfnAngleVectors)
|
||||||
|
#define CLIENT_PRINT (*g_engfuncs.pfnClientPrintf)
|
||||||
|
#define CVAR_DIRECTSET (*g_engfuncs.pfnCvar_DirectSet)
|
||||||
|
#define GETCLIENTLISTENING (*g_engfuncs.pfnVoice_GetClientListening)
|
||||||
|
#define RUNPLAYERMOVE (*g_engfuncs.pfnRunPlayerMove)
|
||||||
|
#define SETCLIENTLISTENING (*g_engfuncs.pfnVoice_SetClientListening)
|
||||||
|
#define SETCLIENTMAXSPEED (*g_engfuncs.pfnSetClientMaxspeed)
|
||||||
|
|
||||||
|
char* UTIL_SplitHudMessage(register const char *src);
|
||||||
|
int UTIL_ReadFlags(const char* c);
|
||||||
|
void UTIL_ClientPrint( edict_t *pEntity, int msg_dest, char *msg );
|
||||||
|
void UTIL_FakeClientCommand(edict_t *pEdict, const char *cmd, const char *arg1 = NULL, const char *arg2 = NULL);
|
||||||
|
void UTIL_GetFlags(char* flags,int flag);
|
||||||
|
void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, char *pMessage);
|
||||||
|
void UTIL_IntToString(int value, char *output);
|
||||||
|
void UTIL_ShowMOTD( edict_t *client , char *motd, int mlen, const char *name);
|
||||||
|
void UTIL_ShowMenu( edict_t* pEntity, int slots, int time, char *menu, int mlen );
|
||||||
|
void UTIL_MakeNewLogFile();
|
||||||
|
void UTIL_Log(const char *fmt, ...);
|
||||||
|
|
||||||
|
#define GET_PLAYER_POINTER(e) (&g_players[ENTINDEX(e)])
|
||||||
|
//#define GET_PLAYER_POINTER(e) (&g_players[(((int)e-g_edict_point)/sizeof(edict_t ))])
|
||||||
|
#define GET_PLAYER_POINTER_I(i) (&g_players[i])
|
||||||
|
|
||||||
|
struct WeaponsVault {
|
||||||
|
String fullName;
|
||||||
|
short int iId;
|
||||||
|
short int ammoSlot;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fakecmd_t {
|
||||||
|
char args[256];
|
||||||
|
const char *argv[3];
|
||||||
|
//char argv[3][128];
|
||||||
|
int argc;
|
||||||
|
bool fake;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern CPluginMngr g_plugins;
|
||||||
|
extern CTaskMngr g_tasksMngr;
|
||||||
|
extern CPlayer g_players[33];
|
||||||
|
extern CPlayer* mPlayer;
|
||||||
|
extern CmdMngr g_commands;
|
||||||
|
extern CList<CCVar> g_cvars;
|
||||||
|
extern CList<ForceObject> g_forcemodels;
|
||||||
|
extern CList<ForceObject> g_forcesounds;
|
||||||
|
extern CList<ForceObject> g_forcegeneric;
|
||||||
|
extern CList<CModule> g_modules;
|
||||||
|
extern CList<CPlayer*> g_auth;
|
||||||
|
extern EventsMngr g_events;
|
||||||
|
extern Grenades g_grenades;
|
||||||
|
extern LogEventsMngr g_logevents;
|
||||||
|
extern MenuMngr g_menucmds;
|
||||||
|
extern String g_log_dir;
|
||||||
|
extern String g_mod_name;
|
||||||
|
extern TeamIds g_teamsIds;
|
||||||
|
extern Vault g_vault;
|
||||||
|
extern CForwardMngr g_forwards;
|
||||||
|
extern WeaponsVault g_weaponsData[MAX_WEAPONS];
|
||||||
|
extern XVars g_xvars;
|
||||||
|
extern bool g_bmod_cstrike;
|
||||||
|
extern bool g_bmod_dod;
|
||||||
|
extern bool g_dontprecache;
|
||||||
|
extern bool g_initialized;
|
||||||
|
extern int g_srvindex;
|
||||||
|
extern cvar_t* amx_version;
|
||||||
|
extern cvar_t* amxmodx_version;
|
||||||
|
extern cvar_t* hostname;
|
||||||
|
extern cvar_t* mp_timelimit;
|
||||||
|
extern fakecmd_t g_fakecmd;
|
||||||
|
extern float g_game_restarting;
|
||||||
|
extern float g_game_timeleft;
|
||||||
|
extern float g_task_time;
|
||||||
|
extern float g_auth_time;
|
||||||
|
extern hudtextparms_t g_hudset;
|
||||||
|
//extern int g_edict_point;
|
||||||
|
extern int g_players_num;
|
||||||
|
extern int mPlayerIndex;
|
||||||
|
extern int mState;
|
||||||
|
extern void (*endfunction)(void*);
|
||||||
|
extern void (*function)(void*);
|
||||||
|
|
||||||
|
typedef void (*funEventCall)(void*);
|
||||||
|
extern funEventCall modMsgsEnd[MAX_REG_MSGS];
|
||||||
|
extern funEventCall modMsgs[MAX_REG_MSGS];
|
||||||
|
|
||||||
|
extern int gmsgAmmoPickup;
|
||||||
|
extern int gmsgAmmoX;
|
||||||
|
extern int gmsgBattery;
|
||||||
|
extern int gmsgCurWeapon;
|
||||||
|
extern int gmsgDamage;
|
||||||
|
extern int gmsgDeathMsg;
|
||||||
|
extern int gmsgHealth;
|
||||||
|
extern int gmsgMOTD;
|
||||||
|
extern int gmsgScoreInfo;
|
||||||
|
extern int gmsgSendAudio;
|
||||||
|
extern int gmsgServerName;
|
||||||
|
extern int gmsgShowMenu;
|
||||||
|
extern int gmsgTeamInfo;
|
||||||
|
extern int gmsgTextMsg;
|
||||||
|
extern int gmsgVGUIMenu;
|
||||||
|
extern int gmsgWeapPickup;
|
||||||
|
extern int gmsgWeaponList;
|
||||||
|
extern int gmsgintermission;
|
||||||
|
extern int gmsgResetHUD;
|
||||||
|
extern int gmsgRoundTime;
|
||||||
|
|
||||||
|
void Client_AmmoPickup(void*);
|
||||||
|
void Client_AmmoX(void*);
|
||||||
|
void Client_CurWeapon(void*);
|
||||||
|
void Client_ScoreInfo(void*);
|
||||||
|
void Client_ShowMenu(void*);
|
||||||
|
void Client_TeamInfo(void*);
|
||||||
|
void Client_TextMsg(void*);
|
||||||
|
void Client_VGUIMenu(void*);
|
||||||
|
void Client_WeaponList(void*);
|
||||||
|
void Client_DamageEnd(void*);
|
||||||
|
void Client_DeathMsg(void*);
|
||||||
|
|
||||||
|
void amx_command();
|
||||||
|
void plugin_srvcmd();
|
||||||
|
|
||||||
|
const char* stristr(const char* a,const char* b);
|
||||||
|
char *strptime(const char *buf, const char *fmt, struct tm *tm, short addthem);
|
||||||
|
|
||||||
|
int loadModules(const char* filename);
|
||||||
|
void dettachModules();
|
||||||
|
void dettachReloadModules();
|
||||||
|
void attachModules();
|
||||||
|
void attachMetaModModules( const char* filename );
|
||||||
|
void dettachMetaModModules( const char* filename );
|
||||||
|
|
||||||
|
int add_amxnatives(module_info_s* info,AMX_NATIVE_INFO*natives);
|
||||||
|
cell* get_amxaddr(AMX *amx,cell amx_addr);
|
||||||
|
char* build_pathname(char *fmt, ... );
|
||||||
|
char* format_amxstring(AMX *amx, cell *params, int parm,int& len);
|
||||||
|
AMX* get_amxscript(int, void**,const char**);
|
||||||
|
const char* get_amxscriptname(AMX* amx);
|
||||||
|
char* get_amxstring(AMX *amx,cell amx_addr,int id,int& len);
|
||||||
|
int amxstring_len(cell* cstr);
|
||||||
|
int load_amxscript(AMX* amx, void** program, const char* path, char error[64]);
|
||||||
|
int set_amxnatives(AMX* amx,char error[64]);
|
||||||
|
int set_amxstring(AMX *amx,cell amx_addr,const char *source,int max);
|
||||||
|
int unload_amxscript(AMX* amx,void** program);
|
||||||
|
void copy_amxmemory(cell* dest,cell* src,int len);
|
||||||
|
void get_modname(char*);
|
||||||
|
void print_srvconsole( char *fmt, ... );
|
||||||
|
void report_error( int code, char* fmt, ... );
|
||||||
|
void* alloc_amxmemory(void**, int size);
|
||||||
|
void free_amxmemory(void **ptr);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // AMXMOD_H
|
||||||
|
|
4863
amxmodx/amxmodx.cpp
4863
amxmodx/amxmodx.cpp
File diff suppressed because it is too large
Load Diff
@ -1,374 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef AMXMODX_H
|
|
||||||
#define AMXMODX_H
|
|
||||||
|
|
||||||
#if defined PLATFORM_POSIX
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "sclinux.h"
|
|
||||||
#endif
|
|
||||||
#include <ctype.h> //tolower, etc
|
|
||||||
#include "string.h"
|
|
||||||
#include <extdll.h>
|
|
||||||
#include <meta_api.h>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
// MSVC8 - replace POSIX functions with ISO C++ conformant ones as they are deprecated
|
|
||||||
#if _MSC_VER >= 1400
|
|
||||||
#define unlink _unlink
|
|
||||||
#define mkdir _mkdir
|
|
||||||
#define strdup _strdup
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "hashing.h"
|
|
||||||
#include "modules.h"
|
|
||||||
#include "CPlugin.h"
|
|
||||||
#include "CLibrarySys.h"
|
|
||||||
#include <auto-string.h>
|
|
||||||
#include <amtl/am-string.h>
|
|
||||||
#include <amtl/am-vector.h>
|
|
||||||
#include <amtl/am-inlinelist.h>
|
|
||||||
#include "CMisc.h"
|
|
||||||
#include "CVault.h"
|
|
||||||
#include "CModule.h"
|
|
||||||
#include "CTask.h"
|
|
||||||
#include "CLogEvent.h"
|
|
||||||
#include "CForward.h"
|
|
||||||
#include "CCmd.h"
|
|
||||||
#include "CEvent.h"
|
|
||||||
#include "CLang.h"
|
|
||||||
#include "fakemeta.h"
|
|
||||||
#include "amxxlog.h"
|
|
||||||
#include "CvarManager.h"
|
|
||||||
#include "CoreConfig.h"
|
|
||||||
#include "CFrameAction.h"
|
|
||||||
#include <amxmodx_version.h>
|
|
||||||
#include <HLTypeConversion.h>
|
|
||||||
|
|
||||||
#define AMXXLOG_Log g_log.Log
|
|
||||||
#define AMXXLOG_Error g_log.LogError
|
|
||||||
|
|
||||||
extern AMX_NATIVE_INFO core_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO time_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO power_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO amxmodx_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO file_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO float_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO string_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO vault_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO msg_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO vector_Natives[];
|
|
||||||
extern AMX_NATIVE_INFO g_SortNatives[];
|
|
||||||
extern AMX_NATIVE_INFO g_DataStructNatives[];
|
|
||||||
extern AMX_NATIVE_INFO g_StackNatives[];
|
|
||||||
extern AMX_NATIVE_INFO g_TextParserNatives[];
|
|
||||||
extern AMX_NATIVE_INFO g_CvarNatives[];
|
|
||||||
extern AMX_NATIVE_INFO g_GameConfigNatives[];
|
|
||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
#define DLLOAD(path) (DLHANDLE)LoadLibrary(path)
|
|
||||||
#define DLPROC(m, func) GetProcAddress(m, func)
|
|
||||||
#define DLFREE(m) FreeLibrary(m)
|
|
||||||
#else
|
|
||||||
#define DLLOAD(path) (DLHANDLE)dlopen(path, RTLD_NOW)
|
|
||||||
#define DLPROC(m, func) dlsym(m, func)
|
|
||||||
#define DLFREE(m) dlclose(m)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined __GNUC__
|
|
||||||
#include <stdint.h>
|
|
||||||
typedef intptr_t _INT_PTR;
|
|
||||||
#else
|
|
||||||
#if defined AMD64
|
|
||||||
typedef __int64 _INT_PTR;
|
|
||||||
#else
|
|
||||||
typedef __int32 _INT_PTR;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
|
||||||
typedef HINSTANCE DLHANDLE;
|
|
||||||
#else
|
|
||||||
typedef void* DLHANDLE;
|
|
||||||
#define INFINITE 0xFFFFFFFF
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GETPLAYERAUTHID
|
|
||||||
#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId)
|
|
||||||
#endif
|
|
||||||
#define ANGLEVECTORS (*g_engfuncs.pfnAngleVectors)
|
|
||||||
#define CLIENT_PRINT (*g_engfuncs.pfnClientPrintf)
|
|
||||||
#define CVAR_DIRECTSET (*g_engfuncs.pfnCvar_DirectSet)
|
|
||||||
#define GETCLIENTLISTENING (*g_engfuncs.pfnVoice_GetClientListening)
|
|
||||||
#define RUNPLAYERMOVE (*g_engfuncs.pfnRunPlayerMove)
|
|
||||||
#define SETCLIENTLISTENING (*g_engfuncs.pfnVoice_SetClientListening)
|
|
||||||
#define SETCLIENTMAXSPEED (*g_engfuncs.pfnSetClientMaxspeed)
|
|
||||||
|
|
||||||
#define MAX_BUFFER_LENGTH 16384
|
|
||||||
|
|
||||||
char* UTIL_SplitHudMessage(register const char *src);
|
|
||||||
int UTIL_ReadFlags(const char* c);
|
|
||||||
|
|
||||||
void UTIL_ClientPrint(edict_t *pEntity, int msg_dest, char *msg);
|
|
||||||
void UTIL_FakeClientCommand(edict_t *pEdict, const char *cmd, const char *arg1 = NULL, const char *arg2 = NULL, bool fwd = false);
|
|
||||||
void UTIL_GetFlags(char* flags, int flag);
|
|
||||||
void UTIL_HudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage);
|
|
||||||
void UTIL_DHudMessage(edict_t *pEntity, const hudtextparms_t &textparms, const char *pMessage, unsigned int length);
|
|
||||||
void UTIL_IntToString(int value, char *output);
|
|
||||||
void UTIL_ShowMOTD(edict_t *client, char *motd, int mlen, const char *name);
|
|
||||||
void UTIL_ShowMenu(edict_t* pEntity, int slots, int time, char *menu, int mlen);
|
|
||||||
void UTIL_ClientSayText(edict_t *pEntity, int sender, char *msg);
|
|
||||||
void UTIL_TeamInfo(edict_t *pEntity, int playerIndex, const char *pszTeamName);
|
|
||||||
|
|
||||||
template <typename D> int UTIL_CheckValidChar(D *c);
|
|
||||||
template <typename D, typename S> unsigned int strncopy(D *dest, const S *src, size_t count);
|
|
||||||
unsigned int UTIL_GetUTF8CharBytes(const char *stream);
|
|
||||||
size_t UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, const char *replace, bool caseSensitive);
|
|
||||||
size_t UTIL_ReplaceAll(char *subject, size_t maxlength, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive);
|
|
||||||
char *UTIL_ReplaceEx(char *subject, size_t maxLen, const char *search, size_t searchLen, const char *replace, size_t replaceLen, bool caseSensitive);
|
|
||||||
void UTIL_TrimLeft(char *buffer);
|
|
||||||
void UTIL_TrimRight(char *buffer);
|
|
||||||
|
|
||||||
char* utf8stristr(const char *string1, const char *string2);
|
|
||||||
int utf8strncasecmp(const char *string1, const char *string2, size_t n);
|
|
||||||
int utf8strcasecmp(const char *string1, const char *string2);
|
|
||||||
|
|
||||||
#define GET_PLAYER_POINTER(e) (&g_players[ENTINDEX(e)])
|
|
||||||
//#define GET_PLAYER_POINTER(e) (&g_players[(((int)e-g_edict_point)/sizeof(edict_t))])
|
|
||||||
#define GET_PLAYER_POINTER_I(i) (&g_players[i])
|
|
||||||
|
|
||||||
struct WeaponsVault
|
|
||||||
{
|
|
||||||
ke::AString fullName;
|
|
||||||
short int iId;
|
|
||||||
short int ammoSlot;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fakecmd_t
|
|
||||||
{
|
|
||||||
char args[256];
|
|
||||||
const char *argv[3];
|
|
||||||
int argc;
|
|
||||||
bool fake;
|
|
||||||
bool notify; // notify to plugins.
|
|
||||||
};
|
|
||||||
|
|
||||||
extern CLog g_log;
|
|
||||||
extern CPluginMngr g_plugins;
|
|
||||||
extern CTaskMngr g_tasksMngr;
|
|
||||||
extern CFrameActionMngr g_frameActionMngr;
|
|
||||||
extern CPlayer g_players[33];
|
|
||||||
extern CPlayer* mPlayer;
|
|
||||||
extern CmdMngr g_commands;
|
|
||||||
extern ke::Vector<ke::AutoPtr<ForceObject>> g_forcemodels;
|
|
||||||
extern ke::Vector<ke::AutoPtr<ForceObject>> g_forcesounds;
|
|
||||||
extern ke::Vector<ke::AutoPtr<ForceObject>> g_forcegeneric;
|
|
||||||
extern ke::Vector<ke::AutoPtr<CPlayer *>> g_auth;
|
|
||||||
extern ke::InlineList<CModule> g_modules;
|
|
||||||
extern ke::InlineList<CScript> g_loadedscripts;
|
|
||||||
extern EventsMngr g_events;
|
|
||||||
extern Grenades g_grenades;
|
|
||||||
extern LogEventsMngr g_logevents;
|
|
||||||
extern CLangMngr g_langMngr;
|
|
||||||
extern ke::AString g_log_dir;
|
|
||||||
extern ke::AString g_mod_name;
|
|
||||||
extern TeamIds g_teamsIds;
|
|
||||||
extern Vault g_vault;
|
|
||||||
extern CForwardMngr g_forwards;
|
|
||||||
extern WeaponsVault g_weaponsData[MAX_WEAPONS];
|
|
||||||
extern XVars g_xvars;
|
|
||||||
extern bool g_bmod_cstrike;
|
|
||||||
extern bool g_bmod_dod;
|
|
||||||
extern bool g_bmod_dmc;
|
|
||||||
extern bool g_bmod_ricochet;
|
|
||||||
extern bool g_bmod_valve;
|
|
||||||
extern bool g_bmod_gearbox;
|
|
||||||
extern bool g_official_mod;
|
|
||||||
extern bool g_dontprecache;
|
|
||||||
extern int g_srvindex;
|
|
||||||
extern cvar_t* amxmodx_version;
|
|
||||||
extern cvar_t* amxmodx_language;
|
|
||||||
extern cvar_t* hostname;
|
|
||||||
extern cvar_t* mp_timelimit;
|
|
||||||
extern fakecmd_t g_fakecmd;
|
|
||||||
extern float g_game_restarting;
|
|
||||||
extern float g_game_timeleft;
|
|
||||||
extern float g_task_time;
|
|
||||||
extern float g_auth_time;
|
|
||||||
extern bool g_NewDLL_Available;
|
|
||||||
extern hudtextparms_t g_hudset;
|
|
||||||
//extern int g_edict_point;
|
|
||||||
extern int g_players_num;
|
|
||||||
extern int mPlayerIndex;
|
|
||||||
extern int mState;
|
|
||||||
extern void (*endfunction)(void*);
|
|
||||||
extern void (*function)(void*);
|
|
||||||
|
|
||||||
typedef void (*funEventCall)(void*);
|
|
||||||
extern funEventCall modMsgsEnd[MAX_REG_MSGS];
|
|
||||||
extern funEventCall modMsgs[MAX_REG_MSGS];
|
|
||||||
|
|
||||||
extern int gmsgAmmoPickup;
|
|
||||||
extern int gmsgAmmoX;
|
|
||||||
extern int gmsgBattery;
|
|
||||||
extern int gmsgCurWeapon;
|
|
||||||
extern int gmsgDamage;
|
|
||||||
extern int gmsgDeathMsg;
|
|
||||||
extern int gmsgHealth;
|
|
||||||
extern int gmsgMOTD;
|
|
||||||
extern int gmsgScoreInfo;
|
|
||||||
extern int gmsgSendAudio;
|
|
||||||
extern int gmsgServerName;
|
|
||||||
extern int gmsgShowMenu;
|
|
||||||
extern int gmsgTeamInfo;
|
|
||||||
extern int gmsgTextMsg;
|
|
||||||
extern int gmsgVGUIMenu;
|
|
||||||
extern int gmsgWeapPickup;
|
|
||||||
extern int gmsgWeaponList;
|
|
||||||
extern int gmsgintermission;
|
|
||||||
extern int gmsgResetHUD;
|
|
||||||
extern int gmsgRoundTime;
|
|
||||||
extern int gmsgSayText;
|
|
||||||
extern int gmsgInitHUD;
|
|
||||||
|
|
||||||
void Client_AmmoPickup(void*);
|
|
||||||
void Client_AmmoX(void*);
|
|
||||||
void Client_CurWeapon(void*);
|
|
||||||
void Client_ScoreInfo(void*);
|
|
||||||
void Client_ShowMenu(void*);
|
|
||||||
void Client_TeamInfo(void*);
|
|
||||||
void Client_TextMsg(void*);
|
|
||||||
void Client_VGUIMenu(void*);
|
|
||||||
void Client_WeaponList(void*);
|
|
||||||
void Client_DamageEnd(void*);
|
|
||||||
void Client_DeathMsg(void*);
|
|
||||||
void Client_InitHUDEnd(void*);
|
|
||||||
|
|
||||||
void amx_command();
|
|
||||||
void plugin_srvcmd();
|
|
||||||
|
|
||||||
const char* stristr(const char* a, const char* b);
|
|
||||||
char *strptime(const char *buf, const char *fmt, struct tm *tm, short addthem);
|
|
||||||
|
|
||||||
int loadModules(const char* filename, PLUG_LOADTIME now);
|
|
||||||
void detachModules();
|
|
||||||
void detachReloadModules();
|
|
||||||
|
|
||||||
// Count modules
|
|
||||||
enum CountModulesMode
|
|
||||||
{
|
|
||||||
CountModules_Running = 0,
|
|
||||||
CountModules_All,
|
|
||||||
CountModules_Stopped
|
|
||||||
};
|
|
||||||
|
|
||||||
int countModules(CountModulesMode mode);
|
|
||||||
void modules_callPluginsLoaded();
|
|
||||||
void modules_callPluginsUnloaded();
|
|
||||||
void modules_callPluginsUnloading();
|
|
||||||
|
|
||||||
cell* get_amxaddr(AMX *amx, cell amx_addr);
|
|
||||||
char* build_pathname(const char *fmt, ...);
|
|
||||||
char* build_pathname_r(char *buffer, size_t maxlen, const char *fmt, ...);
|
|
||||||
char* format_amxstring(AMX *amx, cell *params, int parm, int& len);
|
|
||||||
AMX* get_amxscript(int, void**, const char**);
|
|
||||||
const char* get_amxscriptname(AMX* amx);
|
|
||||||
char* get_amxstring(AMX *amx, cell amx_addr, int id, int& len);
|
|
||||||
char* get_amxstring_null(AMX *amx, cell amx_addr, int id, int& len);
|
|
||||||
cell* get_amxvector_null(AMX *amx, cell amx_addr);
|
|
||||||
extern "C" size_t get_amxstring_r(AMX *amx, cell amx_addr, char *destination, int maxlen);
|
|
||||||
|
|
||||||
int amxstring_len(cell* cstr);
|
|
||||||
int load_amxscript(AMX* amx, void** program, const char* path, char error[64], int debug);
|
|
||||||
int load_amxscript_ex(AMX* amx, void** program, const char* path, char *error, size_t maxLength, int debug);
|
|
||||||
int set_amxnatives(AMX* amx, char error[64]);
|
|
||||||
int set_amxstring(AMX *amx, cell amx_addr, const char *source, int max);
|
|
||||||
int set_amxstring_simple(cell *dest, const char *source, int max);
|
|
||||||
template <typename T> int set_amxstring_utf8(AMX *amx, cell amx_addr, const T *source, size_t sourcelen, size_t maxlen);
|
|
||||||
int set_amxstring_utf8_char(AMX *amx, cell amx_addr, const char *source, size_t sourcelen, size_t maxlen);
|
|
||||||
int set_amxstring_utf8_cell(AMX *amx, cell amx_addr, const cell *source, size_t sourcelen, size_t maxlen);
|
|
||||||
int unload_amxscript(AMX* amx, void** program);
|
|
||||||
|
|
||||||
void copy_amxmemory(cell* dest, cell* src, int len);
|
|
||||||
void get_modname(char*);
|
|
||||||
void print_srvconsole(const char *fmt, ...);
|
|
||||||
void report_error(int code, const char* fmt, ...);
|
|
||||||
// get_localinfo
|
|
||||||
const char* get_localinfo(const char* name, const char* def);
|
|
||||||
extern "C" void LogError(AMX *amx, int err, const char *fmt, ...);
|
|
||||||
|
|
||||||
enum ModuleCallReason
|
|
||||||
{
|
|
||||||
ModuleCall_NotCalled = 0, // nothing
|
|
||||||
ModuleCall_Query, // in Query func
|
|
||||||
ModuleCall_Attach, // in Attach func
|
|
||||||
ModuleCall_Detach, // in Detach func
|
|
||||||
};
|
|
||||||
|
|
||||||
extern ModuleCallReason g_ModuleCallReason; // modules.cpp
|
|
||||||
extern CModule *g_CurrentlyCalledModule; // modules.cpp
|
|
||||||
extern const char *g_LastRequestedFunc; // modules.cpp
|
|
||||||
|
|
||||||
void Module_CacheFunctions();
|
|
||||||
void Module_UncacheFunctions();
|
|
||||||
|
|
||||||
void *Module_ReqFnptr(const char *funcName); // modules.cpp
|
|
||||||
|
|
||||||
// standard forwards
|
|
||||||
// defined in meta_api.cpp
|
|
||||||
extern int FF_ClientCommand;
|
|
||||||
extern int FF_ClientConnect;
|
|
||||||
extern int FF_ClientDisconnect;
|
|
||||||
extern int FF_ClientInfoChanged;
|
|
||||||
extern int FF_ClientPutInServer;
|
|
||||||
extern int FF_PluginInit;
|
|
||||||
extern int FF_PluginCfg;
|
|
||||||
extern int FF_PluginPrecache;
|
|
||||||
extern int FF_PluginLog;
|
|
||||||
extern int FF_PluginEnd;
|
|
||||||
extern int FF_InconsistentFile;
|
|
||||||
extern int FF_ClientAuthorized;
|
|
||||||
extern int FF_ChangeLevel;
|
|
||||||
extern int FF_ClientConnectEx;
|
|
||||||
|
|
||||||
extern bool g_coloredmenus;
|
|
||||||
|
|
||||||
typedef void (*AUTHORIZEFUNC)(int player, const char *authstring);
|
|
||||||
|
|
||||||
#define MM_CVAR2_VERS 13
|
|
||||||
|
|
||||||
struct func_s
|
|
||||||
{
|
|
||||||
void *pfn;
|
|
||||||
const char *desc;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum AdminProperty
|
|
||||||
{
|
|
||||||
Admin_Auth = 0,
|
|
||||||
Admin_Password,
|
|
||||||
Admin_Access,
|
|
||||||
Admin_Flags
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PrintColor
|
|
||||||
{
|
|
||||||
print_team_default = 0,
|
|
||||||
print_team_grey =-1,
|
|
||||||
print_team_red = -2,
|
|
||||||
print_team_blue = -3,
|
|
||||||
};
|
|
||||||
|
|
||||||
extern enginefuncs_t *g_pEngTable;
|
|
||||||
extern HLTypeConversion TypeConversion;
|
|
||||||
|
|
||||||
#endif // AMXMODX_H
|
|
@ -2,6 +2,8 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) ITB CompuPhase, 2001-2002
|
* Copyright (c) ITB CompuPhase, 2001-2002
|
||||||
* This file may be freely used. No warranties of any kind.
|
* This file may be freely used. No warranties of any kind.
|
||||||
|
*
|
||||||
|
* Version: $Id$
|
||||||
*/
|
*/
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@ -9,20 +11,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
# ifndef CLK_TCK
|
|
||||||
# define CLK_TCK CLOCKS_PER_SEC
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
// this file does not include amxmodx.h, so we have to include the memory manager here
|
|
||||||
#ifdef MEMORY_TEST
|
|
||||||
#include "mmgr/mmgr.h"
|
|
||||||
#endif // MEMORY_TEST
|
|
||||||
|
|
||||||
#include "amx.h"
|
#include "amx.h"
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
@ -52,7 +40,7 @@ static cell AMX_NATIVE_CALL _time(AMX *amx, cell *params)
|
|||||||
/* the time() function returns the number of seconds since January 1 1970
|
/* the time() function returns the number of seconds since January 1 1970
|
||||||
* in Universal Coordinated Time (the successor to Greenwich Mean Time)
|
* in Universal Coordinated Time (the successor to Greenwich Mean Time)
|
||||||
*/
|
*/
|
||||||
return (cell)sec1970;
|
return sec1970;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
@ -1,353 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "amxxfile.h"
|
|
||||||
#include "zlib/zlib.h"
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
****** AMXXFILE ******
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
#if defined __GNUC__
|
|
||||||
#define PACKED __attribute__((packed))
|
|
||||||
#else
|
|
||||||
#define PACKED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
|
||||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
|
||||||
#else
|
|
||||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
|
||||||
#if defined __TURBOC__
|
|
||||||
#pragma option -a- /* "pack" pragma for older Borland compilers */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct TableEntry
|
|
||||||
{
|
|
||||||
mint8_t cellSize;
|
|
||||||
mint32_t origSize PACKED; // contains AMX_HEADER->stp
|
|
||||||
mint32_t offset PACKED;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define DATAREAD(addr, itemsize, itemcount) \
|
|
||||||
if (fread((addr), (itemsize), (itemcount), (m_pFile)) != (itemcount)) \
|
|
||||||
{ \
|
|
||||||
if (feof(m_pFile)) \
|
|
||||||
m_Status = Err_FileInvalid; \
|
|
||||||
else \
|
|
||||||
m_Status = Err_FileRead; \
|
|
||||||
fclose(m_pFile); \
|
|
||||||
m_pFile = NULL; \
|
|
||||||
return; \
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmxxReader::CAmxxReader(const char *filename, int cellsize)
|
|
||||||
{
|
|
||||||
m_Bh.plugins = NULL;
|
|
||||||
m_AmxxFile = false;
|
|
||||||
|
|
||||||
if (!filename)
|
|
||||||
{
|
|
||||||
m_Status = Err_InvalidParam;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Status = Err_None;
|
|
||||||
m_CellSize = cellsize;
|
|
||||||
m_pFile = fopen(filename, "rb");
|
|
||||||
|
|
||||||
if (!m_pFile)
|
|
||||||
{
|
|
||||||
m_Status = Err_FileOpen;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mint32_t magic;
|
|
||||||
DATAREAD(&magic, sizeof(magic), 1);
|
|
||||||
|
|
||||||
m_OldFile = false;
|
|
||||||
|
|
||||||
if (magic == 0x524C4542)
|
|
||||||
{
|
|
||||||
//we have an invalid, old, RLEB file
|
|
||||||
m_Status = Err_OldFile;
|
|
||||||
fclose(m_pFile);
|
|
||||||
m_pFile = NULL;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (magic == MAGIC_HEADER2)
|
|
||||||
{
|
|
||||||
DATAREAD(&m_Bh.version, sizeof(int16_t), 1);
|
|
||||||
|
|
||||||
if (m_Bh.version > MAGIC_VERSION)
|
|
||||||
{
|
|
||||||
m_Status = Err_OldFile;
|
|
||||||
fclose(m_pFile);
|
|
||||||
m_pFile = NULL;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_AmxxFile = true;
|
|
||||||
DATAREAD(&m_Bh.numPlugins, sizeof(mint8_t), 1);
|
|
||||||
m_Bh.plugins = new PluginEntry[m_Bh.numPlugins];
|
|
||||||
PluginEntry *pe;
|
|
||||||
m_SectionHdrOffset = 0;
|
|
||||||
m_Entry = -1;
|
|
||||||
|
|
||||||
for (mint8_t i = 0; i < m_Bh.numPlugins; i++)
|
|
||||||
{
|
|
||||||
pe = &(m_Bh.plugins[(unsigned)i]);
|
|
||||||
DATAREAD(&pe->cellsize, sizeof(mint8_t), 1);
|
|
||||||
DATAREAD(&pe->disksize, sizeof(int32_t), 1);
|
|
||||||
DATAREAD(&pe->imagesize, sizeof(int32_t), 1);
|
|
||||||
DATAREAD(&pe->memsize, sizeof(int32_t), 1);
|
|
||||||
DATAREAD(&pe->offs, sizeof(int32_t), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (mint8_t i = 0; i < m_Bh.numPlugins; i++)
|
|
||||||
{
|
|
||||||
pe = &(m_Bh.plugins[(unsigned)i]);
|
|
||||||
|
|
||||||
if (pe->cellsize == m_CellSize)
|
|
||||||
{
|
|
||||||
m_Entry = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Entry == -1)
|
|
||||||
{
|
|
||||||
m_Status = Err_SectionNotFound;
|
|
||||||
fclose(m_pFile);
|
|
||||||
m_pFile = NULL;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pe = &(m_Bh.plugins[m_Entry]);
|
|
||||||
m_SectionLength = pe->disksize;
|
|
||||||
}
|
|
||||||
else if (magic == MAGIC_HEADER)
|
|
||||||
{
|
|
||||||
// try to find the section
|
|
||||||
mint8_t numOfPlugins;
|
|
||||||
DATAREAD(&numOfPlugins, sizeof(numOfPlugins), 1);
|
|
||||||
|
|
||||||
TableEntry entry;
|
|
||||||
|
|
||||||
m_SectionHdrOffset = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < static_cast<int>(numOfPlugins); ++i)
|
|
||||||
{
|
|
||||||
DATAREAD(&entry, sizeof(entry), 1);
|
|
||||||
if (entry.cellSize == m_CellSize)
|
|
||||||
{
|
|
||||||
m_SectionHdrOffset = ftell(m_pFile) - sizeof(entry);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_SectionHdrOffset)
|
|
||||||
{
|
|
||||||
m_Status = Err_SectionNotFound;
|
|
||||||
fclose(m_pFile);
|
|
||||||
m_pFile = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute section length
|
|
||||||
if ((i + 1) < static_cast<int>(numOfPlugins))
|
|
||||||
{
|
|
||||||
// there is a next section
|
|
||||||
TableEntry nextEntry;
|
|
||||||
DATAREAD(&nextEntry, sizeof(nextEntry), 1);
|
|
||||||
m_SectionLength = nextEntry.offset - entry.offset;
|
|
||||||
} else {
|
|
||||||
fseek(m_pFile, 0, SEEK_END);
|
|
||||||
m_SectionLength = ftell(m_pFile) - (long)entry.offset;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// check for old file
|
|
||||||
AMX_HEADER hdr;
|
|
||||||
rewind(m_pFile);
|
|
||||||
fread(&hdr, sizeof(hdr), 1, m_pFile);
|
|
||||||
amx_Align16(&hdr.magic);
|
|
||||||
|
|
||||||
if (hdr.magic == AMX_MAGIC)
|
|
||||||
{
|
|
||||||
if (cellsize != 4)
|
|
||||||
{
|
|
||||||
m_Status = Err_SectionNotFound;
|
|
||||||
fclose(m_pFile);
|
|
||||||
m_pFile = NULL;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_OldFile = true;
|
|
||||||
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// no known file format
|
|
||||||
m_Status = Err_FileInvalid;
|
|
||||||
fclose(m_pFile);
|
|
||||||
m_pFile = NULL;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmxxReader::~CAmxxReader()
|
|
||||||
{
|
|
||||||
if (m_pFile)
|
|
||||||
{
|
|
||||||
fclose(m_pFile);
|
|
||||||
m_pFile = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Bh.plugins)
|
|
||||||
{
|
|
||||||
delete [] m_Bh.plugins;
|
|
||||||
m_Bh.plugins = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmxxReader::Error CAmxxReader::GetStatus()
|
|
||||||
{
|
|
||||||
return m_Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef DATAREAD
|
|
||||||
#define DATAREAD(addr, itemsize, itemcount) \
|
|
||||||
if (fread(addr, itemsize, itemcount, m_pFile) != itemcount) \
|
|
||||||
{ \
|
|
||||||
if (feof(m_pFile)) \
|
|
||||||
m_Status = Err_FileInvalid; \
|
|
||||||
else \
|
|
||||||
m_Status = Err_FileRead; \
|
|
||||||
fclose(m_pFile); \
|
|
||||||
m_pFile = NULL; \
|
|
||||||
return 0; \
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CAmxxReader::GetBufferSize()
|
|
||||||
{
|
|
||||||
if (!m_pFile)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
long save = ftell(m_pFile);
|
|
||||||
|
|
||||||
if (m_OldFile)
|
|
||||||
{
|
|
||||||
rewind(m_pFile);
|
|
||||||
AMX_HEADER hdr;
|
|
||||||
DATAREAD(&hdr, sizeof(hdr), 1);
|
|
||||||
fseek(m_pFile, save, SEEK_SET);
|
|
||||||
|
|
||||||
return hdr.stp;
|
|
||||||
}
|
|
||||||
else if (m_AmxxFile)
|
|
||||||
{
|
|
||||||
PluginEntry *pe = &(m_Bh.plugins[m_Entry]);
|
|
||||||
|
|
||||||
if (pe->imagesize > pe->memsize)
|
|
||||||
return pe->imagesize + 1;
|
|
||||||
|
|
||||||
return pe->memsize + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fseek(m_pFile, m_SectionHdrOffset, SEEK_SET);
|
|
||||||
|
|
||||||
TableEntry entry;
|
|
||||||
DATAREAD(&entry, sizeof(entry), 1);
|
|
||||||
fseek(m_pFile, save, SEEK_SET);
|
|
||||||
|
|
||||||
return entry.origSize + 1; // +1 : safe
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef DATAREAD
|
|
||||||
#define DATAREAD(addr, itemsize, itemcount) \
|
|
||||||
if (fread(addr, itemsize, itemcount, m_pFile) != static_cast<size_t>(itemcount)) \
|
|
||||||
{ \
|
|
||||||
if (feof(m_pFile)) \
|
|
||||||
m_Status = Err_FileInvalid; \
|
|
||||||
else \
|
|
||||||
m_Status = Err_FileRead; \
|
|
||||||
fclose(m_pFile); \
|
|
||||||
m_pFile = NULL; \
|
|
||||||
return m_Status; \
|
|
||||||
}
|
|
||||||
|
|
||||||
CAmxxReader::Error CAmxxReader::GetSection(void *buffer)
|
|
||||||
{
|
|
||||||
if (!m_pFile)
|
|
||||||
return m_Status;
|
|
||||||
|
|
||||||
if (m_OldFile)
|
|
||||||
{
|
|
||||||
// get file size
|
|
||||||
fseek(m_pFile, 0, SEEK_END);
|
|
||||||
long filesize = ftell(m_pFile);
|
|
||||||
rewind(m_pFile);
|
|
||||||
DATAREAD(buffer, 1, filesize);
|
|
||||||
m_Status = Err_None;
|
|
||||||
|
|
||||||
return m_Status;
|
|
||||||
}
|
|
||||||
else if (m_AmxxFile)
|
|
||||||
{
|
|
||||||
PluginEntry *pe = &(m_Bh.plugins[m_Entry]);
|
|
||||||
char *tempBuffer = new char[m_SectionLength + 1];
|
|
||||||
fseek(m_pFile, pe->offs, SEEK_SET);
|
|
||||||
DATAREAD((void *)tempBuffer, 1, m_SectionLength);
|
|
||||||
uLongf destLen = GetBufferSize();
|
|
||||||
int result = uncompress((Bytef *)buffer, &destLen, (Bytef *)tempBuffer, m_SectionLength);
|
|
||||||
delete [] tempBuffer;
|
|
||||||
|
|
||||||
if (result != Z_OK)
|
|
||||||
{
|
|
||||||
AMXXLOG_Log("[AMXX] Zlib error encountered: %d(%d)", result, m_SectionLength);
|
|
||||||
m_Status = Err_Decompress;
|
|
||||||
return Err_Decompress;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err_None;
|
|
||||||
} else {
|
|
||||||
// new file type: go to the section table entry
|
|
||||||
fseek(m_pFile, m_SectionHdrOffset, SEEK_SET);
|
|
||||||
// go to the offset
|
|
||||||
TableEntry entry;
|
|
||||||
DATAREAD(&entry, sizeof(entry), 1);
|
|
||||||
fseek(m_pFile, entry.offset, SEEK_SET);
|
|
||||||
uLongf destLen = GetBufferSize();
|
|
||||||
// read the data to a temporary buffer
|
|
||||||
char *tempBuffer = new char[m_SectionLength + 1];
|
|
||||||
//fread(tempBuffer, sizeof(char), m_SectionLength, m_pFile);
|
|
||||||
DATAREAD((void*)tempBuffer, 1, m_SectionLength);
|
|
||||||
// decompress
|
|
||||||
int result = uncompress((Bytef *)buffer, &destLen, (Bytef *)tempBuffer, m_SectionLength);
|
|
||||||
delete [] tempBuffer;
|
|
||||||
|
|
||||||
if (result != Z_OK)
|
|
||||||
{
|
|
||||||
AMXXLOG_Log("[AMXX] Zlib error encountered: %d(%d)", result, m_SectionLength);
|
|
||||||
m_Status = Err_Decompress;
|
|
||||||
|
|
||||||
return Err_Decompress;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err_None;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef __AMXXFILE_H__
|
|
||||||
#define __AMXXFILE_H__
|
|
||||||
|
|
||||||
#define MAGIC_HEADER 0x414D5842
|
|
||||||
#define MAGIC_HEADER2 0x414D5858
|
|
||||||
#define MAGIC_VERSION 0x0300
|
|
||||||
|
|
||||||
typedef char mint8_t;
|
|
||||||
typedef int16_t mint16_t;
|
|
||||||
typedef int32_t mint32_t;
|
|
||||||
|
|
||||||
struct PluginEntry
|
|
||||||
{
|
|
||||||
mint8_t cellsize; //cell size
|
|
||||||
int32_t imagesize; //uncompressed image size
|
|
||||||
int32_t disksize; //compressed image size
|
|
||||||
int32_t memsize; //memory image size
|
|
||||||
int32_t offs; //file offset
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BinHeader
|
|
||||||
{
|
|
||||||
int32_t magic;
|
|
||||||
mint16_t version;
|
|
||||||
mint8_t numPlugins;
|
|
||||||
PluginEntry *plugins;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CAmxxReader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Error
|
|
||||||
{
|
|
||||||
Err_None=0,
|
|
||||||
Err_InvalidParam,
|
|
||||||
Err_FileOpen,
|
|
||||||
Err_FileRead,
|
|
||||||
Err_FileInvalid,
|
|
||||||
Err_SectionNotFound,
|
|
||||||
Err_DecompressorInit,
|
|
||||||
Err_Decompress,
|
|
||||||
Err_OldFile,
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
Error m_Status;
|
|
||||||
FILE *m_pFile;
|
|
||||||
|
|
||||||
bool m_OldFile; // old .amx file
|
|
||||||
bool m_AmxxFile; // new 'AMXX' header format
|
|
||||||
BinHeader m_Bh; // binary header
|
|
||||||
int m_Entry; // entry #
|
|
||||||
|
|
||||||
int m_CellSize;
|
|
||||||
int m_SectionHdrOffset; // offset to the table in the header that describes the required section
|
|
||||||
int m_SectionLength;
|
|
||||||
public:
|
|
||||||
CAmxxReader(const char *filename, int cellsize);
|
|
||||||
~CAmxxReader();
|
|
||||||
|
|
||||||
Error GetStatus(); // Get the current status
|
|
||||||
size_t GetBufferSize(); // Get the size for the buffer
|
|
||||||
Error GetSection(void *buffer); // Copy the currently selected section to the buffer
|
|
||||||
inline bool IsOldFile() const { return m_OldFile; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __AMXXFILE_H__
|
|
@ -1,268 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
// amxx_logging localinfo:
|
|
||||||
// 0 = no logging
|
|
||||||
// 1 = one logfile / day
|
|
||||||
// 2 = one logfile / map
|
|
||||||
// 3 = HL Logs
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <io.h>
|
|
||||||
#endif
|
|
||||||
#include "amxmodx.h"
|
|
||||||
|
|
||||||
#if defined(_WIN32WIN32)
|
|
||||||
#define vsnprintf _vsnprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <amxmodx_version.h>
|
|
||||||
|
|
||||||
CLog::CLog()
|
|
||||||
{
|
|
||||||
m_LogType = 0;
|
|
||||||
m_LogFile = nullptr;
|
|
||||||
m_FoundError = false;
|
|
||||||
m_LoggedErrMap = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CLog::~CLog()
|
|
||||||
{
|
|
||||||
CloseFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLog::CloseFile()
|
|
||||||
{
|
|
||||||
// log "log file closed" to old file, if any
|
|
||||||
if (m_LogFile.length())
|
|
||||||
{
|
|
||||||
FILE *fp = fopen(m_LogFile.chars(), "r");
|
|
||||||
|
|
||||||
if (fp)
|
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
fp = fopen(m_LogFile.chars(), "a+");
|
|
||||||
|
|
||||||
// get time
|
|
||||||
time_t td;
|
|
||||||
time(&td);
|
|
||||||
tm *curTime = localtime(&td);
|
|
||||||
|
|
||||||
char date[32];
|
|
||||||
strftime(date, 31, "%m/%d/%Y - %H:%M:%S", curTime);
|
|
||||||
|
|
||||||
fprintf(fp, "L %s: %s\n", date, "Log file closed.");
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_LogFile = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLog::CreateNewFile()
|
|
||||||
{
|
|
||||||
CloseFile();
|
|
||||||
|
|
||||||
// build filename
|
|
||||||
time_t td;
|
|
||||||
time(&td);
|
|
||||||
tm *curTime = localtime(&td);
|
|
||||||
|
|
||||||
char file[PLATFORM_MAX_PATH];
|
|
||||||
char name[256];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(name, sizeof(name), "%s/L%02d%02d%03d.log", g_log_dir.chars(), curTime->tm_mon + 1, curTime->tm_mday, i);
|
|
||||||
build_pathname_r(file, sizeof(file), "%s", name);
|
|
||||||
FILE *pTmpFile = fopen(file, "r"); // open for reading to check whether the file exists
|
|
||||||
|
|
||||||
if (!pTmpFile)
|
|
||||||
break;
|
|
||||||
|
|
||||||
fclose(pTmpFile);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
m_LogFile = file;
|
|
||||||
|
|
||||||
// Log logfile start
|
|
||||||
FILE *fp = fopen(m_LogFile.chars(), "w");
|
|
||||||
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
ALERT(at_logged, "[AMXX] Unexpected fatal logging error. AMXX Logging disabled.\n");
|
|
||||||
SET_LOCALINFO("amxx_logging", "0");
|
|
||||||
} else {
|
|
||||||
fprintf(fp, "AMX Mod X log file started (file \"%s\") (version \"%s\")\n", name, AMXX_VERSION);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLog::UseFile(const ke::AString &fileName)
|
|
||||||
{
|
|
||||||
static char file[PLATFORM_MAX_PATH];
|
|
||||||
m_LogFile = build_pathname_r(file, sizeof(file), "%s/%s", g_log_dir.chars(), fileName.chars());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLog::SetLogType(const char* localInfo)
|
|
||||||
{
|
|
||||||
m_LogType = atoi(get_localinfo(localInfo, "1"));
|
|
||||||
|
|
||||||
if (m_LogType < 0 || m_LogType > 3)
|
|
||||||
{
|
|
||||||
SET_LOCALINFO(localInfo, "1");
|
|
||||||
m_LogType = 1;
|
|
||||||
|
|
||||||
print_srvconsole("[AMXX] Invalid amxx_logging value; setting back to 1...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLog::MapChange()
|
|
||||||
{
|
|
||||||
// create dir if not existing
|
|
||||||
char file[PLATFORM_MAX_PATH];
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
|
||||||
mkdir(build_pathname_r(file, sizeof(file), "%s", g_log_dir.chars()), 0700);
|
|
||||||
#else
|
|
||||||
mkdir(build_pathname_r(file, sizeof(file), "%s", g_log_dir.chars()));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SetLogType("amxx_logging");
|
|
||||||
|
|
||||||
m_LoggedErrMap = false;
|
|
||||||
|
|
||||||
if (m_LogType == 2)
|
|
||||||
{
|
|
||||||
// create new logfile
|
|
||||||
CreateNewFile();
|
|
||||||
} else if (m_LogType == 1) {
|
|
||||||
Log("-------- Mapchange to %s --------", STRING(gpGlobals->mapname));
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLog::Log(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
static char file[PLATFORM_MAX_PATH];
|
|
||||||
|
|
||||||
if (m_LogType == 1 || m_LogType == 2)
|
|
||||||
{
|
|
||||||
// get time
|
|
||||||
time_t td;
|
|
||||||
time(&td);
|
|
||||||
tm *curTime = localtime(&td);
|
|
||||||
|
|
||||||
char date[32];
|
|
||||||
strftime(date, 31, "%m/%d/%Y - %H:%M:%S", curTime);
|
|
||||||
|
|
||||||
// msg
|
|
||||||
static char msg[3072];
|
|
||||||
|
|
||||||
va_list arglst;
|
|
||||||
va_start(arglst, fmt);
|
|
||||||
vsnprintf(msg, 3071, fmt, arglst);
|
|
||||||
va_end(arglst);
|
|
||||||
|
|
||||||
FILE *pF = NULL;
|
|
||||||
if (m_LogType == 2)
|
|
||||||
{
|
|
||||||
pF = fopen(m_LogFile.chars(), "a+");
|
|
||||||
if (!pF)
|
|
||||||
{
|
|
||||||
CreateNewFile();
|
|
||||||
pF = fopen(m_LogFile.chars(), "a+");
|
|
||||||
|
|
||||||
if (!pF)
|
|
||||||
{
|
|
||||||
ALERT(at_logged, "[AMXX] Unexpected fatal logging error (couldn't open %s for a+). AMXX Logging disabled for this map.\n", m_LogFile.chars());
|
|
||||||
m_LogType = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
build_pathname_r(file, sizeof(file), "%s/L%04d%02d%02d.log", g_log_dir.chars(), (curTime->tm_year + 1900), curTime->tm_mon + 1, curTime->tm_mday);
|
|
||||||
pF = fopen(file, "a+");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pF)
|
|
||||||
{
|
|
||||||
fprintf(pF, "L %s: %s\n", date, msg);
|
|
||||||
fclose(pF);
|
|
||||||
} else {
|
|
||||||
ALERT(at_logged, "[AMXX] Unexpected fatal logging error (couldn't open %s for a+). AMXX Logging disabled for this map.\n", file);
|
|
||||||
m_LogType = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print on server console
|
|
||||||
print_srvconsole("L %s: %s\n", date, msg);
|
|
||||||
} else if (m_LogType == 3) {
|
|
||||||
// build message
|
|
||||||
static char msg_[3072];
|
|
||||||
va_list arglst;
|
|
||||||
va_start(arglst, fmt);
|
|
||||||
vsnprintf(msg_, 3071, fmt, arglst);
|
|
||||||
va_end(arglst);
|
|
||||||
ALERT(at_logged, "%s\n", msg_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CLog::LogError(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
static char file[PLATFORM_MAX_PATH];
|
|
||||||
static char name[256];
|
|
||||||
|
|
||||||
if (m_FoundError)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get time
|
|
||||||
time_t td;
|
|
||||||
time(&td);
|
|
||||||
tm *curTime = localtime(&td);
|
|
||||||
|
|
||||||
char date[32];
|
|
||||||
strftime(date, 31, "%m/%d/%Y - %H:%M:%S", curTime);
|
|
||||||
|
|
||||||
// msg
|
|
||||||
static char msg[3072];
|
|
||||||
|
|
||||||
va_list arglst;
|
|
||||||
va_start(arglst, fmt);
|
|
||||||
vsnprintf(msg, sizeof(msg)-1, fmt, arglst);
|
|
||||||
va_end(arglst);
|
|
||||||
|
|
||||||
FILE *pF = NULL;
|
|
||||||
ke::SafeSprintf(name, sizeof(name), "%s/error_%04d%02d%02d.log", g_log_dir.chars(), curTime->tm_year + 1900, curTime->tm_mon + 1, curTime->tm_mday);
|
|
||||||
build_pathname_r(file, sizeof(file), "%s", name);
|
|
||||||
pF = fopen(file, "a+");
|
|
||||||
|
|
||||||
if (pF)
|
|
||||||
{
|
|
||||||
if (!m_LoggedErrMap)
|
|
||||||
{
|
|
||||||
fprintf(pF, "L %s: Start of error session.\n", date);
|
|
||||||
fprintf(pF, "L %s: Info (map \"%s\") (file \"%s\")\n", date, STRING(gpGlobals->mapname), name);
|
|
||||||
m_LoggedErrMap = true;
|
|
||||||
}
|
|
||||||
fprintf(pF, "L %s: %s\n", date, msg);
|
|
||||||
fclose(pF);
|
|
||||||
} else {
|
|
||||||
ALERT(at_logged, "[AMXX] Unexpected fatal logging error (couldn't open %s for a+). AMXX Error Logging disabled for this map.\n", file);
|
|
||||||
m_FoundError = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print on server console
|
|
||||||
print_srvconsole("L %s: %s\n", date, msg);
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef __AMXXLOG_H__
|
|
||||||
#define __AMXXLOG_H__
|
|
||||||
|
|
||||||
class CLog
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
ke::AString m_LogFile;
|
|
||||||
int m_LogType;
|
|
||||||
bool m_FoundError;
|
|
||||||
bool m_LoggedErrMap;
|
|
||||||
|
|
||||||
void GetLastFile(int &outMonth, int &outDay, ke::AString &outFilename);
|
|
||||||
void UseFile(const ke::AString &fileName);
|
|
||||||
public:
|
|
||||||
CLog();
|
|
||||||
~CLog();
|
|
||||||
|
|
||||||
void CreateNewFile();
|
|
||||||
void CloseFile();
|
|
||||||
void SetLogType(const char* localInfo);
|
|
||||||
void MapChange();
|
|
||||||
void Log(const char *fmt, ...);
|
|
||||||
void LogError(const char *fmt, ...);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // __AMXXLOG_H__
|
|
@ -1,371 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#if defined BINLOG_ENABLED
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "binlog.h"
|
|
||||||
#include "debugger.h"
|
|
||||||
|
|
||||||
BinLog g_BinLog;
|
|
||||||
int g_binlog_level = 0;
|
|
||||||
int g_binlog_maxsize = 0;
|
|
||||||
|
|
||||||
// Helper function to get a filename index
|
|
||||||
#define USHR(x) ((unsigned int)(x)>>1)
|
|
||||||
int LookupFile(AMX_DBG *amxdbg, ucell address)
|
|
||||||
{
|
|
||||||
int high, low, mid;
|
|
||||||
|
|
||||||
high = amxdbg->hdr->files;
|
|
||||||
low = -1;
|
|
||||||
|
|
||||||
while (high - low > 1)
|
|
||||||
{
|
|
||||||
mid = USHR(low + high);
|
|
||||||
if (amxdbg->filetbl[mid]->address <= address)
|
|
||||||
{
|
|
||||||
low = mid;
|
|
||||||
} else {
|
|
||||||
high = mid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (low == -1)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return low;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BinLog::Open()
|
|
||||||
{
|
|
||||||
const char *data = get_localinfo("amxmodx_datadir", "addons/amxmodx/data");
|
|
||||||
char path[PLATFORM_MAX_PATH];
|
|
||||||
build_pathname_r(path, sizeof(path), "%s/binlogs", data);
|
|
||||||
|
|
||||||
if (!DirExists(path))
|
|
||||||
{
|
|
||||||
mkdir(path
|
|
||||||
#if defined(__linux__) || defined(__APPLE__)
|
|
||||||
, 0755
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
if (!DirExists(path))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char file[PLATFORM_MAX_PATH];
|
|
||||||
build_pathname_r(file, sizeof(file), "%s/binlogs/lastlog", data);
|
|
||||||
|
|
||||||
unsigned int lastcntr = 0;
|
|
||||||
FILE *lastlog = fopen(file, "rb");
|
|
||||||
if (lastlog)
|
|
||||||
{
|
|
||||||
if (fread(&lastcntr, sizeof(int), 1, lastlog) != 1)
|
|
||||||
lastcntr = 0;
|
|
||||||
fclose(lastlog);
|
|
||||||
}
|
|
||||||
lastlog = fopen(file, "wb");
|
|
||||||
if (lastlog)
|
|
||||||
{
|
|
||||||
lastcntr++;
|
|
||||||
fwrite(&lastcntr, sizeof(int), 1, lastlog);
|
|
||||||
fclose(lastlog);
|
|
||||||
}
|
|
||||||
build_pathname_r(file, sizeof(file), "%s/binlogs/binlog%04d.blg", data, lastcntr);
|
|
||||||
m_logfile = file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* it's now safe to create the binary log
|
|
||||||
*/
|
|
||||||
FILE *fp = fopen(m_logfile.chars(), "wb");
|
|
||||||
if (!fp)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int magic = BINLOG_MAGIC;
|
|
||||||
short vers = BINLOG_VERSION;
|
|
||||||
char c = sizeof(time_t);
|
|
||||||
fwrite(&magic, sizeof(int), 1, fp);
|
|
||||||
fwrite(&vers, sizeof(short), 1, fp);
|
|
||||||
fwrite(&c, sizeof(char), 1, fp);
|
|
||||||
|
|
||||||
WritePluginDB(fp);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
m_state = true;
|
|
||||||
|
|
||||||
WriteOp(BinLog_Start, -1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinLog::Close()
|
|
||||||
{
|
|
||||||
WriteOp(BinLog_End, -1);
|
|
||||||
m_state = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinLog::WriteOp(BinLogOp op, int plug, ...)
|
|
||||||
{
|
|
||||||
if (!m_state)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FILE *fp = fopen(m_logfile.chars(), "ab");
|
|
||||||
if (!fp)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (g_binlog_maxsize && op != BinLog_End)
|
|
||||||
{
|
|
||||||
fseek(fp, 0, SEEK_END);
|
|
||||||
if (ftell(fp) > (g_binlog_maxsize * (1024 * 1024)))
|
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
Close();
|
|
||||||
Open();
|
|
||||||
fp = fopen(m_logfile.chars(), "ab");
|
|
||||||
if (!fp)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char c = static_cast<char>(op);
|
|
||||||
time_t t = time(NULL);
|
|
||||||
float gt = gpGlobals->time;
|
|
||||||
fwrite(&c, sizeof(char), 1, fp);
|
|
||||||
fwrite(&t, sizeof(time_t), 1, fp);
|
|
||||||
fwrite(>, sizeof(float), 1, fp);
|
|
||||||
fwrite(&plug, sizeof(int), 1, fp);
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, plug);
|
|
||||||
|
|
||||||
AMX *amx = NULL;
|
|
||||||
bool debug = false;
|
|
||||||
AMX_DBG *dbg = NULL;
|
|
||||||
CPluginMngr::CPlugin *pl = NULL;
|
|
||||||
|
|
||||||
if (plug != -1)
|
|
||||||
{
|
|
||||||
pl = g_plugins.findPlugin(plug);
|
|
||||||
if ((debug = pl->isDebug()))
|
|
||||||
{
|
|
||||||
amx = pl->getAMX();
|
|
||||||
dbg = static_cast<Debugger *>(amx->userdata[UD_DEBUGGER])->m_pAmxDbg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case BinLog_Registered:
|
|
||||||
{
|
|
||||||
const char *title = va_arg(ap, const char *);
|
|
||||||
const char *vers = va_arg(ap, const char *);
|
|
||||||
c = (char)strlen(title);
|
|
||||||
fwrite(&c, sizeof(char), 1, fp);
|
|
||||||
fwrite(title, sizeof(char), c+1, fp);
|
|
||||||
c = (char)strlen(vers);
|
|
||||||
fwrite(&c, sizeof(char), 1 ,fp);
|
|
||||||
fwrite(vers, sizeof(char), c+1, fp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_NativeCall:
|
|
||||||
{
|
|
||||||
int file;
|
|
||||||
int native = va_arg(ap, int);
|
|
||||||
int params = va_arg(ap, int);
|
|
||||||
fwrite(&native, sizeof(int), 1, fp);
|
|
||||||
fwrite(¶ms, sizeof(int), 1, fp);
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
file = LookupFile(dbg, amx->cip);
|
|
||||||
fwrite(&file, sizeof(int), 1, fp);
|
|
||||||
} else {
|
|
||||||
file = 0;
|
|
||||||
fwrite(&file, sizeof(int), 1, fp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_NativeRet:
|
|
||||||
{
|
|
||||||
cell retval = va_arg(ap, cell);
|
|
||||||
fwrite(&retval, sizeof(cell), 1, fp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_NativeError:
|
|
||||||
{
|
|
||||||
int err = va_arg(ap, int);
|
|
||||||
const char *msg = va_arg(ap, const char *);
|
|
||||||
short len = (short)strlen(msg);
|
|
||||||
fwrite(&err, sizeof(int), 1, fp);
|
|
||||||
fwrite(&len, sizeof(short), 1, fp);
|
|
||||||
fwrite(msg, sizeof(char), len+1, fp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_CallPubFunc:
|
|
||||||
{
|
|
||||||
int file;
|
|
||||||
int num = va_arg(ap, int);
|
|
||||||
fwrite(&num, sizeof(int), 1, fp);
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
file = LookupFile(dbg, amx->cip);
|
|
||||||
fwrite(&file, sizeof(int), 1, fp);
|
|
||||||
} else {
|
|
||||||
file = 0;
|
|
||||||
fwrite(&file, sizeof(int), 1, fp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_SetLine:
|
|
||||||
{
|
|
||||||
int file;
|
|
||||||
int line = va_arg(ap, int);
|
|
||||||
fwrite(&line, sizeof(int), 1, fp);
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
file = LookupFile(dbg, amx->cip);
|
|
||||||
fwrite(&file, sizeof(int), 1, fp);
|
|
||||||
} else {
|
|
||||||
file = 0;
|
|
||||||
fwrite(&file, sizeof(int), 1, fp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_FormatString:
|
|
||||||
{
|
|
||||||
int param = va_arg(ap, int);
|
|
||||||
int maxlen = va_arg(ap, int);
|
|
||||||
const char *str = va_arg(ap, const char *);
|
|
||||||
short len = (short)strlen(str);
|
|
||||||
fwrite(¶m, sizeof(int), 1, fp);
|
|
||||||
fwrite(&maxlen, sizeof(int), 1, fp);
|
|
||||||
fwrite(&len, sizeof(short), 1, fp);
|
|
||||||
fwrite(str, sizeof(char), len+1, fp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_NativeParams:
|
|
||||||
{
|
|
||||||
cell *params = va_arg(ap, cell *);
|
|
||||||
cell num = params[0] / sizeof(cell);
|
|
||||||
fwrite(&num, sizeof(cell), 1, fp);
|
|
||||||
for (cell i=1; i<=num; i++)
|
|
||||||
fwrite(&(params[i]), sizeof(cell), 1, fp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_GetString:
|
|
||||||
{
|
|
||||||
cell addr = va_arg(ap, cell);
|
|
||||||
const char *str = va_arg(ap, const char *);
|
|
||||||
short len = (short)strlen(str);
|
|
||||||
fwrite(&addr, sizeof(cell), 1, fp);
|
|
||||||
fwrite(&len, sizeof(short), 1, fp);
|
|
||||||
fwrite(str, sizeof(char), len+1, fp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case BinLog_SetString:
|
|
||||||
{
|
|
||||||
cell addr = va_arg(ap, cell);
|
|
||||||
int maxlen = va_arg(ap, int);
|
|
||||||
const char *str = va_arg(ap, const char *);
|
|
||||||
short len = (short)strlen(str);
|
|
||||||
fwrite(&addr, sizeof(cell), 1, fp);
|
|
||||||
fwrite(&maxlen, sizeof(int), 1, fp);
|
|
||||||
fwrite(&len, sizeof(short), 1, fp);
|
|
||||||
fwrite(str, sizeof(char), len+1, fp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
va_end(ap);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinLog::WritePluginDB(FILE *fp)
|
|
||||||
{
|
|
||||||
int num = g_plugins.getPluginsNum();
|
|
||||||
fwrite(&num, sizeof(int), 1, fp);
|
|
||||||
|
|
||||||
CPluginMngr::CPlugin *pl;
|
|
||||||
char c;
|
|
||||||
unsigned char len;
|
|
||||||
for (CPluginMngr::iterator iter = g_plugins.begin(); iter; ++iter)
|
|
||||||
{
|
|
||||||
pl = &(*iter);
|
|
||||||
if (pl->isValid())
|
|
||||||
c = 1;
|
|
||||||
else
|
|
||||||
c = 0;
|
|
||||||
if (c && pl->isDebug())
|
|
||||||
c = 2;
|
|
||||||
fwrite(&c, sizeof(char), 1, fp);
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
Debugger *pd = NULL;
|
|
||||||
len = (char)strlen(pl->getName());
|
|
||||||
fwrite(&len, sizeof(char), 1, fp);
|
|
||||||
len++;
|
|
||||||
fwrite(pl->getName(), sizeof(char), len, fp);
|
|
||||||
int natives, publics, files;
|
|
||||||
AMX *amx = pl->getAMX();
|
|
||||||
// Write the number of Filenames
|
|
||||||
if (c == 2)
|
|
||||||
{
|
|
||||||
pd = static_cast<Debugger *>(amx->userdata[UD_DEBUGGER]);
|
|
||||||
files = pd->m_pAmxDbg->hdr->files;
|
|
||||||
fwrite(&files, sizeof(int), 1, fp);
|
|
||||||
}
|
|
||||||
amx_NumNatives(amx, &natives);
|
|
||||||
amx_NumPublics(amx, &publics);
|
|
||||||
fwrite(&natives, sizeof(int), 1, fp);
|
|
||||||
fwrite(&publics, sizeof(int), 1, fp);
|
|
||||||
char name[34];
|
|
||||||
// Write the Filenames to the binfile
|
|
||||||
if (c == 2)
|
|
||||||
{
|
|
||||||
AMX_DBG_FILE **ftable = pd->m_pAmxDbg->filetbl;
|
|
||||||
for (int i=0; i<files; i++)
|
|
||||||
{
|
|
||||||
len = (char)strlen(ftable[i]->name);
|
|
||||||
fwrite(&len, sizeof(char), 1, fp);
|
|
||||||
len++;
|
|
||||||
fwrite(ftable[i]->name, sizeof(char), len, fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i=0; i<natives; i++)
|
|
||||||
{
|
|
||||||
amx_GetNative(amx, i, name);
|
|
||||||
len = (char)strlen(name);
|
|
||||||
fwrite(&len, sizeof(char), 1, fp);
|
|
||||||
len++;
|
|
||||||
fwrite(name, sizeof(char), len, fp);
|
|
||||||
}
|
|
||||||
for (int i=0; i<publics; i++)
|
|
||||||
{
|
|
||||||
amx_GetPublic(amx, i, name);
|
|
||||||
len = (char)strlen(name);
|
|
||||||
fwrite(&len, sizeof(char), 1, fp);
|
|
||||||
len++;
|
|
||||||
fwrite(name, sizeof(char), len, fp);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
char empty[] = " ";
|
|
||||||
len = 1;
|
|
||||||
fwrite(&len, sizeof(char), 1, fp);
|
|
||||||
fwrite(empty, sizeof(char), len, fp);
|
|
||||||
int no = 0;
|
|
||||||
fwrite(&no, sizeof(int), 1, fp);
|
|
||||||
fwrite(&no, sizeof(int), 1, fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //BINLOG_ENABLED
|
|
@ -1,93 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_BINLOG_H
|
|
||||||
#define _INCLUDE_BINLOG_H
|
|
||||||
|
|
||||||
#if defined BINLOG_ENABLED
|
|
||||||
|
|
||||||
#include <amtl/am-string.h>
|
|
||||||
|
|
||||||
#define BINLOG_MAGIC 0x414D424C
|
|
||||||
#define BINLOG_VERSION 0x0300
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format of binlog:
|
|
||||||
* uint32 magic
|
|
||||||
* uint16 version
|
|
||||||
* uint8 sizeof(time_t)
|
|
||||||
* uint32 num plugins
|
|
||||||
* [
|
|
||||||
* uint8 status codes
|
|
||||||
* str[int8] filename
|
|
||||||
* if(status==2)
|
|
||||||
* uint32 num filenames
|
|
||||||
* uint32 num natives
|
|
||||||
* uint32 num publics
|
|
||||||
* if (status==2)
|
|
||||||
* [
|
|
||||||
* str[uint8] file name
|
|
||||||
* ]
|
|
||||||
* [
|
|
||||||
* str[uint8] native name
|
|
||||||
* ]
|
|
||||||
* [
|
|
||||||
* str[uint8] public name
|
|
||||||
* ]
|
|
||||||
* ]
|
|
||||||
* [
|
|
||||||
* uint8 operation code
|
|
||||||
* time_t realtime
|
|
||||||
* float gametime
|
|
||||||
* int32 plugin id
|
|
||||||
* <extra info>
|
|
||||||
* ]
|
|
||||||
* If filename id is 0 skip as plugin was not in debug mode, if -1 there was an error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum BinLogOp
|
|
||||||
{
|
|
||||||
BinLog_Start=1,
|
|
||||||
BinLog_End,
|
|
||||||
BinLog_NativeCall, //<int32 native id> <int32_t num_params> <int32_t filename id>
|
|
||||||
BinLog_NativeError, //<int32 errornum> <str[int16] string>
|
|
||||||
BinLog_NativeRet, //<cell value>
|
|
||||||
BinLog_CallPubFunc, //<int32 public id> <int32_t filename id>
|
|
||||||
BinLog_SetLine, //<int32 line no#> <int32_t filename id>
|
|
||||||
BinLog_Registered, //<string title> <string version>
|
|
||||||
BinLog_FormatString, //<int32 param#> <int32 maxlen> <str[int16] string>
|
|
||||||
BinLog_NativeParams, //<int32 num> <cell ...>
|
|
||||||
BinLog_GetString, //<cell addr> <string[int16]>
|
|
||||||
BinLog_SetString, //<cell addr> <int maxlen> <string[int16]>
|
|
||||||
};
|
|
||||||
|
|
||||||
class BinLog
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BinLog() : m_state(false)
|
|
||||||
{
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
bool Open();
|
|
||||||
void Close();
|
|
||||||
void WriteOp(BinLogOp op, int plug, ...);
|
|
||||||
private:
|
|
||||||
void WritePluginDB(FILE *fp);
|
|
||||||
private:
|
|
||||||
ke::AString m_logfile;
|
|
||||||
bool m_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern BinLog g_BinLog;
|
|
||||||
extern int g_binlog_level;
|
|
||||||
extern int g_binlog_maxsize;
|
|
||||||
|
|
||||||
#endif //BINLOG_ENABLED
|
|
||||||
|
|
||||||
#endif //_INCLUDE_BINLOG_H
|
|
@ -1,729 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "CvarManager.h"
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "nongpl_matches.h"
|
|
||||||
|
|
||||||
char CVarTempBuffer[64];
|
|
||||||
const char *invis_cvar_list[5] ={ "amxmodx_version", "amxmodx_modules", "amx_debug", "amx_mldebug", "amx_client_languages" };
|
|
||||||
|
|
||||||
// create_cvar(const name[], const default_value[], flags = 0, const description[] = "", bool:has_min = false, Float:min_val = 0.0, bool:has_max = false, Float:max_val = 0.0)
|
|
||||||
static cell AMX_NATIVE_CALL create_cvar(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char* name = get_amxstring(amx, params[1], 0, length);
|
|
||||||
const char* value = get_amxstring(amx, params[2], 1, length);
|
|
||||||
const char* helpText = get_amxstring(amx, params[4], 2, length);
|
|
||||||
|
|
||||||
int flags = params[3];
|
|
||||||
|
|
||||||
CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);
|
|
||||||
|
|
||||||
if (CheckBadConList(name, 0))
|
|
||||||
{
|
|
||||||
plugin->AddToFailCounter(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags, helpText);
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
bool hasMin = params[5] != 0;
|
|
||||||
bool hasMax = params[7] != 0;
|
|
||||||
float minVal = amx_ctof(params[6]);
|
|
||||||
float maxVal = amx_ctof(params[8]);
|
|
||||||
|
|
||||||
if (hasMin && hasMax)
|
|
||||||
{
|
|
||||||
if (minVal > maxVal)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "The minimum value can not be above the maximum value");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (maxVal < minVal)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "The maximum value can not be below the minimum value");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_CvarManager.SetCvarMin(info, hasMin, minVal, plugin->getId());
|
|
||||||
g_CvarManager.SetCvarMax(info, hasMax, maxVal, plugin->getId());
|
|
||||||
|
|
||||||
return reinterpret_cast<cell>(info->var);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0)
|
|
||||||
static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char* name = get_amxstring(amx, params[1], 0, length);
|
|
||||||
const char* value = get_amxstring(amx, params[2], 1, length);
|
|
||||||
|
|
||||||
int flags = params[3];
|
|
||||||
float fvalue = amx_ctof(params[4]);
|
|
||||||
|
|
||||||
CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);
|
|
||||||
|
|
||||||
if (CheckBadConList(name, 0))
|
|
||||||
{
|
|
||||||
plugin->AddToFailCounter(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags);
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<cell>(info->var);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cvar_exists(const cvar[])
|
|
||||||
static cell AMX_NATIVE_CALL cvar_exists(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int ilen;
|
|
||||||
return (g_CvarManager.FindCvar(get_amxstring(amx, params[1], 0, ilen)) ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_cvar_pointer(const cvar[])
|
|
||||||
static cell AMX_NATIVE_CALL get_cvar_pointer(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
const char *name = get_amxstring(amx, params[1], 0, len);
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(name);
|
|
||||||
|
|
||||||
return reinterpret_cast<cell>(info ? info->var : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// hook_cvar_change(cvarHandle, const callback[])
|
|
||||||
static cell AMX_NATIVE_CALL hook_cvar_change(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t* var = reinterpret_cast<cvar_t*>(params[1]);
|
|
||||||
|
|
||||||
if (!var)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cvar handle: %p", var);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* callback;
|
|
||||||
AutoForward* forward = g_CvarManager.HookCvarChange(var, amx, params[2], &callback);
|
|
||||||
|
|
||||||
if (!forward)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Function \"%s\" is not present", callback);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reinterpret_cast<cell>(forward);
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable_cvar_hook(cvarhook:handle);
|
|
||||||
static cell AMX_NATIVE_CALL enable_cvar_hook(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
AutoForward* forward = reinterpret_cast<AutoForward*>(params[1]);
|
|
||||||
|
|
||||||
if (!forward)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cvar hook handle: %p", forward);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
forward->state = AutoForward::FSTATE_OK;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable_cvar_hook(cvarhook:handle);
|
|
||||||
static cell AMX_NATIVE_CALL disable_cvar_hook(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
AutoForward* forward = reinterpret_cast<AutoForward*>(params[1]);
|
|
||||||
|
|
||||||
if (!forward)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cvar hook handle: %p", forward);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
forward->state = AutoForward::FSTATE_STOP;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_cvar_flags(const cvar[])
|
|
||||||
static cell AMX_NATIVE_CALL get_cvar_flags(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int ilen;
|
|
||||||
char* sCvar = get_amxstring(amx, params[1], 0, ilen);
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(sCvar);
|
|
||||||
|
|
||||||
return info ? info->var->flags : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_cvar_float(const cvarname[])
|
|
||||||
static cell AMX_NATIVE_CALL get_cvar_float(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char* name = get_amxstring(amx, params[1], 0, length);
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(name);
|
|
||||||
|
|
||||||
return info ? amx_ftoc(info->var->value) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_cvar_num(const cvarname[])
|
|
||||||
static cell AMX_NATIVE_CALL get_cvar_num(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char* name = get_amxstring(amx, params[1], 0, length);
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(name);
|
|
||||||
|
|
||||||
return info ? (int)info->var->value : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_cvar_string(const cvarname[], output[], iLen)
|
|
||||||
static cell AMX_NATIVE_CALL get_cvar_string(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char* name = get_amxstring(amx, params[1], 0, length);
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(name);
|
|
||||||
|
|
||||||
const char *value = info ? info->var->string : "";
|
|
||||||
length = info ? strlen(value) : 0;
|
|
||||||
|
|
||||||
return set_amxstring_utf8(amx, params[2], value, length, params[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_cvar_flags(const cvar[], flags)
|
|
||||||
static cell AMX_NATIVE_CALL set_cvar_flags(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int ilen;
|
|
||||||
const char* sCvar = get_amxstring(amx, params[1], 0, ilen);
|
|
||||||
|
|
||||||
if (!strcmp(sCvar, "amx_version") || !strcmp(sCvar, "amxmodx_version") || !strcmp(sCvar, "fun_version") || !strcmp(sCvar, "sv_cheats"))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(sCvar);
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
info->var->flags |= (int)(params[2]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_cvar_float(const cvar[], Float:value)
|
|
||||||
static cell AMX_NATIVE_CALL set_cvar_float(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char* name = get_amxstring(amx, params[1], 0, length);
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(name);
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(CVarTempBuffer, sizeof(CVarTempBuffer), "%f", amx_ctof(params[2]));
|
|
||||||
CVAR_DIRECTSET(info->var, &CVarTempBuffer[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_cvar_num(const cvarname[], value)
|
|
||||||
static cell AMX_NATIVE_CALL set_cvar_num(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char* name = get_amxstring(amx, params[1], 0, length);
|
|
||||||
int value = params[2];
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(name);
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(CVarTempBuffer, sizeof(CVarTempBuffer), "%d", value);
|
|
||||||
CVAR_DIRECTSET(info->var, &CVarTempBuffer[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_cvar_string(const cvar[], const value[])
|
|
||||||
static cell AMX_NATIVE_CALL set_cvar_string(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char* name = get_amxstring(amx, params[1], 0, length);
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(name);
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
CVAR_DIRECTSET(info->var, get_amxstring(amx, params[2], 1, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_pcvar_flags(pcvar)
|
|
||||||
static cell AMX_NATIVE_CALL get_pcvar_flags(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ptr->flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float:get_pcvar_float(pcvar)
|
|
||||||
static cell AMX_NATIVE_CALL get_pcvar_float(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return amx_ftoc(ptr->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_pcvar_num(pcvar)
|
|
||||||
static cell AMX_NATIVE_CALL get_pcvar_num(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)ptr->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bool:get_pcvar_bool(pcvar)
|
|
||||||
static cell AMX_NATIVE_CALL get_pcvar_bool(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return !!get_pcvar_num(amx, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_pcvar_string(pcvar, string[], maxlen)
|
|
||||||
static cell AMX_NATIVE_CALL get_pcvar_string(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return set_amxstring_utf8(amx, params[2], ptr->string ? ptr->string : "", ptr->string ? strlen(ptr->string) : 0, params[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_pcvar_bounds(pcvar, CvarBounds:type, &Float:value)
|
|
||||||
static cell AMX_NATIVE_CALL get_pcvar_bounds(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name)))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasBound = false;
|
|
||||||
float bound;
|
|
||||||
|
|
||||||
switch (params[2])
|
|
||||||
{
|
|
||||||
case CvarBound_Lower:
|
|
||||||
hasBound = info->bound.hasMin;
|
|
||||||
bound = info->bound.minVal;
|
|
||||||
break;
|
|
||||||
case CvarBound_Upper:
|
|
||||||
hasBound = info->bound.hasMax;
|
|
||||||
bound = info->bound.maxVal;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CvarBounds value: %d", params[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*get_amxaddr(amx, params[3]) = amx_ftoc(bound);
|
|
||||||
|
|
||||||
return hasBound;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind_pcvar_float(pcvar, &Float:var)
|
|
||||||
static cell AMX_NATIVE_CALL bind_pcvar_float(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name)))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_CvarManager.BindCvar(info, CvarBind::CvarType_Float, amx, params[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind_pcvar_num(pcvar, &any:var)
|
|
||||||
static cell AMX_NATIVE_CALL bind_pcvar_num(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name)))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_CvarManager.BindCvar(info, CvarBind::CvarType_Int, amx, params[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind_pcvar_string(pcvar, any:var[], varlen)
|
|
||||||
static cell AMX_NATIVE_CALL bind_pcvar_string(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name)))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_CvarManager.BindCvar(info, CvarBind::CvarType_String, amx, params[2], params[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_pcvar_flags(pcvar, flags)
|
|
||||||
static cell AMX_NATIVE_CALL set_pcvar_flags(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr->flags = static_cast<int>(params[2]);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_pcvar_float(pcvar, Float:num)
|
|
||||||
static cell AMX_NATIVE_CALL set_pcvar_float(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ke::SafeSprintf(CVarTempBuffer, sizeof(CVarTempBuffer), "%f", amx_ctof(params[2]));
|
|
||||||
CVAR_DIRECTSET(ptr, &CVarTempBuffer[0]);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_pcvar_num(pcvar, num)
|
|
||||||
static cell AMX_NATIVE_CALL set_pcvar_num(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ke::SafeSprintf(CVarTempBuffer, sizeof(CVarTempBuffer), "%d", params[2]);
|
|
||||||
CVAR_DIRECTSET(ptr, &CVarTempBuffer[0]);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_pcvar_string(pcvar, const string[])
|
|
||||||
static cell AMX_NATIVE_CALL set_pcvar_string(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len;
|
|
||||||
|
|
||||||
CVAR_DIRECTSET(ptr, get_amxstring(amx, params[2], 0, len));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set_pcvar_bounds(pcvar, CvarBounds:type, bool:set, Float:value = 0.0)
|
|
||||||
static cell AMX_NATIVE_CALL set_pcvar_bounds(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cvar_t *ptr = reinterpret_cast<cvar_t *>(params[1]);
|
|
||||||
CvarInfo* info = nullptr;
|
|
||||||
|
|
||||||
if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name)))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set = params[3] != 0;
|
|
||||||
int pluginId = g_plugins.findPluginFast(amx)->getId();
|
|
||||||
float value = amx_ctof(params[4]);
|
|
||||||
|
|
||||||
switch (params[2])
|
|
||||||
{
|
|
||||||
case CvarBound_Lower:
|
|
||||||
{
|
|
||||||
if (set && info->bound.hasMax && value > info->bound.maxVal)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "The minimum value can not be above the maximum value");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_CvarManager.SetCvarMin(info, set, value, pluginId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CvarBound_Upper:
|
|
||||||
{
|
|
||||||
if (set && info->bound.hasMin && value < info->bound.minVal)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "The maximum value can not be below the minimum value");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_CvarManager.SetCvarMax(info, set, value, pluginId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CvarBounds value: %d", params[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove_cvar_flags(const cvar[], flags=-1)
|
|
||||||
static cell AMX_NATIVE_CALL remove_cvar_flags(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int ilen;
|
|
||||||
char* sCvar = get_amxstring(amx, params[1], 0, ilen);
|
|
||||||
|
|
||||||
if (!strcmp(sCvar, "amx_version") || !strcmp(sCvar, "amxmodx_version") || !strcmp(sCvar, "fun_version") || !strcmp(sCvar, "sv_cheats"))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(sCvar);
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
info->var->flags &= ~((int)(params[2]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_plugins_cvar(id, name[], namelen, &flags=0, &plugin_id=0, &pcvar_handle=0, description[]="", desc_len=0)
|
|
||||||
static cell AMX_NATIVE_CALL get_plugins_cvar(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
CvarInfo* info = g_CvarManager.FindCvar(params[1]);
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
set_amxstring(amx, params[2], info->name.chars(), params[3]);
|
|
||||||
*get_amxaddr(amx, params[4]) = info->var->flags;
|
|
||||||
*get_amxaddr(amx, params[5]) = info->pluginId;
|
|
||||||
*get_amxaddr(amx, params[6]) = reinterpret_cast<cell>(info->var);
|
|
||||||
|
|
||||||
if (*params / sizeof(cell) >= 7)
|
|
||||||
{
|
|
||||||
set_amxstring(amx, params[7], info->description.chars(), params[8]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get_plugins_cvarsnum()
|
|
||||||
static cell AMX_NATIVE_CALL get_plugins_cvarsnum(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return g_CvarManager.GetRegCvarsCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined AMD64
|
|
||||||
static bool g_warned_ccqv = false;
|
|
||||||
#endif
|
|
||||||
// query_client_cvar(id, const cvar[], const resultfunc[])
|
|
||||||
static cell AMX_NATIVE_CALL query_client_cvar(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int numParams = params[0] / sizeof(cell);
|
|
||||||
|
|
||||||
if (numParams != 3 && numParams != 5)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid number of parameters passed!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined AMD64
|
|
||||||
if (!g_warned_ccqv)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "[AMXX] Client CVAR Querying is not available on AMD64 (one time warn)");
|
|
||||||
g_warned_ccqv = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!g_NewDLL_Available)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Client CVAR querying is not enabled - check MM version!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int id = params[1];
|
|
||||||
|
|
||||||
if (id < 1 || id > gpGlobals->maxClients)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", id);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPlayer *pPlayer = GET_PLAYER_POINTER_I(id);
|
|
||||||
|
|
||||||
if (!pPlayer->initialized || pPlayer->IsBot())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Player %d is either not connected or a bot", id);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dummy;
|
|
||||||
const char *cvarname = get_amxstring(amx, params[2], 0, dummy);
|
|
||||||
const char *resultfuncname = get_amxstring(amx, params[3], 1, dummy);
|
|
||||||
|
|
||||||
// public clientcvarquery_result(id, const cvar[], const result[], [const param[]])
|
|
||||||
int iFunc;
|
|
||||||
|
|
||||||
if (numParams == 5 && params[4] != 0)
|
|
||||||
iFunc = registerSPForwardByName(amx, resultfuncname, FP_CELL, FP_STRING, FP_STRING, FP_ARRAY, FP_DONE);
|
|
||||||
else
|
|
||||||
iFunc = registerSPForwardByName(amx, resultfuncname, FP_CELL, FP_STRING, FP_STRING, FP_DONE);
|
|
||||||
|
|
||||||
if (iFunc == -1)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Function \"%s\" is not present", resultfuncname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientCvarQuery_Info *queryObject = new ClientCvarQuery_Info;
|
|
||||||
queryObject->resultFwd = iFunc;
|
|
||||||
queryObject->requestId = MAKE_REQUESTID(PLID);
|
|
||||||
|
|
||||||
if (numParams == 5 && params[4] != 0)
|
|
||||||
{
|
|
||||||
queryObject->paramLen = params[4] + 1;
|
|
||||||
queryObject->params = new cell[queryObject->paramLen];
|
|
||||||
|
|
||||||
if (!queryObject->params)
|
|
||||||
{
|
|
||||||
delete queryObject;
|
|
||||||
unregisterSPForward(iFunc);
|
|
||||||
LogError(amx, AMX_ERR_MEMORY, "Hmm. Out of memory?");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(reinterpret_cast<void*>(queryObject->params), reinterpret_cast<const void *>(get_amxaddr(amx, params[5])), queryObject->paramLen * sizeof(cell));
|
|
||||||
|
|
||||||
queryObject->params[queryObject->paramLen - 1] = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
queryObject->params = NULL;
|
|
||||||
queryObject->paramLen = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pPlayer->queries.push_back(queryObject);
|
|
||||||
|
|
||||||
QUERY_CLIENT_CVAR_VALUE2(pPlayer->pEdict, cvarname, queryObject->requestId);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AMX_NATIVE_INFO g_CvarNatives[] =
|
|
||||||
{
|
|
||||||
{"create_cvar", create_cvar},
|
|
||||||
{"register_cvar", register_cvar},
|
|
||||||
{"cvar_exists", cvar_exists},
|
|
||||||
{"get_cvar_pointer", get_cvar_pointer},
|
|
||||||
|
|
||||||
{"hook_cvar_change", hook_cvar_change},
|
|
||||||
{"enable_cvar_hook", enable_cvar_hook},
|
|
||||||
{"disable_cvar_hook", disable_cvar_hook},
|
|
||||||
|
|
||||||
{"get_cvar_flags", get_cvar_flags},
|
|
||||||
{"get_cvar_float", get_cvar_float},
|
|
||||||
{"get_cvar_num", get_cvar_num},
|
|
||||||
{"get_cvar_string", get_cvar_string},
|
|
||||||
|
|
||||||
{"set_cvar_flags", set_cvar_flags},
|
|
||||||
{"set_cvar_float", set_cvar_float},
|
|
||||||
{"set_cvar_num", set_cvar_num},
|
|
||||||
{"set_cvar_string", set_cvar_string},
|
|
||||||
|
|
||||||
{"get_pcvar_flags", get_pcvar_flags},
|
|
||||||
{"get_pcvar_float", get_pcvar_float},
|
|
||||||
{"get_pcvar_num", get_pcvar_num},
|
|
||||||
{"get_pcvar_bool", get_pcvar_bool},
|
|
||||||
{"get_pcvar_string", get_pcvar_string},
|
|
||||||
{"get_pcvar_bounds", get_pcvar_bounds},
|
|
||||||
|
|
||||||
{"set_pcvar_flags", set_pcvar_flags},
|
|
||||||
{"set_pcvar_float", set_pcvar_float},
|
|
||||||
{"set_pcvar_num", set_pcvar_num},
|
|
||||||
{"set_pcvar_bool", set_pcvar_num},
|
|
||||||
{"set_pcvar_string", set_pcvar_string},
|
|
||||||
{"set_pcvar_bounds", set_pcvar_bounds},
|
|
||||||
|
|
||||||
{"remove_cvar_flags", remove_cvar_flags},
|
|
||||||
|
|
||||||
{"bind_pcvar_float", bind_pcvar_float},
|
|
||||||
{"bind_pcvar_num", bind_pcvar_num},
|
|
||||||
{"bind_pcvar_string", bind_pcvar_string},
|
|
||||||
|
|
||||||
{"get_plugins_cvar", get_plugins_cvar},
|
|
||||||
{"get_plugins_cvarsnum", get_plugins_cvarsnum},
|
|
||||||
|
|
||||||
{"query_client_cvar", query_client_cvar},
|
|
||||||
|
|
||||||
{NULL, NULL}
|
|
||||||
};
|
|
@ -1,250 +0,0 @@
|
|||||||
/**
|
|
||||||
* vim: set ts=4 :
|
|
||||||
* =============================================================================
|
|
||||||
* SourceMod
|
|
||||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
|
||||||
* =============================================================================
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
||||||
* Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
||||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
||||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
||||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
||||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
||||||
* this exception to all derivative works. AlliedModders LLC defines further
|
|
||||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
||||||
* or <http://www.sourcemod.net/license.php>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "CDataPack.h"
|
|
||||||
|
|
||||||
NativeHandle<CDataPack> DataPackHandles;
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL CreateDataPack(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
return static_cast<cell>(DataPackHandles.create());
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL WritePackCell(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->PackCell(params[2]);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL WritePackFloat(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->PackFloat(amx_ctof(params[2]));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL WritePackString(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len;
|
|
||||||
const char *str = get_amxstring(amx, params[2], 0, len);
|
|
||||||
|
|
||||||
d->PackString(str);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ReadPackCell(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->CanReadCell())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Datapack operation is invalid.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return d->ReadCell();
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ReadPackFloat(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->CanReadFloat())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Datapack operation is invalid.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float value = d->ReadFloat();
|
|
||||||
|
|
||||||
return amx_ftoc(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ReadPackString(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->CanReadString(NULL))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Datapack operation is invalid.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len;
|
|
||||||
const char *str = d->ReadString(&len);
|
|
||||||
|
|
||||||
return set_amxstring_utf8(amx, params[2], str, len, params[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ResetPack(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->Reset();
|
|
||||||
|
|
||||||
if (params[2])
|
|
||||||
{
|
|
||||||
d->ResetSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL GetPackPosition(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<cell>(d->GetPosition());
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL SetPackPosition(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->SetPosition(params[2]))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid DataPack position, %d is out of bounds", params[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL IsPackEnded(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CDataPack *d = DataPackHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid datapack handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return d->IsReadable(1) ? false : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL DestroyDataPack(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
cell *ptr = get_amxaddr(amx, params[1]);
|
|
||||||
|
|
||||||
CDataPack *d = DataPackHandles.lookup(*ptr);
|
|
||||||
|
|
||||||
if (!d)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DataPackHandles.destroy(*ptr))
|
|
||||||
{
|
|
||||||
*ptr = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AMX_NATIVE_INFO g_DatapackNatives[] =
|
|
||||||
{
|
|
||||||
{ "CreateDataPack" , CreateDataPack },
|
|
||||||
{ "WritePackCell" , WritePackCell },
|
|
||||||
{ "WritePackFloat" , WritePackFloat },
|
|
||||||
{ "WritePackString", WritePackString },
|
|
||||||
{ "ReadPackCell" , ReadPackCell },
|
|
||||||
{ "ReadPackFloat" , ReadPackFloat },
|
|
||||||
{ "ReadPackString" , ReadPackString },
|
|
||||||
{ "ResetPack" , ResetPack },
|
|
||||||
{ "GetPackPosition", GetPackPosition },
|
|
||||||
{ "SetPackPosition", SetPackPosition },
|
|
||||||
{ "IsPackEnded" , IsPackEnded },
|
|
||||||
{ "DestroyDataPack", DestroyDataPack },
|
|
||||||
{ nullptr , nullptr}
|
|
||||||
};
|
|
@ -1,935 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "datastructs.h"
|
|
||||||
#include <amtl/am-utility.h>
|
|
||||||
|
|
||||||
NativeHandle<CellArray> ArrayHandles;
|
|
||||||
|
|
||||||
// Array:ArrayCreate(cellsize=1, reserved=32);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayCreate(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
// params[1] (cellsize) is how big in cells each element is.
|
|
||||||
// this MUST be greater than 0!
|
|
||||||
int cellsize = params[1];
|
|
||||||
|
|
||||||
// params[2] (reserved) is how many elements to allocate
|
|
||||||
// immediately when the list is created.
|
|
||||||
int reserved = params[2];
|
|
||||||
|
|
||||||
if (cellsize <= 0)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array size (%d)", cellsize);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reserved < 0)
|
|
||||||
{
|
|
||||||
reserved = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ArrayHandles.create(cellsize, reserved);
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayClear(Array:which);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayClear(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec->clear();
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArraySize(Array:which);
|
|
||||||
static cell AMX_NATIVE_CALL ArraySize(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return vec->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// native bool:ArrayResize(Array:which, newsize);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayResize(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vec->resize(params[2]))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Unable to resize array to \"%u\"", params[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native Array:ArrayClone(Array:which);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayClone(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto data = vec->clone();
|
|
||||||
|
|
||||||
if (!data)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Failed to clone array. Out of memory.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ArrayHandles.clone(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayGetArray(Array:which, item, any:output[], size = -1);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayGetArray(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = (size_t)params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->at(idx);
|
|
||||||
size_t indexes = vec->blocksize();
|
|
||||||
|
|
||||||
if (*params / sizeof(cell) == 4)
|
|
||||||
{
|
|
||||||
if (params[4] != -1 && (size_t)params[4] <= vec->blocksize())
|
|
||||||
{
|
|
||||||
indexes = params[4];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *addr = get_amxaddr(amx, params[3]);
|
|
||||||
|
|
||||||
memcpy(addr, blk, sizeof(cell) * indexes);
|
|
||||||
|
|
||||||
return indexes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native any:ArrayGetCell(Array:which, item, block = 0, bool:asChar = false);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayGetCell(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = (size_t)params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->at(idx);
|
|
||||||
|
|
||||||
if (*params / sizeof(cell) <= 2)
|
|
||||||
{
|
|
||||||
return *blk;
|
|
||||||
}
|
|
||||||
|
|
||||||
idx = (size_t)params[3];
|
|
||||||
|
|
||||||
if (!params[4])
|
|
||||||
{
|
|
||||||
if (idx >= vec->blocksize())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid block %d (blocksize: %d)", idx, vec->blocksize());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return blk[idx];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (idx >= vec->blocksize() * 4)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid byte %d (blocksize: %d bytes)", idx, vec->blocksize() * 4);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (cell)*((char *)blk + idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayGetString(Array:which, item, output[], size);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayGetString(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = (size_t)params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->at(idx);
|
|
||||||
return set_amxstring_utf8(amx, params[3], blk, amxstring_len(blk), params[4]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArraySetArray(Array:which, item, const any:input[], size =-1);
|
|
||||||
static cell AMX_NATIVE_CALL ArraySetArray(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = (size_t)params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->at(idx);
|
|
||||||
size_t indexes = vec->blocksize();
|
|
||||||
|
|
||||||
if (*params / sizeof(cell) == 4)
|
|
||||||
{
|
|
||||||
if (params[4] != -1 && (size_t)params[4] <= vec->blocksize())
|
|
||||||
{
|
|
||||||
indexes = params[4];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *addr = get_amxaddr(amx, params[3]);
|
|
||||||
|
|
||||||
memcpy(blk, addr, sizeof(cell) * indexes);
|
|
||||||
|
|
||||||
return indexes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArraySetCell(Array:which, item, any:input, block = 0, bool:asChar = false);
|
|
||||||
static cell AMX_NATIVE_CALL ArraySetCell(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = (size_t)params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->at(idx);
|
|
||||||
idx = (size_t)params[4];
|
|
||||||
|
|
||||||
if (*params / sizeof(cell) <= 3)
|
|
||||||
{
|
|
||||||
*blk = params[3];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params[5] == 0)
|
|
||||||
{
|
|
||||||
if (idx >= vec->blocksize())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid block %d (blocksize: %d)", idx, vec->blocksize());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
blk[idx] = params[3];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (idx >= vec->blocksize() * 4)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid byte %d (blocksize: %d bytes)", idx, vec->blocksize() * 4);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*((char *)blk + idx) = (char)params[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArraySetString(Array:which, item, const input[]);
|
|
||||||
static cell AMX_NATIVE_CALL ArraySetString(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = (size_t)params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->at(idx);
|
|
||||||
|
|
||||||
int len;
|
|
||||||
char *str = get_amxstring(amx, params[3], 0, len);
|
|
||||||
|
|
||||||
return strncopy(blk, str, ke::Min((size_t)len + 1, vec->blocksize()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayPushArray(Array:which, const any:input[], size = -1);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayPushArray(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->push();
|
|
||||||
|
|
||||||
if (!blk)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Failed to grow array");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *addr = get_amxaddr(amx, params[2]);
|
|
||||||
size_t indexes = vec->blocksize();
|
|
||||||
|
|
||||||
if (*params / sizeof(cell) == 3)
|
|
||||||
{
|
|
||||||
if (params[3] != -1 && (size_t)params[3] <= vec->blocksize())
|
|
||||||
{
|
|
||||||
indexes = params[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(blk, addr, sizeof(cell) * indexes);
|
|
||||||
|
|
||||||
return static_cast<cell>((vec->size() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayPushCell(Array:which, any:input);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayPushCell(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->push();
|
|
||||||
|
|
||||||
if (!blk)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Failed to grow array");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*blk = params[2];
|
|
||||||
|
|
||||||
return static_cast<cell>((vec->size() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayPushString(Array:which, const input[]);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayPushString(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *blk = vec->push();
|
|
||||||
if (!blk)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Failed to grow array");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncopy(blk, get_amxaddr(amx, params[2]), vec->blocksize());
|
|
||||||
|
|
||||||
return static_cast<cell>((vec->size() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// native DoNotUse : ArrayGetStringHandle(Array : which, item);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayGetStringHandle(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = (size_t)params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell* ptr = vec->at(idx);
|
|
||||||
|
|
||||||
if (ptr == NULL)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reinterpret_cast<cell>(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayInsertArrayAfter(Array:which, item, const any:input[]);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayInsertArrayAfter(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = params[2] + 1;
|
|
||||||
|
|
||||||
if (idx > vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertArrayAfter (%d:%d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *addr = get_amxaddr(amx, params[3]);
|
|
||||||
|
|
||||||
memcpy(vec->insert_at(idx), addr, sizeof(cell) * vec->blocksize());
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayInsertCellAfter(Array:which, item, any:input);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayInsertCellAfter(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = params[2] + 1;
|
|
||||||
|
|
||||||
if (idx > vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertCellAfter (%d:%d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*vec->insert_at(idx) = params[3];
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayInsertStringAfter(Array:which, item, const input[]);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayInsertStringAfter(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = params[2] + 1;
|
|
||||||
|
|
||||||
if (idx > vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertStringAfter (%d:%d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len;
|
|
||||||
const char *str = get_amxstring(amx, params[3], 0, len);
|
|
||||||
|
|
||||||
return strncopy(vec->insert_at(idx), str, ke::Min((size_t)len + 1, vec->blocksize()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayInsertArrayBefore(Array:which, item, const any:input[]);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayInsertArrayBefore(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertArrayBefore (%d:%d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *addr = get_amxaddr(amx, params[3]);
|
|
||||||
|
|
||||||
memcpy(vec->insert_at(idx), addr, vec->blocksize() * sizeof(cell));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayInsertCellBefore(Array:which, item, const any:input);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayInsertCellBefore(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertCellBefore (%d:%d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*vec->insert_at(idx) = params[3];
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// native ArrayInsertStringBefore(Array:which, item, const input[]);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayInsertStringBefore(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertStringBefore (%d:%d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len;
|
|
||||||
const char *str = get_amxstring(amx, params[3], 0, len);
|
|
||||||
|
|
||||||
return strncopy(vec->insert_at(idx), str, ke::Min((size_t)len + 1, vec->blocksize()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArraySwap(Array:which, item1, item2);
|
|
||||||
static cell AMX_NATIVE_CALL ArraySwap(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx1 = (size_t)params[2];
|
|
||||||
size_t idx2 = (size_t)params[3];
|
|
||||||
|
|
||||||
if (idx1 >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx1, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx2 >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx2, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec->swap(idx1, idx2);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayDeleteItem(Array:which, item);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayDeleteItem(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = (size_t)params[2];
|
|
||||||
|
|
||||||
if (idx >= vec->size())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid index %d (count: %d)", idx, vec->size());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec->remove(idx);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayDestroy(&Array:which);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayDestroy(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
cell *handle = get_amxaddr(amx, params[1]);
|
|
||||||
|
|
||||||
CellArray* vec = ArrayHandles.lookup(*handle);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ArrayHandles.destroy(*handle))
|
|
||||||
{
|
|
||||||
*handle = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct ArraySort_s
|
|
||||||
{
|
|
||||||
int func;
|
|
||||||
cell array_hndl;
|
|
||||||
cell* array_base;
|
|
||||||
cell array_bsize;
|
|
||||||
cell data;
|
|
||||||
cell size;
|
|
||||||
cell addr1;
|
|
||||||
cell addr2;
|
|
||||||
AMX *amx;
|
|
||||||
};
|
|
||||||
|
|
||||||
ArraySort_s SortInfo;
|
|
||||||
|
|
||||||
int SortArrayList(const void *elem1, const void *elem2)
|
|
||||||
{
|
|
||||||
return executeForwards(
|
|
||||||
SortInfo.func,
|
|
||||||
SortInfo.array_hndl,
|
|
||||||
((cell)((cell *)elem1 - SortInfo.array_base)) / SortInfo.array_bsize,
|
|
||||||
((cell)((cell *)elem2 - SortInfo.array_base)) / SortInfo.array_bsize,
|
|
||||||
SortInfo.data,
|
|
||||||
SortInfo.size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArraySort(Array:array, const comparefunc[], data[]="", data_size=0);
|
|
||||||
static cell AMX_NATIVE_CALL ArraySort(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
cell handle = params[1];
|
|
||||||
CellArray* vec = ArrayHandles.lookup(handle);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", handle);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len;
|
|
||||||
char* funcName = get_amxstring(amx, params[2], 0, len);
|
|
||||||
|
|
||||||
// MySortFunc(Array:array, item1, item2, const data[], data_size)
|
|
||||||
int func = registerSPForwardByName(amx, funcName, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
||||||
if (func < 0)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "The public function \"%s\" was not found.", funcName);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t arraysize = vec->size();
|
|
||||||
size_t blocksize = vec->blocksize();
|
|
||||||
cell *array = vec->base();
|
|
||||||
|
|
||||||
ArraySort_s oldinfo = SortInfo;
|
|
||||||
|
|
||||||
SortInfo.func = func;
|
|
||||||
SortInfo.array_base = array;
|
|
||||||
SortInfo.array_bsize = static_cast<cell>(blocksize);
|
|
||||||
SortInfo.array_hndl = handle;
|
|
||||||
SortInfo.data = params[3];
|
|
||||||
SortInfo.size = params[4];
|
|
||||||
|
|
||||||
qsort(array, arraysize, blocksize * sizeof(cell), SortArrayList);
|
|
||||||
|
|
||||||
SortInfo = oldinfo;
|
|
||||||
|
|
||||||
unregisterSPForward(func);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int SortArrayListExCell(const void *elem1, const void *elem2)
|
|
||||||
{
|
|
||||||
size_t index1 = ((cell)((cell *)elem1 - SortInfo.array_base)) / SortInfo.array_bsize;
|
|
||||||
size_t index2 = ((cell)((cell *)elem2 - SortInfo.array_base)) / SortInfo.array_bsize;
|
|
||||||
|
|
||||||
return executeForwards(
|
|
||||||
SortInfo.func,
|
|
||||||
SortInfo.array_hndl,
|
|
||||||
*&SortInfo.array_base[index1 * SortInfo.array_bsize],
|
|
||||||
*&SortInfo.array_base[index2 * SortInfo.array_bsize],
|
|
||||||
SortInfo.data,
|
|
||||||
SortInfo.size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
int SortArrayListExArray(const void *elem1, const void *elem2)
|
|
||||||
{
|
|
||||||
size_t index1 = ((cell)((cell *)elem1 - SortInfo.array_base)) / SortInfo.array_bsize;
|
|
||||||
size_t index2 = ((cell)((cell *)elem2 - SortInfo.array_base)) / SortInfo.array_bsize;
|
|
||||||
|
|
||||||
cell *addr1 = get_amxaddr(SortInfo.amx, SortInfo.addr1);
|
|
||||||
cell *addr2 = get_amxaddr(SortInfo.amx, SortInfo.addr2);
|
|
||||||
|
|
||||||
memcpy(addr1, &SortInfo.array_base[index1 * SortInfo.array_bsize], SortInfo.array_bsize * sizeof(cell));
|
|
||||||
memcpy(addr2, &SortInfo.array_base[index2 * SortInfo.array_bsize], SortInfo.array_bsize * sizeof(cell));
|
|
||||||
|
|
||||||
return executeForwards(
|
|
||||||
SortInfo.func,
|
|
||||||
SortInfo.array_hndl,
|
|
||||||
SortInfo.addr1,
|
|
||||||
SortInfo.addr2,
|
|
||||||
SortInfo.data,
|
|
||||||
SortInfo.size
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArraySortEx(Array:array, const comparefunc[], data[]="", data_size=0);
|
|
||||||
static cell AMX_NATIVE_CALL ArraySortEx(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int len;
|
|
||||||
char* funcName = get_amxstring(amx, params[2], 0, len);
|
|
||||||
|
|
||||||
int func = registerSPForwardByName(amx, funcName, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
||||||
|
|
||||||
if (!func)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "The public function \"%s\" was not found.", funcName);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t arraysize = vec->size();
|
|
||||||
size_t blocksize = vec->blocksize();
|
|
||||||
cell *array = vec->base();
|
|
||||||
cell amx_addr1 = 0, amx_addr2 = 0, *phys_addr = NULL;
|
|
||||||
|
|
||||||
if (blocksize > 1)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
if ((err = amx_Allot(amx, blocksize, &amx_addr1, &phys_addr)) != AMX_ERR_NONE
|
|
||||||
|| ( err = amx_Allot(amx, blocksize, &amx_addr2, &phys_addr)) != AMX_ERR_NONE)
|
|
||||||
{
|
|
||||||
LogError(amx, err, "Ran out of memory");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ArraySort_s oldinfo = SortInfo;
|
|
||||||
|
|
||||||
SortInfo.func = func;
|
|
||||||
SortInfo.array_base = array;
|
|
||||||
SortInfo.array_bsize = static_cast<cell>(blocksize);
|
|
||||||
SortInfo.array_hndl = params[1];
|
|
||||||
SortInfo.data = params[3];
|
|
||||||
SortInfo.size = params[4];
|
|
||||||
SortInfo.amx = amx;
|
|
||||||
SortInfo.addr1 = amx_addr1;
|
|
||||||
SortInfo.addr2 = amx_addr2;
|
|
||||||
|
|
||||||
qsort(array, arraysize, blocksize * sizeof(cell), blocksize > 1 ? SortArrayListExArray : SortArrayListExCell);
|
|
||||||
|
|
||||||
SortInfo = oldinfo;
|
|
||||||
|
|
||||||
if (blocksize > 1)
|
|
||||||
{
|
|
||||||
amx_Release(amx, amx_addr1);
|
|
||||||
amx_Release(amx, amx_addr2);
|
|
||||||
}
|
|
||||||
|
|
||||||
unregisterSPForward(func);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern bool fastcellcmp(cell *a, cell *b, cell len);
|
|
||||||
extern int amxstring_len(cell* a);
|
|
||||||
|
|
||||||
// native ArrayFindString(Array:which, const item[]);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayFindString(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *b, *a = get_amxaddr(amx, params[2]);
|
|
||||||
size_t cellcount = vec->blocksize();
|
|
||||||
size_t a_len = ke::Max(1, amxstring_len(a));
|
|
||||||
size_t len = a_len > cellcount ? cellcount : a_len;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < vec->size(); i++)
|
|
||||||
{
|
|
||||||
b = vec->at(i);
|
|
||||||
|
|
||||||
if (fastcellcmp(a, b, len))
|
|
||||||
{
|
|
||||||
return static_cast<cell>(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native ArrayFindValue(Array:which, any:item);
|
|
||||||
static cell AMX_NATIVE_CALL ArrayFindValue(AMX* amx, cell* params)
|
|
||||||
{
|
|
||||||
CellArray* vec = ArrayHandles.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!vec)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", params[1]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < vec->size(); i++)
|
|
||||||
{
|
|
||||||
if (params[2] == *vec->at(i))
|
|
||||||
{
|
|
||||||
return static_cast<cell>(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AMX_NATIVE_INFO g_DataStructNatives[] =
|
|
||||||
{
|
|
||||||
{ "ArrayCreate" , ArrayCreate },
|
|
||||||
{ "ArrayClear" , ArrayClear },
|
|
||||||
{ "ArrayClone" , ArrayClone },
|
|
||||||
{ "ArraySize" , ArraySize },
|
|
||||||
{ "ArrayResize" , ArrayResize },
|
|
||||||
{ "ArrayGetArray" , ArrayGetArray },
|
|
||||||
{ "ArrayGetCell" , ArrayGetCell },
|
|
||||||
{ "ArrayGetString" , ArrayGetString },
|
|
||||||
{ "ArraySetArray" , ArraySetArray },
|
|
||||||
{ "ArraySetCell" , ArraySetCell },
|
|
||||||
{ "ArraySetString" , ArraySetString },
|
|
||||||
{ "ArrayPushArray" , ArrayPushArray },
|
|
||||||
{ "ArrayPushCell" , ArrayPushCell },
|
|
||||||
{ "ArrayPushString" , ArrayPushString },
|
|
||||||
{ "ArrayInsertArrayAfter" , ArrayInsertArrayAfter },
|
|
||||||
{ "ArrayInsertCellAfter" , ArrayInsertCellAfter },
|
|
||||||
{ "ArrayInsertStringAfter" , ArrayInsertStringAfter },
|
|
||||||
{ "ArrayInsertArrayBefore" , ArrayInsertArrayBefore },
|
|
||||||
{ "ArrayInsertCellBefore" , ArrayInsertCellBefore },
|
|
||||||
{ "ArrayInsertStringBefore", ArrayInsertStringBefore },
|
|
||||||
{ "ArraySwap" , ArraySwap },
|
|
||||||
{ "ArrayDeleteItem" , ArrayDeleteItem },
|
|
||||||
{ "ArrayGetStringHandle" , ArrayGetStringHandle },
|
|
||||||
{ "ArrayDestroy" , ArrayDestroy },
|
|
||||||
{ "ArraySort" , ArraySort },
|
|
||||||
{ "ArraySortEx" , ArraySortEx },
|
|
||||||
{ "ArrayFindString" , ArrayFindString },
|
|
||||||
{ "ArrayFindValue" , ArrayFindValue },
|
|
||||||
{ nullptr , nullptr }
|
|
||||||
};
|
|
@ -1,197 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef DATASTRUCTS_H
|
|
||||||
#define DATASTRUCTS_H
|
|
||||||
|
|
||||||
#include "natives_handles.h"
|
|
||||||
|
|
||||||
class CellArray
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CellArray(size_t blocksize, size_t basesize = 0) : m_Data(nullptr), m_BlockSize(blocksize), m_AllocSize(0), m_BaseSize(basesize > 0 ? basesize : 8), m_Size(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~CellArray()
|
|
||||||
{
|
|
||||||
free(m_Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const
|
|
||||||
{
|
|
||||||
return m_Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *push()
|
|
||||||
{
|
|
||||||
if (!GrowIfNeeded(1))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
cell *arr = &m_Data[m_Size * m_BlockSize];
|
|
||||||
m_Size++;
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *at(size_t b) const
|
|
||||||
{
|
|
||||||
return &m_Data[b * m_BlockSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t blocksize() const
|
|
||||||
{
|
|
||||||
return m_BlockSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_Size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool swap(size_t item1, size_t item2)
|
|
||||||
{
|
|
||||||
/* Make sure there is extra space available */
|
|
||||||
if (!GrowIfNeeded(1))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *pri = at(item1);
|
|
||||||
cell *alt = at(item2);
|
|
||||||
|
|
||||||
/* Get our temporary array 1 after the limit */
|
|
||||||
cell *temp = &m_Data[m_Size * m_BlockSize];
|
|
||||||
|
|
||||||
memcpy(temp, pri, sizeof(cell)* m_BlockSize);
|
|
||||||
memcpy(pri, alt, sizeof(cell)* m_BlockSize);
|
|
||||||
memcpy(alt, temp, sizeof(cell)* m_BlockSize);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(size_t index)
|
|
||||||
{
|
|
||||||
/* If we're at the end, take the easy way out */
|
|
||||||
if (index == m_Size - 1)
|
|
||||||
{
|
|
||||||
m_Size--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise, it's time to move stuff! */
|
|
||||||
size_t remaining_indexes = (m_Size - 1) - index;
|
|
||||||
cell *src = at(index + 1);
|
|
||||||
cell *dest = at(index);
|
|
||||||
memmove(dest, src, sizeof(cell)* m_BlockSize * remaining_indexes);
|
|
||||||
|
|
||||||
m_Size--;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *insert_at(size_t index)
|
|
||||||
{
|
|
||||||
/* Make sure it'll fit */
|
|
||||||
if (!GrowIfNeeded(1))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* move everything up */
|
|
||||||
cell *src = at(index);
|
|
||||||
cell *dst = at(index + 1);
|
|
||||||
memmove(dst, src, sizeof(cell)* m_BlockSize * (m_Size - index));
|
|
||||||
|
|
||||||
m_Size++;
|
|
||||||
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool resize(size_t count)
|
|
||||||
{
|
|
||||||
if (count <= m_Size)
|
|
||||||
{
|
|
||||||
m_Size = count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GrowIfNeeded(count - m_Size))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Size = count;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CellArray *clone()
|
|
||||||
{
|
|
||||||
CellArray *array = new CellArray(m_BlockSize);
|
|
||||||
array->m_AllocSize = m_AllocSize;
|
|
||||||
array->m_Size = m_Size;
|
|
||||||
array->m_Data = (cell *)malloc(sizeof(cell)* m_BlockSize * m_AllocSize);
|
|
||||||
|
|
||||||
if (!array->m_Data)
|
|
||||||
{
|
|
||||||
delete array;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(array->m_Data, m_Data, sizeof(cell)* m_BlockSize * m_Size);
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *base()
|
|
||||||
{
|
|
||||||
return m_Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mem_usage()
|
|
||||||
{
|
|
||||||
return m_AllocSize * m_BlockSize * sizeof(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool GrowIfNeeded(size_t count)
|
|
||||||
{
|
|
||||||
/* Shortcut out if we can store this */
|
|
||||||
if (m_Size + count <= m_AllocSize)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/* Set a base allocation size of 8 items */
|
|
||||||
if (!m_AllocSize)
|
|
||||||
{
|
|
||||||
m_AllocSize = m_BaseSize;
|
|
||||||
}
|
|
||||||
/* If it's not enough, keep doubling */
|
|
||||||
while (m_Size + count > m_AllocSize)
|
|
||||||
{
|
|
||||||
m_AllocSize *= 2;
|
|
||||||
}
|
|
||||||
/* finally, allocate the new block */
|
|
||||||
if (m_Data)
|
|
||||||
{
|
|
||||||
m_Data = (cell *)realloc(m_Data, sizeof(cell)* m_BlockSize * m_AllocSize);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_Data = (cell *)malloc(sizeof(cell)* m_BlockSize * m_AllocSize);
|
|
||||||
}
|
|
||||||
return (m_Data != NULL);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
cell *m_Data;
|
|
||||||
size_t m_BlockSize;
|
|
||||||
size_t m_AllocSize;
|
|
||||||
size_t m_BaseSize;
|
|
||||||
size_t m_Size;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern NativeHandle<CellArray> ArrayHandles;
|
|
||||||
|
|
||||||
#endif
|
|
1025
amxmodx/debugger.cpp
1025
amxmodx/debugger.cpp
File diff suppressed because it is too large
Load Diff
@ -1,180 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_DEBUGGER_H_
|
|
||||||
#define _INCLUDE_DEBUGGER_H_
|
|
||||||
|
|
||||||
#include "amxdbg.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Third revision of the AMX Mod X Plugin Debugger.
|
|
||||||
* This final, object oriented version is safe for multiple calls and lets you
|
|
||||||
* fine-tune error handling.
|
|
||||||
* -BAILOPAN
|
|
||||||
*/
|
|
||||||
class Debugger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
class Tracer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct trace_info
|
|
||||||
{
|
|
||||||
trace_info() : cip(0), frm(0), next(NULL), prev(NULL), used(false) {};
|
|
||||||
|
|
||||||
cell cip;
|
|
||||||
cell frm;
|
|
||||||
|
|
||||||
trace_info *next;
|
|
||||||
trace_info *prev;
|
|
||||||
|
|
||||||
bool used;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
Tracer() : m_Error(0), m_pStart(NULL), m_pEnd(NULL), m_Reset(true) {};
|
|
||||||
~Tracer();
|
|
||||||
public:
|
|
||||||
void StepI(cell frm, cell cip);
|
|
||||||
void Reset();
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
Debugger::Tracer::trace_info *GetStart() const;
|
|
||||||
Debugger::Tracer::trace_info *GetEnd() const;
|
|
||||||
public:
|
|
||||||
int m_Error;
|
|
||||||
private:
|
|
||||||
trace_info *m_pStart;
|
|
||||||
trace_info *m_pEnd;
|
|
||||||
|
|
||||||
bool m_Reset;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
Debugger(AMX *pAmx, AMX_DBG *pAmxDbg) : m_pAmx(pAmx), m_pAmxDbg(pAmxDbg), m_Top(-1)
|
|
||||||
{
|
|
||||||
_CacheAmxOpcodeList();
|
|
||||||
};
|
|
||||||
~Debugger();
|
|
||||||
public:
|
|
||||||
//Begin a trace for a function
|
|
||||||
void BeginExec();
|
|
||||||
|
|
||||||
//Step through one instruction
|
|
||||||
void StepI();
|
|
||||||
|
|
||||||
//Get/set the last traced error
|
|
||||||
int GetTracedError();
|
|
||||||
void SetTracedError(int error);
|
|
||||||
|
|
||||||
//Get the first trace info of the call stack
|
|
||||||
Debugger::Tracer::trace_info *GetTraceStart() const;
|
|
||||||
|
|
||||||
//Get extra info about the call stack
|
|
||||||
bool GetTraceInfo(Debugger::Tracer::trace_info *pTraceInfo, long &line, const char *&function, const char *&file);
|
|
||||||
|
|
||||||
//Get the next trace in the call stack, NULL if none
|
|
||||||
Debugger::Tracer::trace_info *GetNextTrace(Debugger::Tracer::trace_info *pTraceInfo);
|
|
||||||
|
|
||||||
//Returns true if an error exists
|
|
||||||
bool ErrorExists();
|
|
||||||
|
|
||||||
//Formats the error message into a buffer.
|
|
||||||
//returns length of data copied, or -1 if there is no error.
|
|
||||||
int FormatError(char *buffer, size_t maxLength);
|
|
||||||
|
|
||||||
//End a trace
|
|
||||||
void EndExec();
|
|
||||||
|
|
||||||
//Reset the internal states as if the debugger was inactive
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
//Destroy internal states for shutdown
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
void DisplayTrace(const char *message);
|
|
||||||
|
|
||||||
AMX *GetAMX() const { return m_pAmx; }
|
|
||||||
public:
|
|
||||||
//generic static opcode breaker
|
|
||||||
static int AMXAPI DebugHook(AMX *amx);
|
|
||||||
|
|
||||||
static void FmtGenericMsg(AMX *amx, int error, char buffer[], size_t maxLength);
|
|
||||||
static void GenericMessage(AMX *amx, int error);
|
|
||||||
private:
|
|
||||||
void _CacheAmxOpcodeList();
|
|
||||||
|
|
||||||
int _GetOpcodeFromCip(cell cip, cell *&addr);
|
|
||||||
cell _CipAsVa(cell cip);
|
|
||||||
|
|
||||||
const char *_GetFilename();
|
|
||||||
const char *_GetVersion();
|
|
||||||
public:
|
|
||||||
AMX *m_pAmx;
|
|
||||||
AMX_DBG *m_pAmxDbg;
|
|
||||||
|
|
||||||
int m_Top;
|
|
||||||
cell *m_pOpcodeList;
|
|
||||||
ke::AString m_FileName;
|
|
||||||
ke::AString m_Version;
|
|
||||||
|
|
||||||
ke::Vector<Tracer *> m_pCalls;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef Debugger::Tracer::trace_info trace_info_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error handler for plugins
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Handler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Handler(AMX *pAmx) : m_pAmx(pAmx), m_iErrFunc(-1), m_iModFunc(-1), m_iNatFunc(-1), m_Handling(false), m_InNativeFilter(false) {};
|
|
||||||
~Handler() {};
|
|
||||||
public:
|
|
||||||
int SetErrorHandler(const char *function);
|
|
||||||
int SetNativeFilter(const char *function);
|
|
||||||
int SetModuleFilter(const char *function);
|
|
||||||
public:
|
|
||||||
int HandleError(const char *msg);
|
|
||||||
int HandleNative(const char *native, int index, int trap);
|
|
||||||
int HandleModule(const char *module, bool isClass=false);
|
|
||||||
public:
|
|
||||||
bool IsHandling() const { return m_Handling; }
|
|
||||||
void SetErrorMsg(const char *msg);
|
|
||||||
|
|
||||||
const char *GetLastMsg();
|
|
||||||
trace_info_t *GetTrace() const { return m_pTrace; }
|
|
||||||
const char *GetFmtCache() { return m_FmtCache.chars(); }
|
|
||||||
|
|
||||||
bool IsNativeFiltering() { return (m_iNatFunc > -1); }
|
|
||||||
bool InNativeFilter() { return m_InNativeFilter; }
|
|
||||||
private:
|
|
||||||
AMX *m_pAmx;
|
|
||||||
|
|
||||||
int m_iErrFunc;
|
|
||||||
int m_iModFunc;
|
|
||||||
int m_iNatFunc;
|
|
||||||
|
|
||||||
bool m_Handling;
|
|
||||||
|
|
||||||
//in the future, make this a stack!
|
|
||||||
bool m_InNativeFilter;
|
|
||||||
|
|
||||||
ke::AString m_MsgCache;
|
|
||||||
ke::AString m_FmtCache;
|
|
||||||
|
|
||||||
trace_info_t *m_pTrace;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern AMX_NATIVE_INFO g_DebugNatives[];
|
|
||||||
|
|
||||||
#endif //_INCLUDE_DEBUGGER_H_
|
|
203
amxmodx/emsg.cpp
203
amxmodx/emsg.cpp
@ -1,14 +1,37 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
/* AMX Mod X
|
||||||
//
|
*
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
* by the AMX Mod X Development Team
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
* originally developed by OLO
|
||||||
//
|
*
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
*
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
// https://alliedmods.net/amxmodx-license
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, write to the Free Software Foundation,
|
||||||
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the author gives permission to
|
||||||
|
* link the code of this program with the Half-Life Game Engine ("HL
|
||||||
|
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||||
|
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||||
|
* respects for all of the code used other than the HL Engine and MODs
|
||||||
|
* from Valve. If you modify this file, you may extend this exception
|
||||||
|
* to your version of the file, but you are not obligated to do so. If
|
||||||
|
* you do not wish to do so, delete this exception statement from your
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "amxmodx.h"
|
#include <extdll.h>
|
||||||
#include "CMenu.h"
|
#include <meta_api.h>
|
||||||
|
#include "amxmod.h"
|
||||||
|
|
||||||
int gmsgAmmoPickup;
|
int gmsgAmmoPickup;
|
||||||
int gmsgAmmoX;
|
int gmsgAmmoX;
|
||||||
@ -30,8 +53,6 @@ int gmsgWeaponList;
|
|||||||
int gmsgintermission;
|
int gmsgintermission;
|
||||||
int gmsgResetHUD;
|
int gmsgResetHUD;
|
||||||
int gmsgRoundTime;
|
int gmsgRoundTime;
|
||||||
int gmsgSayText;
|
|
||||||
int gmsgInitHUD;
|
|
||||||
|
|
||||||
TeamIds g_teamsIds;
|
TeamIds g_teamsIds;
|
||||||
WeaponsVault g_weaponsData[MAX_WEAPONS];
|
WeaponsVault g_weaponsData[MAX_WEAPONS];
|
||||||
@ -39,14 +60,9 @@ WeaponsVault g_weaponsData[MAX_WEAPONS];
|
|||||||
void Client_VGUIMenu(void* mValue)
|
void Client_VGUIMenu(void* mValue)
|
||||||
{
|
{
|
||||||
if (!mPlayer) return;
|
if (!mPlayer) return;
|
||||||
|
switch (mState++){
|
||||||
mPlayer->vgui = true;
|
|
||||||
|
|
||||||
switch (mState++)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
mPlayer->menu = -(*(int*)mValue);
|
mPlayer->menu = -(*(int*)mValue);
|
||||||
mPlayer->newmenu = -1;
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
mPlayer->keys = *(int*)mValue;
|
mPlayer->keys = *(int*)mValue;
|
||||||
@ -56,113 +72,72 @@ void Client_VGUIMenu(void* mValue)
|
|||||||
void Client_ShowMenu(void* mValue)
|
void Client_ShowMenu(void* mValue)
|
||||||
{
|
{
|
||||||
if (!mPlayer) return;
|
if (!mPlayer) return;
|
||||||
|
switch (mState++){
|
||||||
mPlayer->vgui = true;
|
|
||||||
|
|
||||||
switch (mState++)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
mPlayer->keys = *(int*)mValue;
|
mPlayer->keys = *(int*)mValue;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
{
|
|
||||||
mPlayer->menu = g_menucmds.findMenuId( (char*)mValue );
|
mPlayer->menu = g_menucmds.findMenuId( (char*)mValue );
|
||||||
mPlayer->newmenu = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern bool g_bmod_tfc;
|
|
||||||
void Client_TeamInfo(void* mValue)
|
void Client_TeamInfo(void* mValue)
|
||||||
{
|
{
|
||||||
if (mPlayer && !g_bmod_tfc) return;
|
if (mPlayer) return;
|
||||||
static int index;
|
static int index;
|
||||||
|
switch (mState++) {
|
||||||
switch (mState++)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
index = *(int*)mValue;
|
index = *(int*)mValue;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
if ( index < 1 || index > gpGlobals->maxClients ) break;
|
if ( index < 1 || index > gpGlobals->maxClients ) break;
|
||||||
char* msg = (char*)mValue;
|
char* msg = (char*)mValue;
|
||||||
if (!msg) break;
|
g_players[ index ].team.set( msg );
|
||||||
g_players[index].team = msg;
|
|
||||||
g_teamsIds.registerTeam( msg , -1 );
|
g_teamsIds.registerTeam( msg , -1 );
|
||||||
g_players[index].teamId = g_teamsIds.findTeamId(msg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CS fix for SPECTATOR team.
|
|
||||||
* -
|
|
||||||
* When a player chooses spectator, ScoreInfo is sent before TeamInfo and with 0 as index.
|
|
||||||
* This means for the first round of first spectator, SPECTATOR name is not associated with its index.
|
|
||||||
* The following fix manually sets the team index when we hit SPECTATOR team.
|
|
||||||
*/
|
|
||||||
if (g_players[index].teamId == -1 && g_bmod_cstrike && !strcmp(msg, "SPECTATOR"))
|
|
||||||
{
|
|
||||||
g_players[index].teamId = 3;
|
|
||||||
g_teamsIds.registerTeam(msg, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client_TextMsg(void* mValue)
|
void Client_TextMsg(void* mValue)
|
||||||
{
|
{
|
||||||
if ( mPlayer ) return;
|
if ( mPlayer ) return;
|
||||||
|
switch (mState++) {
|
||||||
switch (mState++)
|
case 1:{
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
char * msg = (char*)mValue;
|
char * msg = (char*)mValue;
|
||||||
if (!msg) break;
|
if (!msg) break;
|
||||||
|
if ( !strncmp("#Game_C", msg , 7) ) {
|
||||||
if (!strncmp("#Game_C", msg, 7))
|
|
||||||
{
|
|
||||||
g_game_timeleft = g_game_restarting = gpGlobals->time + 3;
|
g_game_timeleft = g_game_restarting = gpGlobals->time + 3;
|
||||||
// g_endround_time = gpGlobals->time;
|
// g_endround_time = gpGlobals->time;
|
||||||
// g_newround_time = gpGlobals->time + CVAR_GET_FLOAT("mp_freezetime") + 3;
|
// g_newround_time = gpGlobals->time + CVAR_GET_FLOAT("mp_freezetime") + 3;
|
||||||
}
|
}
|
||||||
else if (!strncmp("#Game_w", msg, 7))
|
else if (!strncmp("#Game_w", msg , 7) ) {
|
||||||
{
|
|
||||||
g_game_timeleft = -2;
|
g_game_timeleft = -2;
|
||||||
}
|
}
|
||||||
else if (!strncmp("#game_clan_s", msg, 12))
|
else if ( !strncmp("#game_clan_s", msg , 12) ){
|
||||||
{
|
|
||||||
g_game_timeleft = -3;
|
g_game_timeleft = -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:{
|
||||||
{
|
|
||||||
char * msg = (char*)mValue;
|
char * msg = (char*)mValue;
|
||||||
if (!msg) break;
|
if (!msg) break;
|
||||||
|
if (g_game_timeleft == -2 ){
|
||||||
if (g_game_timeleft == -2)
|
|
||||||
{
|
|
||||||
g_game_timeleft = g_game_restarting = gpGlobals->time + atoi( msg );
|
g_game_timeleft = g_game_restarting = gpGlobals->time + atoi( msg );
|
||||||
// g_newround_time = g_game_timeleft + CVAR_GET_FLOAT("mp_freezetime");
|
// g_newround_time = g_game_timeleft + CVAR_GET_FLOAT("mp_freezetime");
|
||||||
}
|
}
|
||||||
else if ( g_game_timeleft == -3 )
|
else if ( g_game_timeleft == -3 )
|
||||||
g_game_restarting = atoi(msg) * 60.0f;
|
g_game_restarting = atoi( msg ) * 60;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:{
|
||||||
{
|
|
||||||
char * msg = (char*)mValue;
|
char * msg = (char*)mValue;
|
||||||
if (!msg) break;
|
if (!msg) break;
|
||||||
if ( g_game_timeleft != -3 ) break;
|
if ( g_game_timeleft != -3 ) break;
|
||||||
g_game_restarting += atoi( msg );
|
g_game_restarting += atoi( msg );
|
||||||
g_game_timeleft = g_game_restarting = gpGlobals->time + g_game_restarting;
|
g_game_timeleft = g_game_restarting = gpGlobals->time + g_game_restarting;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client_WeaponList(void* mValue)
|
void Client_WeaponList(void* mValue)
|
||||||
@ -171,9 +146,7 @@ void Client_WeaponList(void* mValue)
|
|||||||
//static int wpnList2;
|
//static int wpnList2;
|
||||||
static int iSlot;
|
static int iSlot;
|
||||||
static const char* wpnName;
|
static const char* wpnName;
|
||||||
|
switch (mState++) {
|
||||||
switch (mState++)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
wpnName = (char*)mValue;
|
wpnName = (char*)mValue;
|
||||||
break;
|
break;
|
||||||
@ -182,12 +155,24 @@ void Client_WeaponList(void* mValue)
|
|||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
int iId = *(int*)mValue;
|
int iId = *(int*)mValue;
|
||||||
|
/*int* blocker;
|
||||||
|
|
||||||
|
int iwpn = iId;
|
||||||
|
|
||||||
|
if (iId > 31) {
|
||||||
|
iwpn -= 31;
|
||||||
|
blocker = &wpnList2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
blocker = &wpnList;*/
|
||||||
|
|
||||||
if ( (iId < 0 || iId >= MAX_WEAPONS ) || (wpnList & (1<<iId)) )
|
if ( (iId < 0 || iId >= MAX_WEAPONS ) || (wpnList & (1<<iId)) )
|
||||||
break;
|
break;
|
||||||
wpnList |= (1<<iId);
|
wpnList |= (1<<iId);
|
||||||
g_weaponsData[iId].iId = iId;
|
g_weaponsData[iId].iId = iId;
|
||||||
g_weaponsData[iId].ammoSlot = iSlot;
|
g_weaponsData[iId].ammoSlot = iSlot;
|
||||||
g_weaponsData[iId].fullName = wpnName;
|
g_weaponsData[iId].fullName.set(wpnName);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,9 +180,7 @@ void Client_CurWeapon(void* mValue)
|
|||||||
{
|
{
|
||||||
static int iState;
|
static int iState;
|
||||||
static int iId;
|
static int iId;
|
||||||
|
switch (mState++){
|
||||||
switch (mState++)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
iState = *(int*)mValue;
|
iState = *(int*)mValue;
|
||||||
break;
|
break;
|
||||||
@ -208,24 +191,17 @@ void Client_CurWeapon(void* mValue)
|
|||||||
case 2:
|
case 2:
|
||||||
if (!mPlayer) return;
|
if (!mPlayer) return;
|
||||||
if (!iState || (iId < 1 || iId >= MAX_WEAPONS ) ) break;
|
if (!iState || (iId < 1 || iId >= MAX_WEAPONS ) ) break;
|
||||||
mPlayer->current = iId;
|
|
||||||
|
|
||||||
|
|
||||||
if (*(int*)mValue < mPlayer->weapons[iId].clip && // Only update the lastHit vector if the clip size is decreasing
|
|
||||||
*(int*)mValue != -1) // But not if it's a melee weapon
|
|
||||||
{
|
|
||||||
mPlayer->lastHit = mPlayer->lastTrace;
|
|
||||||
}
|
|
||||||
mPlayer->weapons[iId].clip = *(int*)mValue;
|
mPlayer->weapons[iId].clip = *(int*)mValue;
|
||||||
|
mPlayer->current = iId;
|
||||||
|
mPlayer->lastHit = mPlayer->lastTrace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client_AmmoX(void* mValue)
|
void Client_AmmoX(void* mValue)
|
||||||
{
|
{
|
||||||
static int iAmmo;
|
|
||||||
|
|
||||||
switch (mState++)
|
static int iAmmo;
|
||||||
{
|
switch (mState++){
|
||||||
case 0:
|
case 0:
|
||||||
iAmmo = *(int*)mValue;
|
iAmmo = *(int*)mValue;
|
||||||
break;
|
break;
|
||||||
@ -240,9 +216,7 @@ void Client_AmmoX(void* mValue)
|
|||||||
void Client_AmmoPickup(void* mValue)
|
void Client_AmmoPickup(void* mValue)
|
||||||
{
|
{
|
||||||
static int iSlot;
|
static int iSlot;
|
||||||
|
switch (mState++){
|
||||||
switch (mState++)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
iSlot = *(int*)mValue;
|
iSlot = *(int*)mValue;
|
||||||
break;
|
break;
|
||||||
@ -258,9 +232,7 @@ void Client_ScoreInfo(void* mValue)
|
|||||||
{
|
{
|
||||||
static int index;
|
static int index;
|
||||||
static int deaths;
|
static int deaths;
|
||||||
|
switch (mState++){
|
||||||
switch (mState++)
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
index = *(int*)mValue;
|
index = *(int*)mValue;
|
||||||
break;
|
break;
|
||||||
@ -273,7 +245,7 @@ void Client_ScoreInfo(void* mValue)
|
|||||||
pPlayer->deaths = deaths;
|
pPlayer->deaths = deaths;
|
||||||
pPlayer->teamId = *(int*)mValue;
|
pPlayer->teamId = *(int*)mValue;
|
||||||
if ( g_teamsIds.isNewTeam() )
|
if ( g_teamsIds.isNewTeam() )
|
||||||
g_teamsIds.registerTeam(pPlayer->team.chars(), pPlayer->teamId);
|
g_teamsIds.registerTeam( pPlayer->team.str() , pPlayer->teamId );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +259,7 @@ void Client_DamageEnd(void* mValue)
|
|||||||
g_events.parseValue( dead->death_killer );
|
g_events.parseValue( dead->death_killer );
|
||||||
g_events.parseValue( dead->index );
|
g_events.parseValue( dead->index );
|
||||||
g_events.parseValue( dead->death_headshot );
|
g_events.parseValue( dead->death_headshot );
|
||||||
g_events.parseValue(dead->death_weapon.chars());
|
g_events.parseValue( dead->death_weapon.str() );
|
||||||
g_events.parseValue( dead->death_tk ? 1 : 0 );
|
g_events.parseValue( dead->death_tk ? 1 : 0 );
|
||||||
g_events.executeEvents();
|
g_events.executeEvents();
|
||||||
dead->death_killer = 0;
|
dead->death_killer = 0;
|
||||||
@ -302,47 +274,30 @@ void Client_DeathMsg(void* mValue)
|
|||||||
static int victim_id;
|
static int victim_id;
|
||||||
static int hs;
|
static int hs;
|
||||||
|
|
||||||
switch (mState++)
|
switch (mState++){
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
killer_id = *(int*)mValue;
|
killer_id = *(int*)mValue;
|
||||||
killer = (killer_id > 0 && killer_id < 33) ? GET_PLAYER_POINTER_I(killer_id) : 0;
|
killer = (killer_id > 0 && killer_id < 33) ?
|
||||||
|
GET_PLAYER_POINTER_I(killer_id) : 0;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
victim_id = *(int*)mValue;
|
victim_id = *(int*)mValue;
|
||||||
victim = (victim_id > 0 && victim_id < 33) ? GET_PLAYER_POINTER_I(victim_id) : 0;
|
victim = (victim_id > 0 && victim_id < 33) ?
|
||||||
|
GET_PLAYER_POINTER_I(victim_id) : 0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
hs = *(int*)mValue;
|
hs = *(int*)mValue;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
|
||||||
if ( !killer || !victim ) break;
|
if ( !killer || !victim ) break;
|
||||||
|
|
||||||
victim->death_killer = killer_id;
|
victim->death_killer = killer_id;
|
||||||
victim->death_weapon = (char*)mValue;
|
victim->death_weapon.set((char*)mValue);
|
||||||
victim->death_headshot = hs;
|
victim->death_headshot = hs;
|
||||||
victim->death_tk = (killer->teamId == victim->teamId);
|
victim->death_tk = (killer->teamId == victim->teamId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client_InitHUDEnd(void* mValue)
|
|
||||||
{
|
|
||||||
if (!g_bmod_cstrike)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CPlayer *pPlayer = mPlayer;
|
|
||||||
|
|
||||||
if (!pPlayer->teamIdsInitialized && !pPlayer->IsBot())
|
|
||||||
{
|
|
||||||
// This creates specific indexes (> maxplayers) for print_chat_color().
|
|
||||||
// 33 : print_team_grey / spectator
|
|
||||||
// 34 : print_team_red / terrorist
|
|
||||||
// 35 : print_team_blue / ct
|
|
||||||
UTIL_TeamInfo(pPlayer->pEdict, 33 + 1, "TERRORIST"); // print_team_red
|
|
||||||
UTIL_TeamInfo(pPlayer->pEdict, 33 + 2, "CT"); // print_team_blue
|
|
||||||
pPlayer->teamIdsInitialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void Client_SendAudio(void* mValue)
|
void Client_SendAudio(void* mValue)
|
||||||
{
|
{
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "fakemeta.h"
|
|
||||||
|
|
||||||
int LoadMetamodPlugin(const char *path, void **handle, PLUG_LOADTIME now)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
if ( (err = LOAD_PLUGIN(PLID, path, now, handle)) || !*handle)
|
|
||||||
{
|
|
||||||
LOG_MESSAGE(PLID, "Can't Attach Module \"%s\".", path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int UnloadMetamodPlugin(void *handle)
|
|
||||||
{
|
|
||||||
if (UNLOAD_PLUGIN_BY_HANDLE(PLID, (void *)handle, PT_ANYTIME, PNL_PLUGIN))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef __FAKEMETA_H__
|
|
||||||
#define __FAKEMETA_H__
|
|
||||||
|
|
||||||
int UnloadMetamodPlugin(void *handle);
|
|
||||||
int LoadMetamodPlugin(const char *path, void **handle, PLUG_LOADTIME now);
|
|
||||||
|
|
||||||
#endif // #ifndef __FAKEMETA_H__
|
|
1393
amxmodx/file.cpp
1393
amxmodx/file.cpp
File diff suppressed because it is too large
Load Diff
@ -14,19 +14,11 @@
|
|||||||
* 2003-11-24: A few more native functions (geometry), plus minor modifications,
|
* 2003-11-24: A few more native functions (geometry), plus minor modifications,
|
||||||
* mostly to be compatible with dynamically loadable extension
|
* mostly to be compatible with dynamically loadable extension
|
||||||
* modules, by Thiadmer Riemersma
|
* modules, by Thiadmer Riemersma
|
||||||
* 2004-01-09: Adaptions for 64-bit cells (using "double precision"), by
|
|
||||||
* Thiadmer Riemersma
|
|
||||||
*/
|
*/
|
||||||
#include <stdlib.h> /* for atof() */
|
#include <stdlib.h> /* for atof() */
|
||||||
#include <stdio.h> /* for NULL */
|
#include <stdio.h> /* for NULL */
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cmath>
|
#include <math.h>
|
||||||
|
|
||||||
// this file does not include amxmodx.h, so we have to include the memory manager here
|
|
||||||
#ifdef MEMORY_TEST
|
|
||||||
#include "mmgr/mmgr.h"
|
|
||||||
#endif // MEMORY_TEST
|
|
||||||
|
|
||||||
#include "amx.h"
|
#include "amx.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -37,19 +29,6 @@
|
|||||||
|
|
||||||
#define PI 3.1415926535897932384626433832795
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
|
||||||
static REAL FromRadians(REAL angle, int radix)
|
|
||||||
{
|
|
||||||
switch (radix)
|
|
||||||
{
|
|
||||||
case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
|
|
||||||
return (REAL)(angle / PI * 180.0);
|
|
||||||
case 2: /* grades, centesimal system */
|
|
||||||
return (REAL)(angle / PI * 200.0);
|
|
||||||
default: /* assume already radian */
|
|
||||||
return angle;
|
|
||||||
} /* switch */
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
#if defined __BORLANDC__ || defined __WATCOMC__
|
||||||
#pragma argsused
|
#pragma argsused
|
||||||
#endif
|
#endif
|
||||||
@ -60,10 +39,10 @@ static cell AMX_NATIVE_CALL n_float(AMX *amx,cell *params)
|
|||||||
* params[0] = number of bytes
|
* params[0] = number of bytes
|
||||||
* params[1] = long value to convert to a float
|
* params[1] = long value to convert to a float
|
||||||
*/
|
*/
|
||||||
REAL fValue;
|
float fValue;
|
||||||
|
|
||||||
/* Convert to a float. Calls the compilers long to float conversion. */
|
/* Convert to a float. Calls the compilers long to float conversion. */
|
||||||
fValue = (REAL) params[1];
|
fValue = (float) params[1];
|
||||||
|
|
||||||
/* Return the cell. */
|
/* Return the cell. */
|
||||||
return amx_ftoc(fValue);
|
return amx_ftoc(fValue);
|
||||||
@ -81,7 +60,7 @@ static cell AMX_NATIVE_CALL n_floatstr(AMX *amx,cell *params)
|
|||||||
*/
|
*/
|
||||||
char szSource[60];
|
char szSource[60];
|
||||||
cell *pString;
|
cell *pString;
|
||||||
REAL fNum;
|
float fNum;
|
||||||
int nLen;
|
int nLen;
|
||||||
|
|
||||||
/* They should have sent us 1 cell. */
|
/* They should have sent us 1 cell. */
|
||||||
@ -92,14 +71,14 @@ static cell AMX_NATIVE_CALL n_floatstr(AMX *amx,cell *params)
|
|||||||
|
|
||||||
/* Find out how long the string is in characters. */
|
/* Find out how long the string is in characters. */
|
||||||
amx_StrLen(pString, &nLen);
|
amx_StrLen(pString, &nLen);
|
||||||
if (nLen == 0 || (unsigned int)nLen >= sizeof szSource)
|
if (nLen == 0 || nLen >= sizeof szSource)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Now convert the Small String into a C type null terminated string */
|
/* Now convert the Small String into a C type null terminated string */
|
||||||
amx_GetStringOld(szSource, pString, 0);
|
amx_GetString(szSource, pString);
|
||||||
|
|
||||||
/* Now convert this to a float. */
|
/* Now convert this to a float. */
|
||||||
fNum = (REAL)atof(szSource);
|
fNum = (float)atof(szSource);
|
||||||
|
|
||||||
return amx_ftoc(fNum);
|
return amx_ftoc(fNum);
|
||||||
}
|
}
|
||||||
@ -115,7 +94,7 @@ static cell AMX_NATIVE_CALL n_floatmul(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1
|
* params[1] = float operand 1
|
||||||
* params[2] = float operand 2
|
* params[2] = float operand 2
|
||||||
*/
|
*/
|
||||||
REAL fRes = amx_ctof(params[1]) * amx_ctof(params[2]);
|
float fRes = amx_ctof(params[1]) * amx_ctof(params[2]);
|
||||||
return amx_ftoc(fRes);
|
return amx_ftoc(fRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +109,7 @@ static cell AMX_NATIVE_CALL n_floatdiv(AMX *amx,cell *params)
|
|||||||
* params[1] = float dividend (top)
|
* params[1] = float dividend (top)
|
||||||
* params[2] = float divisor (bottom)
|
* params[2] = float divisor (bottom)
|
||||||
*/
|
*/
|
||||||
REAL fRes = amx_ctof(params[1]) / amx_ctof(params[2]);
|
float fRes = amx_ctof(params[1]) / amx_ctof(params[2]);
|
||||||
return amx_ftoc(fRes);
|
return amx_ftoc(fRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +124,7 @@ static cell AMX_NATIVE_CALL n_floatadd(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1
|
* params[1] = float operand 1
|
||||||
* params[2] = float operand 2
|
* params[2] = float operand 2
|
||||||
*/
|
*/
|
||||||
REAL fRes = amx_ctof(params[1]) + amx_ctof(params[2]);
|
float fRes = amx_ctof(params[1]) + amx_ctof(params[2]);
|
||||||
return amx_ftoc(fRes);
|
return amx_ftoc(fRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +139,7 @@ static cell AMX_NATIVE_CALL n_floatsub(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1
|
* params[1] = float operand 1
|
||||||
* params[2] = float operand 2
|
* params[2] = float operand 2
|
||||||
*/
|
*/
|
||||||
REAL fRes = amx_ctof(params[1]) - amx_ctof(params[2]);
|
float fRes = amx_ctof(params[1]) - amx_ctof(params[2]);
|
||||||
return amx_ftoc(fRes);
|
return amx_ftoc(fRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,8 +154,8 @@ static cell AMX_NATIVE_CALL n_floatfract(AMX *amx,cell *params)
|
|||||||
* params[0] = number of bytes
|
* params[0] = number of bytes
|
||||||
* params[1] = float operand
|
* params[1] = float operand
|
||||||
*/
|
*/
|
||||||
REAL fA = amx_ctof(params[1]);
|
float fA = amx_ctof(params[1]);
|
||||||
fA = fA - (REAL)(floor((double)fA));
|
fA = fA - (float)(floor((double)fA));
|
||||||
return amx_ftoc(fA);
|
return amx_ftoc(fA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,24 +171,24 @@ static cell AMX_NATIVE_CALL n_floatround(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand
|
* params[1] = float operand
|
||||||
* params[2] = Type of rounding (long)
|
* params[2] = Type of rounding (long)
|
||||||
*/
|
*/
|
||||||
REAL fA = amx_ctof(params[1]);
|
float fA = amx_ctof(params[1]);
|
||||||
|
|
||||||
switch (params[2])
|
switch (params[2])
|
||||||
{
|
{
|
||||||
case 1: /* round downwards (truncate) */
|
case 1: /* round downwards (truncate) */
|
||||||
fA = (REAL)(floor((double)fA));
|
fA = (float)(floor((double)fA));
|
||||||
break;
|
break;
|
||||||
case 2: /* round upwards */
|
case 2: /* round upwards */
|
||||||
fA = (REAL)(ceil((double)fA));
|
fA = (float)(ceil((double)fA));
|
||||||
break;
|
break;
|
||||||
case 3: /* round towards zero */
|
case 3: /* round towards zero */
|
||||||
if ( fA>=0.0 )
|
if ( fA>=0.0 )
|
||||||
fA = (REAL)(floor((double)fA));
|
fA = (float)(floor((double)fA));
|
||||||
else
|
else
|
||||||
fA = (REAL)(ceil((double)fA));
|
fA = (float)(ceil((double)fA));
|
||||||
break;
|
break;
|
||||||
default: /* standard, round to nearest */
|
default: /* standard, round to nearest */
|
||||||
fA = (REAL)(floor((double)fA+.5));
|
fA = (float)(floor((double)fA+.5));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +206,7 @@ static cell AMX_NATIVE_CALL n_floatcmp(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1
|
* params[1] = float operand 1
|
||||||
* params[2] = float operand 2
|
* params[2] = float operand 2
|
||||||
*/
|
*/
|
||||||
REAL fA, fB;
|
float fA, fB;
|
||||||
|
|
||||||
fA = amx_ctof(params[1]);
|
fA = amx_ctof(params[1]);
|
||||||
fB = amx_ctof(params[2]);
|
fB = amx_ctof(params[2]);
|
||||||
@ -247,8 +226,8 @@ static cell AMX_NATIVE_CALL n_floatsqroot(AMX *amx,cell *params)
|
|||||||
* params[0] = number of bytes
|
* params[0] = number of bytes
|
||||||
* params[1] = float operand
|
* params[1] = float operand
|
||||||
*/
|
*/
|
||||||
REAL fA = amx_ctof(params[1]);
|
float fA = amx_ctof(params[1]);
|
||||||
fA = (REAL)sqrt(fA);
|
fA = (float)sqrt(fA);
|
||||||
if (fA < 0)
|
if (fA < 0)
|
||||||
return amx_RaiseError(amx, AMX_ERR_DOMAIN);
|
return amx_RaiseError(amx, AMX_ERR_DOMAIN);
|
||||||
return amx_ftoc(fA);
|
return amx_ftoc(fA);
|
||||||
@ -265,9 +244,9 @@ static cell AMX_NATIVE_CALL n_floatpower(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1 (base)
|
* params[1] = float operand 1 (base)
|
||||||
* params[2] = float operand 2 (exponent)
|
* params[2] = float operand 2 (exponent)
|
||||||
*/
|
*/
|
||||||
REAL fA = amx_ctof(params[1]);
|
float fA = amx_ctof(params[1]);
|
||||||
REAL fB = amx_ctof(params[2]);
|
float fB = amx_ctof(params[2]);
|
||||||
fA = (REAL)pow(fA, fB);
|
fA = (float)pow(fA, fB);
|
||||||
return amx_ftoc(fA);
|
return amx_ftoc(fA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,25 +261,25 @@ static cell AMX_NATIVE_CALL n_floatlog(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1 (value)
|
* params[1] = float operand 1 (value)
|
||||||
* params[2] = float operand 2 (base)
|
* params[2] = float operand 2 (base)
|
||||||
*/
|
*/
|
||||||
REAL fValue = amx_ctof(params[1]);
|
float fValue = amx_ctof(params[1]);
|
||||||
REAL fBase = amx_ctof(params[2]);
|
float fBase = amx_ctof(params[2]);
|
||||||
if (fValue <= 0.0 || fBase <= 0)
|
if (fValue <= 0.0 || fBase <= 0)
|
||||||
return amx_RaiseError(amx, AMX_ERR_DOMAIN);
|
return amx_RaiseError(amx, AMX_ERR_DOMAIN);
|
||||||
if (fBase == 10.0) // ??? epsilon
|
if (fBase == 10.0) // ??? epsilon
|
||||||
fValue = (REAL)log10(fValue);
|
fValue = (float)log10(fValue);
|
||||||
else
|
else
|
||||||
fValue = (REAL)(log(fValue) / log(fBase));
|
fValue = (float)(log(fValue) / log(fBase));
|
||||||
return amx_ftoc(fValue);
|
return amx_ftoc(fValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static REAL ToRadians(REAL angle, int radix)
|
static float ToRadians(float angle, int radix)
|
||||||
{
|
{
|
||||||
switch (radix)
|
switch (radix)
|
||||||
{
|
{
|
||||||
case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
|
case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
|
||||||
return (REAL)(angle * PI / 180.0);
|
return (float)(angle * PI / 180.0);
|
||||||
case 2: /* grades, centesimal system */
|
case 2: /* grades, centesimal system */
|
||||||
return (REAL)(angle * PI / 200.0);
|
return (float)(angle * PI / 200.0);
|
||||||
default: /* assume already radian */
|
default: /* assume already radian */
|
||||||
return angle;
|
return angle;
|
||||||
} /* switch */
|
} /* switch */
|
||||||
@ -317,9 +296,9 @@ static cell AMX_NATIVE_CALL n_floatsin(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1 (angle)
|
* params[1] = float operand 1 (angle)
|
||||||
* params[2] = float operand 2 (radix)
|
* params[2] = float operand 2 (radix)
|
||||||
*/
|
*/
|
||||||
REAL fA = amx_ctof(params[1]);
|
float fA = amx_ctof(params[1]);
|
||||||
fA = ToRadians(fA, params[2]);
|
fA = ToRadians(fA, params[2]);
|
||||||
fA = sin(fA);
|
fA = sinf(fA); // PM: using the float version of sin
|
||||||
return amx_ftoc(fA);
|
return amx_ftoc(fA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,9 +313,9 @@ static cell AMX_NATIVE_CALL n_floatcos(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1 (angle)
|
* params[1] = float operand 1 (angle)
|
||||||
* params[2] = float operand 2 (radix)
|
* params[2] = float operand 2 (radix)
|
||||||
*/
|
*/
|
||||||
REAL fA = amx_ctof(params[1]);
|
float fA = amx_ctof(params[1]);
|
||||||
fA = ToRadians(fA, params[2]);
|
fA = ToRadians(fA, params[2]);
|
||||||
fA = cos(fA);
|
fA = cosf(fA); // PM: using the float version of cos
|
||||||
return amx_ftoc(fA);
|
return amx_ftoc(fA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,124 +330,9 @@ static cell AMX_NATIVE_CALL n_floattan(AMX *amx,cell *params)
|
|||||||
* params[1] = float operand 1 (angle)
|
* params[1] = float operand 1 (angle)
|
||||||
* params[2] = float operand 2 (radix)
|
* params[2] = float operand 2 (radix)
|
||||||
*/
|
*/
|
||||||
REAL fA = amx_ctof(params[1]);
|
float fA = amx_ctof(params[1]);
|
||||||
fA = ToRadians(fA, params[2]);
|
fA = ToRadians(fA, params[2]);
|
||||||
fA = tan(fA);
|
fA = tanf(fA); // PM: using the float version of tan
|
||||||
return amx_ftoc(fA);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
|
||||||
#pragma argsused
|
|
||||||
#endif
|
|
||||||
/* Added by BAILOPAN */
|
|
||||||
static cell AMX_NATIVE_CALL n_floatatan(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* params[1] = angle
|
|
||||||
* params[2] = radix
|
|
||||||
*/
|
|
||||||
REAL fA = amx_ctof(params[1]);
|
|
||||||
fA = atan(fA);
|
|
||||||
fA = FromRadians(fA, params[2]);
|
|
||||||
return amx_ftoc(fA);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
|
||||||
#pragma argsused
|
|
||||||
#endif
|
|
||||||
/* Added by BAILOPAN */
|
|
||||||
static cell AMX_NATIVE_CALL n_floatacos(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* params[1] = angle
|
|
||||||
* params[2] = radix
|
|
||||||
*/
|
|
||||||
REAL fA = amx_ctof(params[1]);
|
|
||||||
fA = acos(fA);
|
|
||||||
fA = FromRadians(fA, params[2]);
|
|
||||||
return amx_ftoc(fA);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
|
||||||
#pragma argsused
|
|
||||||
#endif
|
|
||||||
/* Added by BAILOPAN */
|
|
||||||
static cell AMX_NATIVE_CALL n_floatasin(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* params[1] = angle
|
|
||||||
* params[2] = radix
|
|
||||||
*/
|
|
||||||
REAL fA = amx_ctof(params[1]);
|
|
||||||
fA = asin(fA);
|
|
||||||
fA = FromRadians(fA, params[2]);
|
|
||||||
return amx_ftoc(fA);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
|
||||||
#pragma argsused
|
|
||||||
#endif
|
|
||||||
/* Added by BAILOPAN */
|
|
||||||
static cell AMX_NATIVE_CALL n_floatatan2(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* params[1] = x
|
|
||||||
* params[2] = y
|
|
||||||
* params[3] = radix
|
|
||||||
*/
|
|
||||||
REAL fA = amx_ctof(params[1]);
|
|
||||||
REAL fB = amx_ctof(params[2]);
|
|
||||||
REAL fC;
|
|
||||||
fC = atan2(fA, fB);
|
|
||||||
fC = FromRadians(fC, params[3]);
|
|
||||||
return amx_ftoc(fC);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
|
||||||
#pragma argsused
|
|
||||||
#endif
|
|
||||||
/* Added by DS */
|
|
||||||
static cell AMX_NATIVE_CALL n_floatsinh(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* params[1] = angle
|
|
||||||
* params[2] = radix
|
|
||||||
*/
|
|
||||||
REAL fA = amx_ctof(params[1]);
|
|
||||||
fA = ToRadians(fA, params[2]);
|
|
||||||
fA = sinh(fA);
|
|
||||||
return amx_ftoc(fA);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
|
||||||
#pragma argsused
|
|
||||||
#endif
|
|
||||||
/* Added by DS */
|
|
||||||
static cell AMX_NATIVE_CALL n_floatcosh(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* params[1] = angle
|
|
||||||
* params[2] = radix
|
|
||||||
*/
|
|
||||||
REAL fA = amx_ctof(params[1]);
|
|
||||||
fA = ToRadians(fA, params[2]);
|
|
||||||
fA = cosh(fA);
|
|
||||||
return amx_ftoc(fA);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __BORLANDC__ || defined __WATCOMC__
|
|
||||||
#pragma argsused
|
|
||||||
#endif
|
|
||||||
/* Added by DS */
|
|
||||||
static cell AMX_NATIVE_CALL n_floattanh(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* params[1] = angle
|
|
||||||
* params[2] = radix
|
|
||||||
*/
|
|
||||||
REAL fA = amx_ctof(params[1]);
|
|
||||||
fA = ToRadians(fA, params[2]);
|
|
||||||
fA = tanh(fA);
|
|
||||||
return amx_ftoc(fA);
|
return amx_ftoc(fA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,7 +342,7 @@ static cell AMX_NATIVE_CALL n_floattanh(AMX *amx, cell *params)
|
|||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
static cell AMX_NATIVE_CALL n_floatabs(AMX *amx,cell *params)
|
static cell AMX_NATIVE_CALL n_floatabs(AMX *amx,cell *params)
|
||||||
{
|
{
|
||||||
REAL fA = amx_ctof(params[1]);
|
float fA = amx_ctof(params[1]);
|
||||||
fA = (fA >= 0) ? fA : -fA;
|
fA = (fA >= 0) ? fA : -fA;
|
||||||
return amx_ftoc(fA);
|
return amx_ftoc(fA);
|
||||||
}
|
}
|
||||||
@ -500,13 +364,6 @@ AMX_NATIVE_INFO float_Natives[] = {
|
|||||||
{ "floatcos", n_floatcos },
|
{ "floatcos", n_floatcos },
|
||||||
{ "floattan", n_floattan },
|
{ "floattan", n_floattan },
|
||||||
{ "floatabs", n_floatabs },
|
{ "floatabs", n_floatabs },
|
||||||
{ "floatasin", n_floatasin },
|
|
||||||
{ "floatacos", n_floatacos },
|
|
||||||
{ "floatatan", n_floatatan },
|
|
||||||
{ "floatatan2", n_floatatan2 },
|
|
||||||
{ "floatsinh", n_floatsinh },
|
|
||||||
{ "floatcosh", n_floatcosh },
|
|
||||||
{ "floattanh", n_floattanh },
|
|
||||||
{ NULL, NULL } /* terminator */
|
{ NULL, NULL } /* terminator */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,828 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "format.h"
|
|
||||||
#include "datastructs.h"
|
|
||||||
|
|
||||||
//Adapted from Quake3's vsprintf
|
|
||||||
// thanks to cybermind for linking me to this :)
|
|
||||||
//I made the following changes:
|
|
||||||
// - Fixed spacing to be AMX Mod X standard
|
|
||||||
// - Added 'n' support, no buffer overflows
|
|
||||||
// - Templatized input/output buffers
|
|
||||||
|
|
||||||
#define ALT 0x00000001 /* alternate form */
|
|
||||||
#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */
|
|
||||||
#define LADJUST 0x00000004 /* left adjustment */
|
|
||||||
#define LONGDBL 0x00000008 /* long double */
|
|
||||||
#define LONGINT 0x00000010 /* long integer */
|
|
||||||
#define QUADINT 0x00000020 /* quad integer */
|
|
||||||
#define SHORTINT 0x00000040 /* short integer */
|
|
||||||
#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */
|
|
||||||
#define FPT 0x00000100 /* floating point number */
|
|
||||||
#define UPPERDIGITS 0x00000200 /* make alpha digits uppercase */
|
|
||||||
#define to_digit(c) ((c) - '0')
|
|
||||||
#define is_digit(c) ((unsigned)to_digit(c) <= 9)
|
|
||||||
#define to_char(n) ((n) + '0')
|
|
||||||
#define CHECK_ARGS(n) \
|
|
||||||
if ((arg+n) > args) { \
|
|
||||||
LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", arg, args); \
|
|
||||||
return 0; \
|
|
||||||
}
|
|
||||||
|
|
||||||
template size_t atcprintf<cell, cell>(cell *, size_t, const cell *, AMX *, cell *, int *);
|
|
||||||
template size_t atcprintf<char, cell>(char *, size_t, const cell *, AMX *, cell *, int *);
|
|
||||||
template size_t atcprintf<cell, char>(cell *, size_t, const char *, AMX *, cell *, int *);
|
|
||||||
template size_t atcprintf<char, char>(char *, size_t, const char *, AMX *, cell *, int *);
|
|
||||||
|
|
||||||
THash<ke::AString, lang_err> BadLang_Table;
|
|
||||||
|
|
||||||
static cvar_t *amx_mldebug = nullptr;
|
|
||||||
static cvar_t *amx_cl_langs = nullptr;
|
|
||||||
|
|
||||||
const char *playerlang(const cell index)
|
|
||||||
{
|
|
||||||
const char *pLangName = nullptr;
|
|
||||||
|
|
||||||
if (index == LANG_PLAYER)
|
|
||||||
{
|
|
||||||
if (!amx_cl_langs)
|
|
||||||
{
|
|
||||||
amx_cl_langs = CVAR_GET_POINTER("amx_client_languages");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<int>(amx_cl_langs->value) == 0)
|
|
||||||
{
|
|
||||||
pLangName = amxmodx_language->string;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(g_langMngr.GetDefLang())->pEdict, "lang");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (index == LANG_SERVER)
|
|
||||||
{
|
|
||||||
pLangName = amxmodx_language->string;
|
|
||||||
}
|
|
||||||
else if (index >= 1 && index <= gpGlobals->maxClients)
|
|
||||||
{
|
|
||||||
if (!amx_cl_langs)
|
|
||||||
{
|
|
||||||
amx_cl_langs = CVAR_GET_POINTER("amx_client_languages");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<int>(amx_cl_langs->value) == 0)
|
|
||||||
{
|
|
||||||
pLangName = amxmodx_language->string;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(index)->pEdict, "lang");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pLangName;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *translate(AMX *amx, const char *lang, const char *key)
|
|
||||||
{
|
|
||||||
auto pLangName = lang;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (!pLangName || !isalpha(pLangName[0]))
|
|
||||||
{
|
|
||||||
pLangName = amxmodx_language->string;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto def = g_langMngr.GetDef(pLangName, key, status);
|
|
||||||
|
|
||||||
if (!amx_mldebug)
|
|
||||||
{
|
|
||||||
amx_mldebug = CVAR_GET_POINTER("amx_mldebug");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto debug = (amx_mldebug && amx_mldebug->string && (amx_mldebug->string[0] != '\0'));
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
int debug_status;
|
|
||||||
auto validlang = true;
|
|
||||||
auto testlang = amx_mldebug->string;
|
|
||||||
|
|
||||||
if (!g_langMngr.LangExists(testlang))
|
|
||||||
{
|
|
||||||
AMXXLOG_Error("[AMXX] \"%s\" is an invalid debug language", testlang);
|
|
||||||
validlang = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_langMngr.GetDef(testlang, key, debug_status);
|
|
||||||
|
|
||||||
if (validlang && debug_status == ERR_BADKEY)
|
|
||||||
{
|
|
||||||
AMXXLOG_Error("[AMXX] Language key \"%s\" not found for language \"%s\", check \"%s\"", key, testlang, GetFileName(amx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!def)
|
|
||||||
{
|
|
||||||
if (debug && status == ERR_BADLANG)
|
|
||||||
{
|
|
||||||
ke::AString langName(pLangName);
|
|
||||||
|
|
||||||
auto &err = BadLang_Table.AltFindOrInsert(ke::Move(langName));
|
|
||||||
|
|
||||||
if (err.last + 120.0f < gpGlobals->time)
|
|
||||||
{
|
|
||||||
AMXXLOG_Error("[AMXX] Language \"%s\" not found", pLangName);
|
|
||||||
err.last = gpGlobals->time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(pLangName, amxmodx_language->string) != 0)
|
|
||||||
{
|
|
||||||
def = g_langMngr.GetDef(amxmodx_language->string, key, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!def && (strcmp(pLangName, "en") != 0 && strcmp(amxmodx_language->string, "en") != 0))
|
|
||||||
{
|
|
||||||
def = g_langMngr.GetDef("en", key, status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U, typename S>
|
|
||||||
void AddString(U **buf_p, size_t &maxlen, const S *string, int width, int prec)
|
|
||||||
{
|
|
||||||
int size = 0;
|
|
||||||
U *buf;
|
|
||||||
static S nlstr[] = {'(','n','u','l','l',')','\0'};
|
|
||||||
|
|
||||||
buf = *buf_p;
|
|
||||||
|
|
||||||
if (string == NULL)
|
|
||||||
{
|
|
||||||
string = nlstr;
|
|
||||||
prec = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prec >= 0)
|
|
||||||
{
|
|
||||||
for (size = 0; size < prec; size++)
|
|
||||||
{
|
|
||||||
if (string[size] == '\0')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (string[size++]) ;
|
|
||||||
size--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size > (int)maxlen)
|
|
||||||
size = maxlen;
|
|
||||||
|
|
||||||
/* If precision is provided, make sure we don't truncate a multi-byte character */
|
|
||||||
if (prec >= size && (string[size - 1] & 1 << 7))
|
|
||||||
{
|
|
||||||
size -= UTIL_CheckValidChar((cell *)string + size - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
maxlen -= size;
|
|
||||||
width -= size;
|
|
||||||
|
|
||||||
while (size--)
|
|
||||||
*buf++ = static_cast<U>(*string++);
|
|
||||||
|
|
||||||
while (width-- > 0 && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = ' ';
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
*buf_p = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
void AddFloat(U **buf_p, size_t &maxlen, double fval, int width, int prec, int flags)
|
|
||||||
{
|
|
||||||
int digits; // non-fraction part digits
|
|
||||||
double tmp; // temporary
|
|
||||||
U *buf = *buf_p; // output buffer pointer
|
|
||||||
int val; // temporary
|
|
||||||
int sign = 0; // 0: positive, 1: negative
|
|
||||||
int fieldlength; // for padding
|
|
||||||
int significant_digits = 0; // number of significant digits written
|
|
||||||
const int MAX_SIGNIFICANT_DIGITS = 16;
|
|
||||||
|
|
||||||
// default precision
|
|
||||||
if (prec < 0)
|
|
||||||
{
|
|
||||||
prec = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the sign
|
|
||||||
if (fval < 0)
|
|
||||||
{
|
|
||||||
fval = -fval;
|
|
||||||
sign = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute whole-part digits count
|
|
||||||
digits = (int)log10(fval) + 1;
|
|
||||||
|
|
||||||
// Only print 0.something if 0 < fval < 1
|
|
||||||
if (digits < 1)
|
|
||||||
{
|
|
||||||
digits = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute the field length
|
|
||||||
fieldlength = digits + prec + ((prec > 0) ? 1 : 0) + sign;
|
|
||||||
|
|
||||||
// minus sign BEFORE left padding if padding with zeros
|
|
||||||
if (sign && maxlen && (flags & ZEROPAD))
|
|
||||||
{
|
|
||||||
*buf++ = '-';
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// right justify if required
|
|
||||||
if ((flags & LADJUST) == 0)
|
|
||||||
{
|
|
||||||
while ((fieldlength < width) && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// minus sign AFTER left padding if padding with spaces
|
|
||||||
if (sign && maxlen && !(flags & ZEROPAD))
|
|
||||||
{
|
|
||||||
*buf++ = '-';
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the whole part
|
|
||||||
tmp = pow(10.0, digits-1);
|
|
||||||
while ((digits--) && maxlen)
|
|
||||||
{
|
|
||||||
if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
|
|
||||||
{
|
|
||||||
*buf++ = '0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
val = (int)(fval / tmp);
|
|
||||||
*buf++ = '0' + val;
|
|
||||||
fval -= val * tmp;
|
|
||||||
tmp *= 0.1;
|
|
||||||
}
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the fraction part
|
|
||||||
if (maxlen && prec)
|
|
||||||
{
|
|
||||||
*buf++ = '.';
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = pow(10.0, prec);
|
|
||||||
|
|
||||||
fval *= tmp;
|
|
||||||
while (prec-- && maxlen)
|
|
||||||
{
|
|
||||||
if (++significant_digits > MAX_SIGNIFICANT_DIGITS)
|
|
||||||
{
|
|
||||||
*buf++ = '0';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp *= 0.1;
|
|
||||||
val = (int)(fval / tmp);
|
|
||||||
*buf++ = '0' + val;
|
|
||||||
fval -= val * tmp;
|
|
||||||
}
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// left justify if required
|
|
||||||
if (flags & LADJUST)
|
|
||||||
{
|
|
||||||
while ((fieldlength < width) && maxlen)
|
|
||||||
{
|
|
||||||
// right-padding only with spaces, ZEROPAD is ignored
|
|
||||||
*buf++ = ' ';
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update parent's buffer pointer
|
|
||||||
*buf_p = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
void AddBinary(U **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
|
|
||||||
{
|
|
||||||
char text[32];
|
|
||||||
int digits;
|
|
||||||
U *buf;
|
|
||||||
|
|
||||||
digits = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (val & 1)
|
|
||||||
{
|
|
||||||
text[digits++] = '1';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
text[digits++] = '0';
|
|
||||||
}
|
|
||||||
val >>= 1;
|
|
||||||
} while (val);
|
|
||||||
|
|
||||||
buf = *buf_p;
|
|
||||||
|
|
||||||
if (!(flags & LADJUST))
|
|
||||||
{
|
|
||||||
while (digits < width && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (digits-- && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = text[digits];
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & LADJUST)
|
|
||||||
{
|
|
||||||
while (width-- && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*buf_p = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
void AddUInt(U **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
|
|
||||||
{
|
|
||||||
U text[32];
|
|
||||||
int digits;
|
|
||||||
U *buf;
|
|
||||||
|
|
||||||
digits = 0;
|
|
||||||
do {
|
|
||||||
text[digits++] = '0' + val % 10;
|
|
||||||
val /= 10;
|
|
||||||
} while (val);
|
|
||||||
|
|
||||||
buf = *buf_p;
|
|
||||||
|
|
||||||
if( !(flags & LADJUST) )
|
|
||||||
{
|
|
||||||
while (digits < width && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (digits-- && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = text[digits];
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & LADJUST)
|
|
||||||
{
|
|
||||||
while (width-- && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*buf_p = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
void AddInt(U **buf_p, size_t &maxlen, int val, int width, int flags)
|
|
||||||
{
|
|
||||||
U text[32];
|
|
||||||
int digits;
|
|
||||||
int signedVal;
|
|
||||||
U *buf;
|
|
||||||
unsigned int unsignedVal;
|
|
||||||
|
|
||||||
digits = 0;
|
|
||||||
signedVal = val;
|
|
||||||
if (val < 0)
|
|
||||||
{
|
|
||||||
/* we want the unsigned version */
|
|
||||||
unsignedVal = abs(val);
|
|
||||||
} else {
|
|
||||||
unsignedVal = val;
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
text[digits++] = '0' + unsignedVal % 10;
|
|
||||||
unsignedVal /= 10;
|
|
||||||
} while (unsignedVal);
|
|
||||||
|
|
||||||
if (signedVal < 0)
|
|
||||||
text[digits++] = '-';
|
|
||||||
|
|
||||||
buf = *buf_p;
|
|
||||||
|
|
||||||
if( !(flags & LADJUST) )
|
|
||||||
{
|
|
||||||
while (digits < width && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (digits-- && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = text[digits];
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & LADJUST)
|
|
||||||
{
|
|
||||||
while (width-- && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*buf_p = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
void AddHex(U **buf_p, size_t &maxlen, unsigned int val, int width, int flags)
|
|
||||||
{
|
|
||||||
U text[32];
|
|
||||||
int digits;
|
|
||||||
U *buf;
|
|
||||||
U digit;
|
|
||||||
int hexadjust;
|
|
||||||
|
|
||||||
if (flags & UPPERDIGITS)
|
|
||||||
{
|
|
||||||
hexadjust = 'A' - '9' - 1;
|
|
||||||
} else {
|
|
||||||
hexadjust = 'a' - '9' - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
digits = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
digit = ('0' + val % 16);
|
|
||||||
if (digit > '9')
|
|
||||||
{
|
|
||||||
digit += hexadjust;
|
|
||||||
}
|
|
||||||
|
|
||||||
text[digits++] = digit;
|
|
||||||
val /= 16;
|
|
||||||
} while (val);
|
|
||||||
|
|
||||||
buf = *buf_p;
|
|
||||||
|
|
||||||
if( !(flags & LADJUST) )
|
|
||||||
{
|
|
||||||
while (digits < width && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (digits-- && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = text[digits];
|
|
||||||
width--;
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & LADJUST)
|
|
||||||
{
|
|
||||||
while (width-- && maxlen)
|
|
||||||
{
|
|
||||||
*buf++ = (flags & ZEROPAD) ? '0' : ' ';
|
|
||||||
maxlen--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*buf_p = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename D, typename S>
|
|
||||||
size_t atcprintf(D *buffer, size_t maxlen, const S *format, AMX *amx, cell *params, int *param)
|
|
||||||
{
|
|
||||||
int arg;
|
|
||||||
int args = params[0] / sizeof(cell);
|
|
||||||
D *buf_p;
|
|
||||||
D ch;
|
|
||||||
int flags;
|
|
||||||
int width;
|
|
||||||
int prec;
|
|
||||||
int n;
|
|
||||||
//char sign;
|
|
||||||
const S *fmt;
|
|
||||||
size_t llen = maxlen;
|
|
||||||
|
|
||||||
buf_p = buffer;
|
|
||||||
arg = *param;
|
|
||||||
fmt = format;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
// run through the format string until we hit a '%' or '\0'
|
|
||||||
for (ch = static_cast<D>(*fmt);
|
|
||||||
llen && ((ch = static_cast<D>(*fmt)) != '\0' && ch != '%');
|
|
||||||
fmt++)
|
|
||||||
{
|
|
||||||
*buf_p++ = static_cast<D>(ch);
|
|
||||||
llen--;
|
|
||||||
}
|
|
||||||
if (ch == '\0' || llen <= 0)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
// skip over the '%'
|
|
||||||
fmt++;
|
|
||||||
|
|
||||||
// reset formatting state
|
|
||||||
flags = 0;
|
|
||||||
width = 0;
|
|
||||||
prec = -1;
|
|
||||||
//sign = '\0';
|
|
||||||
|
|
||||||
rflag:
|
|
||||||
ch = static_cast<D>(*fmt++);
|
|
||||||
reswitch:
|
|
||||||
switch(ch)
|
|
||||||
{
|
|
||||||
case '-':
|
|
||||||
flags |= LADJUST;
|
|
||||||
goto rflag;
|
|
||||||
case '.':
|
|
||||||
n = 0;
|
|
||||||
while( is_digit( ( ch = static_cast<D>(*fmt++)) ) )
|
|
||||||
n = 10 * n + ( ch - '0' );
|
|
||||||
prec = n < 0 ? -1 : n;
|
|
||||||
goto reswitch;
|
|
||||||
case '0':
|
|
||||||
flags |= ZEROPAD;
|
|
||||||
goto rflag;
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9':
|
|
||||||
n = 0;
|
|
||||||
do {
|
|
||||||
n = 10 * n + ( ch - '0' );
|
|
||||||
ch = static_cast<D>(*fmt++);
|
|
||||||
} while( is_digit( ch ) );
|
|
||||||
width = n;
|
|
||||||
goto reswitch;
|
|
||||||
case 'c':
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
*buf_p++ = static_cast<D>(*get_amxaddr(amx, params[arg]));
|
|
||||||
llen--;
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
AddBinary(&buf_p, llen, *get_amxaddr(amx, params[arg]), width, flags);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
AddInt(&buf_p, llen, *get_amxaddr(amx, params[arg]), width, flags);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
AddUInt(&buf_p, llen, static_cast<unsigned int>(*get_amxaddr(amx, params[arg])), width, flags);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
AddFloat(&buf_p, llen, amx_ctof(*get_amxaddr(amx, params[arg])), width, prec, flags);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
flags |= UPPERDIGITS;
|
|
||||||
AddHex(&buf_p, llen, static_cast<unsigned int>(*get_amxaddr(amx, params[arg])), width, flags);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
AddHex(&buf_p, llen, static_cast<unsigned int>(*get_amxaddr(amx, params[arg])), width, flags);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
{
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
// %a is passed a pointer directly to a cell string.
|
|
||||||
cell* ptr=reinterpret_cast<cell*>(*get_amxaddr(amx, params[arg]));
|
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid vector string handle provided (%d)", *get_amxaddr(amx, params[arg]));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddString(&buf_p, llen, ptr, width, prec);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 's':
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
AddString(&buf_p, llen, get_amxaddr(amx, params[arg]), width, prec);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
case 'L':
|
|
||||||
case 'l':
|
|
||||||
{
|
|
||||||
const char *lang;
|
|
||||||
int len;
|
|
||||||
if (ch == 'L')
|
|
||||||
{
|
|
||||||
CHECK_ARGS(1);
|
|
||||||
auto currParam = params[arg++];
|
|
||||||
lang = playerlang(*get_amxaddr(amx, currParam));
|
|
||||||
if (!lang)
|
|
||||||
lang = get_amxstring(amx, currParam, 2, len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
lang = playerlang(g_langMngr.GetDefLang());
|
|
||||||
}
|
|
||||||
const char *key = get_amxstring(amx, params[arg++], 3, len);
|
|
||||||
const char *def = translate(amx, lang, key);
|
|
||||||
if (!def)
|
|
||||||
{
|
|
||||||
static char buf[255];
|
|
||||||
ke::SafeSprintf(buf, sizeof(buf), "ML_NOTFOUND: %s", key);
|
|
||||||
def = buf;
|
|
||||||
}
|
|
||||||
size_t written = atcprintf(buf_p, llen, def, amx, params, &arg);
|
|
||||||
buf_p += written;
|
|
||||||
llen -= written;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'N':
|
|
||||||
{
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
cell *addr = get_amxaddr(amx, params[arg]);
|
|
||||||
char buffer[255];
|
|
||||||
if (*addr)
|
|
||||||
{
|
|
||||||
CPlayer *player = NULL;
|
|
||||||
|
|
||||||
if (*addr >= 1 && *addr <= gpGlobals->maxClients)
|
|
||||||
{
|
|
||||||
player = GET_PLAYER_POINTER_I(*addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!player || !player->initialized)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Client index %d is invalid", *addr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *auth = GETPLAYERAUTHID(player->pEdict);
|
|
||||||
if (!auth || auth[0] == '\0')
|
|
||||||
{
|
|
||||||
auth = "STEAM_ID_PENDING";
|
|
||||||
}
|
|
||||||
|
|
||||||
int userid = GETPLAYERUSERID(player->pEdict);
|
|
||||||
ke::SafeSprintf(buffer, sizeof(buffer), "%s<%d><%s><%s>", player->name.chars(), userid, auth, player->team.chars());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ke::SafeSprintf(buffer, sizeof(buffer), "Console<0><Console><Console>");
|
|
||||||
}
|
|
||||||
|
|
||||||
AddString(&buf_p, llen, buffer, width, prec);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'n':
|
|
||||||
{
|
|
||||||
CHECK_ARGS(0);
|
|
||||||
cell *addr = get_amxaddr(amx, params[arg]);
|
|
||||||
const char *name = "Console";
|
|
||||||
|
|
||||||
if (*addr)
|
|
||||||
{
|
|
||||||
CPlayer *player = NULL;
|
|
||||||
|
|
||||||
if (*addr >= 1 && *addr <= gpGlobals->maxClients)
|
|
||||||
{
|
|
||||||
player = GET_PLAYER_POINTER_I(*addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!player || !player->initialized)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Client index %d is invalid", *addr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = player->name.chars();
|
|
||||||
}
|
|
||||||
|
|
||||||
AddString(&buf_p, llen, name, width, prec);
|
|
||||||
arg++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '%':
|
|
||||||
*buf_p++ = static_cast<D>(ch);
|
|
||||||
if (!llen)
|
|
||||||
goto done;
|
|
||||||
llen--;
|
|
||||||
break;
|
|
||||||
case '\0':
|
|
||||||
*buf_p++ = static_cast<D>('%');
|
|
||||||
if (!llen)
|
|
||||||
goto done;
|
|
||||||
llen--;
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*buf_p++ = static_cast<D>(ch);
|
|
||||||
if (!llen)
|
|
||||||
goto done;
|
|
||||||
llen--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
*buf_p = static_cast<D>(0);
|
|
||||||
*param = arg;
|
|
||||||
|
|
||||||
/* if max buffer length consumed, make sure we don't truncate a multi-byte character */
|
|
||||||
if (llen <= 0 && *(buf_p - 1) & 1 << 7)
|
|
||||||
{
|
|
||||||
llen += UTIL_CheckValidChar(buf_p - 1);
|
|
||||||
*(buf_p - llen) = static_cast<D>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return maxlen-llen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HACKHACK: The compiler will generate code for each case we need.
|
|
||||||
* Don't remove this, otherwise files that use certain code generations
|
|
||||||
* will have extern problems. For each case you need, add dummy code
|
|
||||||
* here.
|
|
||||||
*/
|
|
||||||
void __WHOA_DONT_CALL_ME_PLZ_K_lol_o_O()
|
|
||||||
{
|
|
||||||
//acsprintf
|
|
||||||
atcprintf((cell *)NULL, 0, (const char *)NULL, NULL, NULL, NULL);
|
|
||||||
//accprintf
|
|
||||||
atcprintf((cell *)NULL, 0, (cell *)NULL, NULL, NULL, NULL);
|
|
||||||
//ascprintf
|
|
||||||
atcprintf((char *)NULL, 0, (cell *)NULL, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_FORMATTING_H
|
|
||||||
#define _INCLUDE_FORMATTING_H
|
|
||||||
|
|
||||||
//Amx Templatized Cell Printf
|
|
||||||
template <typename D, typename S>
|
|
||||||
size_t atcprintf(D *buffer, size_t maxlen, const S *format, AMX *amx, cell *params, int *param);
|
|
||||||
|
|
||||||
const char *playerlang(const cell index);
|
|
||||||
const char *translate(AMX *amx, const char *lang, const char *key);
|
|
||||||
|
|
||||||
#endif //_INCLUDE_FORMATTING_H
|
|
@ -1,175 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "gameconfigs.h"
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "CGameConfigs.h"
|
|
||||||
|
|
||||||
NativeHandle<GameConfigNative> GameConfigHandle;
|
|
||||||
|
|
||||||
// native GameConfig:LoadGameConfigFile(const file[]);
|
|
||||||
static cell AMX_NATIVE_CALL LoadGameConfigFile(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int length;
|
|
||||||
const char *filename = get_amxstring(amx, params[1], 0, length);
|
|
||||||
|
|
||||||
IGameConfig *config = nullptr;
|
|
||||||
char error[128];
|
|
||||||
|
|
||||||
if (!ConfigManager.LoadGameConfigFile(filename, &config, error, sizeof(error)))
|
|
||||||
{
|
|
||||||
ConfigManager.CloseGameConfigFile(config);
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Unable to open %s: %s", filename, error);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int handle = GameConfigHandle.create();
|
|
||||||
|
|
||||||
auto configHandle = GameConfigHandle.lookup(handle);
|
|
||||||
|
|
||||||
if (!configHandle)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
configHandle->m_config = config;
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native GameConfGetOffset(GameConfig:handle, const key[]);
|
|
||||||
static cell AMX_NATIVE_CALL GameConfGetOffset(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
GameConfigNative *handle = GameConfigHandle.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!handle)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid game config handle %d", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int length;
|
|
||||||
TypeDescription value;
|
|
||||||
|
|
||||||
const char *key = get_amxstring(amx, params[2], 0, length);
|
|
||||||
|
|
||||||
if (!handle->m_config->GetOffset(key, &value))
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.fieldOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native GameConfGetClassOffset(GameConfig:handle, const classname[], const key[]);
|
|
||||||
static cell AMX_NATIVE_CALL GameConfGetClassOffset(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
GameConfigNative *handle = GameConfigHandle.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!handle)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid game config handle %d", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int length;
|
|
||||||
TypeDescription value;
|
|
||||||
|
|
||||||
const char *classname = get_amxstring(amx, params[2], 0, length);
|
|
||||||
const char *key = get_amxstring(amx, params[3], 1, length);
|
|
||||||
|
|
||||||
if (!handle->m_config->GetOffsetByClass(classname, key, &value))
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.fieldOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native bool:GameConfGetKeyValue(GameConfig:handle, const key[], buffer[], maxlen);
|
|
||||||
static cell AMX_NATIVE_CALL GameConfGetKeyValue(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
GameConfigNative *handle = GameConfigHandle.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!handle)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid game config handle %d", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int length;
|
|
||||||
const char *value;
|
|
||||||
const char *key = get_amxstring(amx, params[2], 0, length);
|
|
||||||
|
|
||||||
if (!(value = handle->m_config->GetKeyValue(key)))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
set_amxstring_utf8(amx, params[3], value, strlen(value), params[4]);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// native GameConfGetAddress(GameConfig:handle, const name[]);
|
|
||||||
static cell AMX_NATIVE_CALL GameConfGetAddress(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
GameConfigNative *handle = GameConfigHandle.lookup(params[1]);
|
|
||||||
|
|
||||||
if (!handle)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid game config handle %d", params[1]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int length;
|
|
||||||
void *value;
|
|
||||||
|
|
||||||
const char *key = get_amxstring(amx, params[2], 0, length);
|
|
||||||
|
|
||||||
if (!handle->m_config->GetAddress(key, &value))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reinterpret_cast<cell>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// native CloseGameConfigFile(&GameConfig:handle);
|
|
||||||
static cell AMX_NATIVE_CALL CloseGameConfigFile(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
cell *address = get_amxaddr(amx, params[1]);
|
|
||||||
|
|
||||||
GameConfigNative *handle = GameConfigHandle.lookup(*address);
|
|
||||||
|
|
||||||
if (!handle)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GameConfigHandle.destroy(*address))
|
|
||||||
{
|
|
||||||
*address = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AMX_NATIVE_INFO g_GameConfigNatives[] =
|
|
||||||
{
|
|
||||||
{ "LoadGameConfigFile" , LoadGameConfigFile },
|
|
||||||
{ "GameConfGetOffset" , GameConfGetOffset },
|
|
||||||
{ "GameConfGetClassOffset", GameConfGetClassOffset },
|
|
||||||
{ "GameConfGetKeyValue" , GameConfGetKeyValue },
|
|
||||||
{ "GameConfGetAddress" , GameConfGetAddress },
|
|
||||||
{ "CloseGameConfigFile" , CloseGameConfigFile },
|
|
||||||
{ nullptr , nullptr }
|
|
||||||
};
|
|
@ -1,18 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "IGameConfigs.h"
|
|
||||||
#include "natives_handles.h"
|
|
||||||
|
|
||||||
struct GameConfigNative
|
|
||||||
{
|
|
||||||
IGameConfig *m_config;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern NativeHandle<GameConfigNative> GameConfigHandle;
|
|
@ -1,52 +0,0 @@
|
|||||||
; vim: set ts=4 sw=4 tw=99 noet ft=nasm:
|
|
||||||
;
|
|
||||||
; AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
; Copyright (C) The AMX Mod X Development Team.
|
|
||||||
;
|
|
||||||
; This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
; Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
; https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
section .text
|
|
||||||
|
|
||||||
global amxx_CpuSupport, _amxx_CpuSupport
|
|
||||||
|
|
||||||
amxx_CpuSupport:
|
|
||||||
_amxx_CpuSupport:
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
|
|
||||||
push ebx
|
|
||||||
|
|
||||||
mov eax, 0
|
|
||||||
cpuid
|
|
||||||
cmp eax, 1
|
|
||||||
jl .fail
|
|
||||||
|
|
||||||
mov eax, 1
|
|
||||||
cpuid
|
|
||||||
;check if family == 5 or 4
|
|
||||||
and eax, 0780h ;family mask
|
|
||||||
shr eax, 7 ;family shift
|
|
||||||
cmp eax, 5
|
|
||||||
je .fail
|
|
||||||
cmp eax, 4
|
|
||||||
je .fail
|
|
||||||
;check if CMOV exists
|
|
||||||
shr edx, 15
|
|
||||||
and edx, 1
|
|
||||||
cmp edx, 0
|
|
||||||
je .fail
|
|
||||||
|
|
||||||
mov eax, 1
|
|
||||||
jmp .end
|
|
||||||
|
|
||||||
.fail:
|
|
||||||
xor eax, eax
|
|
||||||
|
|
||||||
.end:
|
|
||||||
|
|
||||||
pop ebx
|
|
||||||
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
@ -1,252 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "libraries.h"
|
|
||||||
#include "sh_list.h"
|
|
||||||
|
|
||||||
List<Library *> g_libraries;
|
|
||||||
|
|
||||||
bool AddLibrary(const char *name, LibType type, LibSource src, void *parent)
|
|
||||||
{
|
|
||||||
if (FindLibrary(name, type))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Library *lib = new Library;
|
|
||||||
|
|
||||||
lib->name = name;
|
|
||||||
lib->type = type;
|
|
||||||
lib->src = src;
|
|
||||||
lib->parent = parent;
|
|
||||||
|
|
||||||
g_libraries.push_back(lib);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DecodeLibCmdString(const char *str, LibDecoder *dec)
|
|
||||||
{
|
|
||||||
if (dec->buffer)
|
|
||||||
{
|
|
||||||
free(dec->buffer);
|
|
||||||
dec->buffer = NULL;
|
|
||||||
}
|
|
||||||
if (str[0] != '?')
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
str++;
|
|
||||||
if (*str == 'r')
|
|
||||||
{
|
|
||||||
str++;
|
|
||||||
if (*str == 'c')
|
|
||||||
dec->cmd = LibCmd_ReqClass;
|
|
||||||
else if (*str == 'l')
|
|
||||||
dec->cmd = LibCmd_ReqLib;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
str++;
|
|
||||||
} else if (*str == 'f') {
|
|
||||||
str++;
|
|
||||||
dec->cmd = LibCmd_ForceLib;
|
|
||||||
} else if (*str == 'e') {
|
|
||||||
str++;
|
|
||||||
if (*str == 'c')
|
|
||||||
dec->cmd = LibCmd_ExpectClass;
|
|
||||||
else if (*str == 'l')
|
|
||||||
dec->cmd = LibCmd_ExpectLib;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
str++;
|
|
||||||
} else if (*str == 'd') {
|
|
||||||
str++;
|
|
||||||
dec->cmd = LibCmd_DefaultLib;
|
|
||||||
}
|
|
||||||
if (*str != '_')
|
|
||||||
return false;
|
|
||||||
str++;
|
|
||||||
if (dec->cmd < LibCmd_ExpectLib)
|
|
||||||
{
|
|
||||||
dec->buffer = strdup(str);
|
|
||||||
dec->param1 = dec->buffer;
|
|
||||||
dec->param2 = NULL;
|
|
||||||
} else {
|
|
||||||
dec->buffer = strdup(str);
|
|
||||||
char *p = strchr(dec->buffer, '_');
|
|
||||||
while (p && (*(p+1) == '_'))
|
|
||||||
p = strchr(p+2, '_');
|
|
||||||
if (!p || !*(p+1))
|
|
||||||
return false;
|
|
||||||
*p = '\0';
|
|
||||||
dec->param1 = dec->buffer;
|
|
||||||
dec->param2 = p+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AddLibrariesFromString(const char *name, LibType type, LibSource src, void *parent)
|
|
||||||
{
|
|
||||||
char buffer[255];
|
|
||||||
char *ptr, *p, s;
|
|
||||||
size_t count = 0;
|
|
||||||
|
|
||||||
ke::SafeSprintf(buffer, sizeof(buffer), "%s", name);
|
|
||||||
|
|
||||||
ptr = buffer;
|
|
||||||
p = buffer;
|
|
||||||
while (*p)
|
|
||||||
{
|
|
||||||
while (*p && (*p != ','))
|
|
||||||
p++;
|
|
||||||
s = *p;
|
|
||||||
*p = '\0';
|
|
||||||
if (AddLibrary(ptr, type, src, parent))
|
|
||||||
count++;
|
|
||||||
if (!s)
|
|
||||||
break;
|
|
||||||
p++;
|
|
||||||
while (*p && (*p == ','))
|
|
||||||
p++;
|
|
||||||
ptr = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ClearLibraries(LibSource src)
|
|
||||||
{
|
|
||||||
List<Library *>::iterator iter;
|
|
||||||
size_t count = 0;
|
|
||||||
|
|
||||||
iter = g_libraries.begin();
|
|
||||||
while (iter != g_libraries.end())
|
|
||||||
{
|
|
||||||
if ( (*iter)->src == src )
|
|
||||||
{
|
|
||||||
delete (*iter);
|
|
||||||
iter = g_libraries.erase(iter);
|
|
||||||
count++;
|
|
||||||
} else {
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t RemoveLibraries(void *parent)
|
|
||||||
{
|
|
||||||
List<Library *>::iterator iter;
|
|
||||||
Library *lib;
|
|
||||||
size_t count = 0;
|
|
||||||
|
|
||||||
iter = g_libraries.begin();
|
|
||||||
while (iter != g_libraries.end())
|
|
||||||
{
|
|
||||||
lib = (*iter);
|
|
||||||
if (lib->parent == parent)
|
|
||||||
{
|
|
||||||
delete (*iter);
|
|
||||||
iter = g_libraries.erase(iter);
|
|
||||||
count++;
|
|
||||||
} else {
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FindLibrary(const char *name, LibType type)
|
|
||||||
{
|
|
||||||
List<Library *>::iterator iter;
|
|
||||||
Library *lib;
|
|
||||||
|
|
||||||
for (iter = g_libraries.begin(); iter != g_libraries.end(); iter++)
|
|
||||||
{
|
|
||||||
lib = (*iter);
|
|
||||||
if (lib->type != type)
|
|
||||||
continue;
|
|
||||||
if (strcasecmp(lib->name.chars(), name) == 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LibError RunLibCommand(const LibDecoder *enc)
|
|
||||||
{
|
|
||||||
List<Library *>::iterator iter,end;
|
|
||||||
Library *lib;
|
|
||||||
|
|
||||||
iter = g_libraries.begin();
|
|
||||||
end = g_libraries.end();
|
|
||||||
|
|
||||||
if ( (enc->cmd == LibCmd_ReqLib) || (enc->cmd == LibCmd_ReqClass) )
|
|
||||||
{
|
|
||||||
LibType expect = LibType_Library;
|
|
||||||
|
|
||||||
if (enc->cmd == LibCmd_ReqLib)
|
|
||||||
expect = LibType_Library;
|
|
||||||
else if (enc->cmd == LibCmd_ReqClass)
|
|
||||||
expect = LibType_Class;
|
|
||||||
|
|
||||||
/** see if it exists */
|
|
||||||
for (; iter != end; iter++)
|
|
||||||
{
|
|
||||||
lib = (*iter);
|
|
||||||
if (lib->type != expect)
|
|
||||||
continue;
|
|
||||||
if (strcasecmp(lib->name.chars(), enc->param1) == 0)
|
|
||||||
return LibErr_None;
|
|
||||||
}
|
|
||||||
if (expect == LibType_Library)
|
|
||||||
return LibErr_NoLibrary;
|
|
||||||
else if (expect == LibType_Class)
|
|
||||||
return LibErr_NoClass;
|
|
||||||
|
|
||||||
return LibErr_NoLibrary;
|
|
||||||
} else if (enc->cmd == LibCmd_ForceLib) {
|
|
||||||
if (!LoadModule(enc->param1, PT_ANYTIME, true, true))
|
|
||||||
{
|
|
||||||
return LibErr_NoLibrary;
|
|
||||||
}
|
|
||||||
} else if ( (enc->cmd == LibCmd_DefaultLib) ||
|
|
||||||
((enc->cmd == LibCmd_ExpectLib) || (enc->cmd == LibCmd_ExpectClass)) )
|
|
||||||
{
|
|
||||||
LibType expect;
|
|
||||||
|
|
||||||
if (enc->cmd == LibCmd_ExpectLib)
|
|
||||||
expect = LibType_Library;
|
|
||||||
else
|
|
||||||
expect = LibType_Class;
|
|
||||||
|
|
||||||
/** see if it exists */
|
|
||||||
for (; iter != end; iter++)
|
|
||||||
{
|
|
||||||
lib = (*iter);
|
|
||||||
if (lib->type != expect)
|
|
||||||
continue;
|
|
||||||
if (strcasecmp(lib->name.chars(), enc->param1) == 0)
|
|
||||||
return LibErr_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!LoadModule(enc->param2, PT_ANYTIME, true, true))
|
|
||||||
{
|
|
||||||
return LibErr_NoLibrary;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LibErr_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LibErr_None;
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _INCLUDE_LIBRARIES_H
|
|
||||||
#define _INCLUDE_LIBRARIES_H
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include "amxmodx.h"
|
|
||||||
|
|
||||||
enum LibSource
|
|
||||||
{
|
|
||||||
LibSource_Plugin,
|
|
||||||
LibSource_Module
|
|
||||||
};
|
|
||||||
|
|
||||||
enum LibType
|
|
||||||
{
|
|
||||||
LibType_Library,
|
|
||||||
LibType_Class
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Library
|
|
||||||
{
|
|
||||||
ke::AString name;
|
|
||||||
LibSource src;
|
|
||||||
LibType type;
|
|
||||||
void *parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum LibCmd
|
|
||||||
{
|
|
||||||
LibCmd_ReqLib,
|
|
||||||
LibCmd_ReqClass,
|
|
||||||
LibCmd_ForceLib,
|
|
||||||
LibCmd_ExpectLib,
|
|
||||||
LibCmd_ExpectClass,
|
|
||||||
LibCmd_DefaultLib,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum LibError
|
|
||||||
{
|
|
||||||
LibErr_None = 0,
|
|
||||||
LibErr_NoLibrary,
|
|
||||||
LibErr_NoClass,
|
|
||||||
};
|
|
||||||
|
|
||||||
class LibDecoder
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LibDecoder() : buffer(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
~LibDecoder()
|
|
||||||
{
|
|
||||||
free(buffer);
|
|
||||||
buffer = NULL;
|
|
||||||
param1 = NULL;
|
|
||||||
param2 = NULL;
|
|
||||||
}
|
|
||||||
char *buffer;
|
|
||||||
char *param1;
|
|
||||||
char *param2;
|
|
||||||
LibCmd cmd;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool AddLibrary(const char *name, LibType type, LibSource src, void *parent=NULL);
|
|
||||||
bool DecodeLibCmdString(const char *str, LibDecoder *cmd);
|
|
||||||
size_t AddLibrariesFromString(const char *name, LibType type, LibSource src, void *parent=NULL);
|
|
||||||
size_t ClearLibraries(LibSource src);
|
|
||||||
LibError RunLibCommand(const LibDecoder *enc);
|
|
||||||
size_t RemoveLibraries(void *parent);
|
|
||||||
bool FindLibrary(const char *name, LibType type);
|
|
||||||
|
|
||||||
|
|
||||||
#endif //_INCLUDE_LIBRARIES_H
|
|
@ -1,908 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#include "amxmodx.h"
|
|
||||||
#include "messages.h"
|
|
||||||
|
|
||||||
Message Msg;
|
|
||||||
RegisteredMessage msgHooks[256];
|
|
||||||
int msgBlocks[256] = {BLOCK_NOT};
|
|
||||||
int msgDest;
|
|
||||||
int msgType;
|
|
||||||
float *msgOrigin;
|
|
||||||
edict_t *msgpEntity;
|
|
||||||
bool inhook = false;
|
|
||||||
bool inblock = false;
|
|
||||||
enginefuncs_t *g_pEngTable = NULL;
|
|
||||||
|
|
||||||
void ClearMessages()
|
|
||||||
{
|
|
||||||
for (size_t i=0; i<MAX_MESSAGES; i++)
|
|
||||||
{
|
|
||||||
msgHooks[i].Clear();
|
|
||||||
msgBlocks[i] = BLOCK_NOT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Message::Message()
|
|
||||||
{
|
|
||||||
m_CurParam = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Message::Ready()
|
|
||||||
{
|
|
||||||
if (!m_Params.length())
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::Init()
|
|
||||||
{
|
|
||||||
if (!Ready())
|
|
||||||
{
|
|
||||||
msgparam *p = new msgparam;
|
|
||||||
m_Params.append(p);
|
|
||||||
}
|
|
||||||
m_CurParam = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Message::~Message()
|
|
||||||
{
|
|
||||||
for (size_t i=0; i<m_Params.length(); i++)
|
|
||||||
delete m_Params[i];
|
|
||||||
|
|
||||||
m_Params.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
msgparam *Message::AdvPtr()
|
|
||||||
{
|
|
||||||
msgparam *pParam = NULL;
|
|
||||||
|
|
||||||
if (++m_CurParam >= m_Params.length())
|
|
||||||
{
|
|
||||||
pParam = new msgparam;
|
|
||||||
m_Params.append(pParam);
|
|
||||||
} else {
|
|
||||||
pParam = m_Params[m_CurParam];
|
|
||||||
}
|
|
||||||
|
|
||||||
return pParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::AddParam(const char *data, msgtype type)
|
|
||||||
{
|
|
||||||
msgparam *pParam = AdvPtr();
|
|
||||||
|
|
||||||
pParam->szData = data;
|
|
||||||
pParam->type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::AddParam(int data, msgtype type)
|
|
||||||
{
|
|
||||||
msgparam *pParam = AdvPtr();
|
|
||||||
|
|
||||||
pParam->v.iData = data;
|
|
||||||
pParam->type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::AddParam(float data, msgtype type)
|
|
||||||
{
|
|
||||||
msgparam *pParam = AdvPtr();
|
|
||||||
|
|
||||||
pParam->v.fData = data;
|
|
||||||
pParam->type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
msgtype Message::GetParamType(size_t index)
|
|
||||||
{
|
|
||||||
if (index < 1 || index > m_CurParam)
|
|
||||||
return static_cast<msgtype>(0);
|
|
||||||
|
|
||||||
return m_Params[index]->type;
|
|
||||||
}
|
|
||||||
|
|
||||||
float Message::GetParamFloat(size_t index)
|
|
||||||
{
|
|
||||||
if (index < 1 || index > m_CurParam)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_Params[index]->v.fData;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *Message::GetParamString(size_t index)
|
|
||||||
{
|
|
||||||
if (index < 1 || index > m_CurParam)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_Params[index]->szData.chars();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Message::GetParamInt(size_t index)
|
|
||||||
{
|
|
||||||
if (index < 1 || index > m_CurParam)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return m_Params[index]->v.iData;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::SetParam(size_t index, float data)
|
|
||||||
{
|
|
||||||
if (index < 1 || index > m_CurParam)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_Params[index]->v.fData = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::SetParam(size_t index, int data)
|
|
||||||
{
|
|
||||||
if (index < 1 || index > m_CurParam)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_Params[index]->v.iData = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::SetParam(size_t index, const char *data)
|
|
||||||
{
|
|
||||||
if (index < 1 || index > m_CurParam)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_Params[index]->szData = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::Reset()
|
|
||||||
{
|
|
||||||
m_CurParam = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Message::Params()
|
|
||||||
{
|
|
||||||
return m_CurParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Message::Send()
|
|
||||||
{
|
|
||||||
msgparam *pParam = NULL;
|
|
||||||
|
|
||||||
for (size_t i=1; i<=m_CurParam; i++)
|
|
||||||
{
|
|
||||||
pParam = m_Params[i];
|
|
||||||
switch (pParam->type)
|
|
||||||
{
|
|
||||||
case arg_byte:
|
|
||||||
WRITE_BYTE(pParam->v.iData);
|
|
||||||
break;
|
|
||||||
case arg_char:
|
|
||||||
WRITE_CHAR(pParam->v.iData);
|
|
||||||
break;
|
|
||||||
case arg_short:
|
|
||||||
WRITE_SHORT(pParam->v.iData);
|
|
||||||
break;
|
|
||||||
case arg_long:
|
|
||||||
WRITE_LONG(pParam->v.iData);
|
|
||||||
break;
|
|
||||||
case arg_angle:
|
|
||||||
WRITE_ANGLE(pParam->v.fData);
|
|
||||||
break;
|
|
||||||
case arg_coord:
|
|
||||||
WRITE_COORD(pParam->v.fData);
|
|
||||||
break;
|
|
||||||
case arg_string:
|
|
||||||
WRITE_STRING(pParam->szData.chars());
|
|
||||||
break;
|
|
||||||
case arg_entity:
|
|
||||||
WRITE_ENTITY(pParam->v.iData);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed)
|
|
||||||
{
|
|
||||||
if (msgBlocks[msg_type])
|
|
||||||
{
|
|
||||||
inblock = true;
|
|
||||||
msgType = msg_type;
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (msgHooks[msg_type].Hooked()) {
|
|
||||||
inhook = true;
|
|
||||||
msgDest = msg_dest;
|
|
||||||
msgType = msg_type;
|
|
||||||
msgOrigin = (float *)pOrigin;
|
|
||||||
msgpEntity = ed;
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_WriteByte(int iValue)
|
|
||||||
{
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
Msg.AddParam(iValue, arg_byte);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_WriteChar(int iValue)
|
|
||||||
{
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
Msg.AddParam(iValue, arg_char);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_WriteShort(int iValue)
|
|
||||||
{
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
Msg.AddParam(iValue, arg_short);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_WriteLong(int iValue)
|
|
||||||
{
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
Msg.AddParam(iValue, arg_long);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_WriteAngle(float flValue)
|
|
||||||
{
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
Msg.AddParam(flValue, arg_angle);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_WriteCoord(float flValue)
|
|
||||||
{
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
Msg.AddParam(flValue, arg_coord);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_WriteString(const char *sz)
|
|
||||||
{
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
Msg.AddParam(sz, arg_string);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_WriteEntity(int iValue)
|
|
||||||
{
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
Msg.AddParam(iValue, arg_entity);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
void C_MessageEnd(void)
|
|
||||||
{
|
|
||||||
int mres = 0;
|
|
||||||
|
|
||||||
if (inblock)
|
|
||||||
{
|
|
||||||
inblock = false;
|
|
||||||
if (msgBlocks[msgType] == BLOCK_ONCE)
|
|
||||||
{
|
|
||||||
msgBlocks[msgType] = BLOCK_NOT;
|
|
||||||
}
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
} else if (inhook) {
|
|
||||||
|
|
||||||
mres = msgHooks[msgType].Execute((cell)msgType, (cell)msgDest, (cell)ENTINDEX(msgpEntity));
|
|
||||||
|
|
||||||
/*
|
|
||||||
for (i=0; i<msgHooks[msgType].size(); i++)
|
|
||||||
{
|
|
||||||
mresB = executeForwards(msgHooks[msgType].at(i), (cell)msgType, (cell)msgDest, (cell)ENTINDEX(msgpEntity));
|
|
||||||
if (mresB > mres)
|
|
||||||
mres = mresB;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
inhook = false;
|
|
||||||
if (mres & 1)
|
|
||||||
{
|
|
||||||
Msg.Reset();
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send the real message */
|
|
||||||
MESSAGE_BEGIN(msgDest, msgType, msgOrigin, msgpEntity);
|
|
||||||
Msg.Send();
|
|
||||||
MESSAGE_END();
|
|
||||||
|
|
||||||
/* reset */
|
|
||||||
Msg.Reset();
|
|
||||||
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_META(MRES_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell _message_begin(AMX *amx, cell *params, bool useFloat) /* 4 param */
|
|
||||||
{
|
|
||||||
int numparam = *params / sizeof(cell);
|
|
||||||
float vecOrigin[3];
|
|
||||||
cell *cpOrigin;
|
|
||||||
|
|
||||||
if (params[2] < 1 || ((params[2] > 63) // maximal number of engine messages
|
|
||||||
&& !GET_USER_MSG_NAME(PLID, params[2], NULL)))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Plugin called message_begin with an invalid message id (%d).", params[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (params[1])
|
|
||||||
{
|
|
||||||
case MSG_BROADCAST:
|
|
||||||
case MSG_ALL:
|
|
||||||
case MSG_SPEC:
|
|
||||||
case MSG_INIT:
|
|
||||||
MESSAGE_BEGIN(params[1], params[2], NULL);
|
|
||||||
break;
|
|
||||||
case MSG_PVS: case MSG_PAS:
|
|
||||||
case MSG_PVS_R: case MSG_PAS_R:
|
|
||||||
if (numparam < 3)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid number of parameters passed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpOrigin = get_amxaddr(amx, params[3]);
|
|
||||||
|
|
||||||
if (!useFloat)
|
|
||||||
{
|
|
||||||
vecOrigin[0] = static_cast<float>(*cpOrigin);
|
|
||||||
vecOrigin[1] = static_cast<float>(*(cpOrigin + 1));
|
|
||||||
vecOrigin[2] = static_cast<float>(*(cpOrigin + 2));
|
|
||||||
} else {
|
|
||||||
vecOrigin[0] = amx_ctof(*cpOrigin);
|
|
||||||
vecOrigin[1] = amx_ctof(*(cpOrigin + 1));
|
|
||||||
vecOrigin[2] = amx_ctof(*(cpOrigin + 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
MESSAGE_BEGIN(params[1], params[2], vecOrigin);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case MSG_ONE_UNRELIABLE:
|
|
||||||
case MSG_ONE:
|
|
||||||
if (numparam < 4)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid number of parameters passed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MESSAGE_BEGIN(params[1], params[2], NULL, TypeConversion.id_to_edict(params[4]));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL message_begin(AMX *amx, cell *params) /* 4 param */
|
|
||||||
{
|
|
||||||
return _message_begin(amx, params, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL message_begin_f(AMX *amx, cell *params) /* 4 param */
|
|
||||||
{
|
|
||||||
return _message_begin(amx, params, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL message_end(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
MESSAGE_END();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_byte(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_BYTE(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_char(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_CHAR(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_short(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_SHORT(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_long(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_LONG(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_entity(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_ENTITY(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_angle(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_ANGLE(static_cast<float>(params[1]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_angle_f(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_ANGLE(amx_ctof(params[1]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_coord(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_COORD(static_cast<float>(params[1]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_coord_f(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
WRITE_COORD(amx_ctof(params[1]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL write_string(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
int a;
|
|
||||||
WRITE_STRING(get_amxstring(amx, params[1], 3, a));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL register_message(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
char *name = get_amxstring(amx, params[2], 0, len);
|
|
||||||
|
|
||||||
if (!Msg.Ready())
|
|
||||||
Msg.Init();
|
|
||||||
|
|
||||||
if (params[1]>0 && params[1] < 256)
|
|
||||||
{
|
|
||||||
int id = registerSPForwardByName(amx, name, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
|
||||||
if (id != -1)
|
|
||||||
{
|
|
||||||
msgHooks[params[1]].AddHook(id);
|
|
||||||
return id;
|
|
||||||
} else {
|
|
||||||
LogError(amx, AMX_ERR_NOTFOUND, "Could not find function \"%s\"", name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// unregister_message(msgid, msghandle)
|
|
||||||
static cell AMX_NATIVE_CALL unregister_message(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
if (!Msg.Ready())
|
|
||||||
Msg.Init();
|
|
||||||
|
|
||||||
if (params[1]>0 && params[1] < 256)
|
|
||||||
{
|
|
||||||
int id = params[2];
|
|
||||||
if (id != -1)
|
|
||||||
{
|
|
||||||
msgHooks[params[1]].RemoveHook(id);
|
|
||||||
return id;
|
|
||||||
} else {
|
|
||||||
LogError(amx, AMX_ERR_NOTFOUND, "Invalid registered message handle");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL set_msg_block(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int msgid = params[1];
|
|
||||||
int block = params[2];
|
|
||||||
|
|
||||||
if (msgid < 1 || msgid > 255)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message id");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
msgBlocks[msgid] = block;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL get_msg_block(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
int msgid = params[1];
|
|
||||||
|
|
||||||
if (msgid < 1 || msgid > 255)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message id");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return msgBlocks[msgid];
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL get_msg_args(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
return Msg.Params();
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL get_msg_argtype(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
size_t argn = static_cast<size_t>(params[1]);
|
|
||||||
|
|
||||||
if (!inhook || argn > Msg.Params())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message argument %d", argn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Msg.GetParamType(argn);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL get_msg_arg_int(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
size_t argn = static_cast<size_t>(params[1]);
|
|
||||||
|
|
||||||
if (!inhook || argn > Msg.Params())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message argument %d", argn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Msg.GetParamInt(argn);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL set_msg_arg_int(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
size_t argn = static_cast<size_t>(params[1]);
|
|
||||||
|
|
||||||
if (!inhook || argn > Msg.Params())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message argument %d", argn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Msg.SetParam(argn, (int)params[3]);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL get_msg_arg_float(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
size_t argn = static_cast<size_t>(params[1]);
|
|
||||||
|
|
||||||
if (!inhook || argn > Msg.Params())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message argument %d", argn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
REAL f = (REAL)Msg.GetParamFloat(argn);
|
|
||||||
return amx_ftoc(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL set_msg_arg_float(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
size_t argn = static_cast<size_t>(params[1]);
|
|
||||||
|
|
||||||
if (!inhook || argn > Msg.Params())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message argument %d", argn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
REAL fVal = amx_ctof(params[3]);
|
|
||||||
|
|
||||||
Msg.SetParam(argn, (float)fVal);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL get_msg_arg_string(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
size_t argn = static_cast<size_t>(params[1]);
|
|
||||||
|
|
||||||
if (!inhook || argn > Msg.Params())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message argument %d", argn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *szVal = Msg.GetParamString(argn);
|
|
||||||
|
|
||||||
return set_amxstring(amx, params[2], szVal, params[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL set_msg_arg_string(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
size_t argn = static_cast<size_t>(params[1]);
|
|
||||||
int iLen;
|
|
||||||
|
|
||||||
if (!inhook || argn > Msg.Params())
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid message argument %d", argn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *szVal = get_amxstring(amx, params[2], 0, iLen);
|
|
||||||
|
|
||||||
Msg.SetParam(argn, szVal);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL get_msg_origin(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
if (!inhook)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Not in a message hook");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell *cAddr = get_amxaddr(amx, params[1]);
|
|
||||||
|
|
||||||
if (msgDest >= MSG_PVS && msgDest <= MSG_PAS_R)
|
|
||||||
{
|
|
||||||
vec3_t vRet = (Vector)msgOrigin;
|
|
||||||
cAddr[0] = FloatToCell(vRet.x);
|
|
||||||
cAddr[1] = FloatToCell(vRet.y);
|
|
||||||
cAddr[2] = FloatToCell(vRet.z);
|
|
||||||
} else {
|
|
||||||
cAddr[0] = 0;
|
|
||||||
cAddr[1] = 0;
|
|
||||||
cAddr[2] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell _emessage_begin(AMX *amx, cell *params, bool useFloat)
|
|
||||||
{
|
|
||||||
int numparam = *params / sizeof(cell);
|
|
||||||
float vecOrigin[3];
|
|
||||||
cell *cpOrigin;
|
|
||||||
|
|
||||||
if (params[2] < 1 || ((params[2] > 63) // maximal number of engine messages
|
|
||||||
&& !GET_USER_MSG_NAME(PLID, params[2], NULL)))
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Plugin called message_begin with an invalid message id (%d).", params[2]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (params[1])
|
|
||||||
{
|
|
||||||
case MSG_BROADCAST:
|
|
||||||
case MSG_ALL:
|
|
||||||
case MSG_SPEC:
|
|
||||||
g_pEngTable->pfnMessageBegin(params[1], params[2], NULL, NULL);
|
|
||||||
break;
|
|
||||||
case MSG_PVS: case MSG_PAS:
|
|
||||||
case MSG_PVS_R: case MSG_PAS_R:
|
|
||||||
if (numparam < 3)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid number of parameters passed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpOrigin = get_amxaddr(amx, params[3]);
|
|
||||||
|
|
||||||
if (!useFloat)
|
|
||||||
{
|
|
||||||
vecOrigin[0] = static_cast<float>(*cpOrigin);
|
|
||||||
vecOrigin[1] = static_cast<float>(*(cpOrigin + 1));
|
|
||||||
vecOrigin[2] = static_cast<float>(*(cpOrigin + 2));
|
|
||||||
} else {
|
|
||||||
vecOrigin[0] = amx_ctof(*cpOrigin);
|
|
||||||
vecOrigin[1] = amx_ctof(*(cpOrigin + 1));
|
|
||||||
vecOrigin[2] = amx_ctof(*(cpOrigin + 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_pEngTable->pfnMessageBegin(params[1], params[2], vecOrigin, NULL);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case MSG_ONE_UNRELIABLE:
|
|
||||||
case MSG_ONE:
|
|
||||||
if (numparam < 4)
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid number of parameters passed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_pEngTable->pfnMessageBegin(params[1], params[2], NULL, TypeConversion.id_to_edict(params[4]));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL emessage_begin(AMX *amx, cell *params) /* 4 param */
|
|
||||||
{
|
|
||||||
return _emessage_begin(amx, params, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL emessage_begin_f(AMX *amx, cell *params) /* 4 param */
|
|
||||||
{
|
|
||||||
return _emessage_begin(amx, params, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL emessage_end(AMX *amx, cell *params)
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnMessageEnd();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_byte(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteByte(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_char(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteChar(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_short(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteShort(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_long(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteLong(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_entity(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteEntity(params[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_angle(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteAngle(static_cast<float>(params[1]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_angle_f(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteAngle(amx_ctof(params[1]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_coord(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteCoord(static_cast<float>(params[1]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_coord_f(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
g_pEngTable->pfnWriteCoord(amx_ctof(params[1]));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static cell AMX_NATIVE_CALL ewrite_string(AMX *amx, cell *params) /* 1 param */
|
|
||||||
{
|
|
||||||
int a;
|
|
||||||
g_pEngTable->pfnWriteString(get_amxstring(amx, params[1], 3, a));
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
AMX_NATIVE_INFO msg_Natives[] =
|
|
||||||
{
|
|
||||||
{"message_begin", message_begin},
|
|
||||||
{"message_begin_f", message_begin_f},
|
|
||||||
{"message_end", message_end},
|
|
||||||
|
|
||||||
{"write_angle", write_angle},
|
|
||||||
{"write_angle_f", write_angle_f},
|
|
||||||
{"write_byte", write_byte},
|
|
||||||
{"write_char", write_char},
|
|
||||||
{"write_coord", write_coord},
|
|
||||||
{"write_coord_f", write_coord_f},
|
|
||||||
{"write_entity", write_entity},
|
|
||||||
{"write_long", write_long},
|
|
||||||
{"write_short", write_short},
|
|
||||||
{"write_string", write_string},
|
|
||||||
|
|
||||||
{"register_message", register_message},
|
|
||||||
{"unregister_message", unregister_message},
|
|
||||||
|
|
||||||
{"set_msg_block", set_msg_block},
|
|
||||||
{"get_msg_block", get_msg_block},
|
|
||||||
|
|
||||||
{"get_msg_args", get_msg_args},
|
|
||||||
{"get_msg_argtype", get_msg_argtype},
|
|
||||||
{"get_msg_arg_int", get_msg_arg_int},
|
|
||||||
{"set_msg_arg_int", set_msg_arg_int},
|
|
||||||
{"get_msg_arg_float", get_msg_arg_float},
|
|
||||||
{"set_msg_arg_float", set_msg_arg_float},
|
|
||||||
{"get_msg_arg_string", get_msg_arg_string},
|
|
||||||
{"set_msg_arg_string", set_msg_arg_string},
|
|
||||||
{"get_msg_origin", get_msg_origin},
|
|
||||||
|
|
||||||
{"emessage_begin", emessage_begin},
|
|
||||||
{"emessage_begin_f", emessage_begin_f},
|
|
||||||
{"emessage_end", emessage_end},
|
|
||||||
|
|
||||||
{"ewrite_angle", ewrite_angle},
|
|
||||||
{"ewrite_angle_f", ewrite_angle_f},
|
|
||||||
{"ewrite_byte", ewrite_byte},
|
|
||||||
{"ewrite_char", ewrite_char},
|
|
||||||
{"ewrite_coord", ewrite_coord},
|
|
||||||
{"ewrite_coord_f", ewrite_coord_f},
|
|
||||||
{"ewrite_entity", ewrite_entity},
|
|
||||||
{"ewrite_long", ewrite_long},
|
|
||||||
{"ewrite_short", ewrite_short},
|
|
||||||
{"ewrite_string", ewrite_string},
|
|
||||||
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
@ -1,216 +0,0 @@
|
|||||||
// vim: set ts=4 sw=4 tw=99 noet:
|
|
||||||
//
|
|
||||||
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
|
|
||||||
// Copyright (C) The AMX Mod X Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the GNU General Public License, version 3 or higher.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://alliedmods.net/amxmodx-license
|
|
||||||
|
|
||||||
#ifndef _MSGS_INCLUDE_H
|
|
||||||
#define _MSGS_INCLUDE_H
|
|
||||||
|
|
||||||
#include <extdll.h>
|
|
||||||
#include <meta_api.h>
|
|
||||||
#include "amx.h"
|
|
||||||
#include "sh_stack.h"
|
|
||||||
|
|
||||||
#define MAX_MESSAGES 255
|
|
||||||
|
|
||||||
#define MSGBLOCK_SET 0
|
|
||||||
#define MSGBLOCK_GET 1
|
|
||||||
#define BLOCK_NOT 0
|
|
||||||
#define BLOCK_ONCE 1
|
|
||||||
#define BLOCK_SET 2
|
|
||||||
|
|
||||||
class RegisteredMessage
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
ke::Vector<int> m_Forwards;
|
|
||||||
CStack<int> m_InExecution;
|
|
||||||
bool m_Cleanup;
|
|
||||||
|
|
||||||
public:
|
|
||||||
RegisteredMessage() : m_Cleanup(false) { }
|
|
||||||
~RegisteredMessage() { this->Clear(); }
|
|
||||||
|
|
||||||
void AddHook(int fwd)
|
|
||||||
{
|
|
||||||
m_Forwards.append(fwd);
|
|
||||||
}
|
|
||||||
bool RemoveHook(int fwd)
|
|
||||||
{
|
|
||||||
// Don't erase a forward if we're in the middle of execution; this
|
|
||||||
// could throw off the iterator that is going through the forwards
|
|
||||||
// and executing them. Instead, unregister the forward and set it
|
|
||||||
// to -1 from within the vector.
|
|
||||||
if (m_InExecution.size())
|
|
||||||
{
|
|
||||||
this->m_Cleanup = true;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < m_Forwards.length(); ++i)
|
|
||||||
{
|
|
||||||
int& forward = m_Forwards[i];
|
|
||||||
|
|
||||||
if (forward == fwd)
|
|
||||||
{
|
|
||||||
if (forward != -1)
|
|
||||||
{
|
|
||||||
unregisterSPForward(forward);
|
|
||||||
}
|
|
||||||
|
|
||||||
forward = -1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < m_Forwards.length(); ++i)
|
|
||||||
{
|
|
||||||
int forward = m_Forwards[i];
|
|
||||||
|
|
||||||
if (forward == fwd)
|
|
||||||
{
|
|
||||||
if (forward != -1)
|
|
||||||
{
|
|
||||||
unregisterSPForward(forward);
|
|
||||||
|
|
||||||
m_Forwards.remove(forward);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// -1 could be in here more than once
|
|
||||||
m_Forwards.remove(forward);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear()
|
|
||||||
{
|
|
||||||
while (m_InExecution.size())
|
|
||||||
{
|
|
||||||
m_InExecution.pop();
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < m_Forwards.length(); i++)
|
|
||||||
{
|
|
||||||
int fwd = m_Forwards[i];
|
|
||||||
|
|
||||||
if (fwd != -1)
|
|
||||||
{
|
|
||||||
unregisterSPForward(m_Forwards[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Forwards.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
cell Execute(cell type, cell dest, cell entity)
|
|
||||||
{
|
|
||||||
m_InExecution.push(1);
|
|
||||||
cell res = 0;
|
|
||||||
cell thisres = 0;
|
|
||||||
for (size_t i = 0; i < m_Forwards.length(); i++)
|
|
||||||
{
|
|
||||||
int fwd = m_Forwards[i];
|
|
||||||
|
|
||||||
if (fwd != -1)
|
|
||||||
{
|
|
||||||
thisres = executeForwards(fwd, type, dest, entity);
|
|
||||||
if (thisres > res)
|
|
||||||
{
|
|
||||||
res = thisres;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_InExecution.pop();
|
|
||||||
|
|
||||||
if (m_InExecution.size() == 0 && m_Cleanup)
|
|
||||||
{
|
|
||||||
this->RemoveHook(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
bool Hooked() const
|
|
||||||
{
|
|
||||||
return m_Forwards.length() != 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
enum msgtype
|
|
||||||
{
|
|
||||||
arg_byte = 1,
|
|
||||||
arg_char,
|
|
||||||
arg_short,
|
|
||||||
arg_long,
|
|
||||||
arg_angle,
|
|
||||||
arg_coord,
|
|
||||||
arg_string,
|
|
||||||
arg_entity,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct msgparam
|
|
||||||
{
|
|
||||||
msgtype type;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
REAL fData;
|
|
||||||
int iData;
|
|
||||||
} v;
|
|
||||||
ke::AString szData;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Message
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Message();
|
|
||||||
~Message();
|
|
||||||
void AddParam(float data, msgtype type);
|
|
||||||
void AddParam(int data, msgtype type);
|
|
||||||
void AddParam(const char *data, msgtype type);
|
|
||||||
void SetParam(size_t index, float data);
|
|
||||||
void SetParam(size_t index, int data);
|
|
||||||
void SetParam(size_t index, const char *data);
|
|
||||||
const char *GetParamString(size_t index);
|
|
||||||
float GetParamFloat(size_t index);
|
|
||||||
bool Ready();
|
|
||||||
void Init();
|
|
||||||
int GetParamInt(size_t index);
|
|
||||||
msgtype GetParamType(size_t index);
|
|
||||||
void Reset();
|
|
||||||
void Send();
|
|
||||||
size_t Params();
|
|
||||||
private:
|
|
||||||
msgparam *AdvPtr();
|
|
||||||
private:
|
|
||||||
ke::Vector<msgparam *> m_Params;
|
|
||||||
size_t m_CurParam;
|
|
||||||
};
|
|
||||||
|
|
||||||
void C_MessageBegin(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);
|
|
||||||
void C_WriteByte(int iValue);
|
|
||||||
void C_WriteChar(int iValue);
|
|
||||||
void C_WriteShort(int iValue);
|
|
||||||
void C_WriteLong(int iValue);
|
|
||||||
void C_WriteAngle(float flValue);
|
|
||||||
void C_WriteCoord(float flValue);
|
|
||||||
void C_WriteString(const char *sz);
|
|
||||||
void C_WriteEntity(int iValue);
|
|
||||||
void C_MessageEnd(void);
|
|
||||||
|
|
||||||
extern RegisteredMessage msgHooks[256];
|
|
||||||
extern int msgBlocks[256];
|
|
||||||
|
|
||||||
void ClearMessages();
|
|
||||||
|
|
||||||
#endif //_MSGS_INCLUDE_H
|
|
||||||
|
|
1832
amxmodx/meta_api.cpp
1832
amxmodx/meta_api.cpp
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,146 +0,0 @@
|
|||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Copyright 2000, Paul Nettle. All rights reserved.
|
|
||||||
//
|
|
||||||
// You are free to use this source code in any commercial or non-commercial product.
|
|
||||||
//
|
|
||||||
// mmgr.h - Memory manager & tracking software
|
|
||||||
//
|
|
||||||
// The most recent version of this software can be found at: ftp://ftp.GraphicsPapers.com/pub/ProgrammingTools/MemoryManagers/
|
|
||||||
//
|
|
||||||
// [NOTE: Best when viewed with 8-character tabs]
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifndef _H_MMGR
|
|
||||||
#define _H_MMGR
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// For systems that don't have the __FUNCTION__ variable, we can just define it here
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifndef __FUNCTION__
|
|
||||||
#define __FUNCTION__ "??"
|
|
||||||
#endif // #ifndef __FUNCTION__
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Types
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
typedef struct tag_au
|
|
||||||
{
|
|
||||||
size_t actualSize;
|
|
||||||
size_t reportedSize;
|
|
||||||
void *actualAddress;
|
|
||||||
void *reportedAddress;
|
|
||||||
char sourceFile[40];
|
|
||||||
char sourceFunc[40];
|
|
||||||
unsigned int sourceLine;
|
|
||||||
unsigned int allocationType;
|
|
||||||
bool breakOnDealloc;
|
|
||||||
bool breakOnRealloc;
|
|
||||||
unsigned int allocationNumber;
|
|
||||||
struct tag_au *next;
|
|
||||||
struct tag_au *prev;
|
|
||||||
} sAllocUnit;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
unsigned int totalReportedMemory;
|
|
||||||
unsigned int totalActualMemory;
|
|
||||||
unsigned int peakReportedMemory;
|
|
||||||
unsigned int peakActualMemory;
|
|
||||||
unsigned int accumulatedReportedMemory;
|
|
||||||
unsigned int accumulatedActualMemory;
|
|
||||||
unsigned int accumulatedAllocUnitCount;
|
|
||||||
unsigned int totalAllocUnitCount;
|
|
||||||
unsigned int peakAllocUnitCount;
|
|
||||||
} sMStats;
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// External constants
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
extern const unsigned int m_alloc_unknown;
|
|
||||||
extern const unsigned int m_alloc_new;
|
|
||||||
extern const unsigned int m_alloc_new_array;
|
|
||||||
extern const unsigned int m_alloc_malloc;
|
|
||||||
extern const unsigned int m_alloc_calloc;
|
|
||||||
extern const unsigned int m_alloc_realloc;
|
|
||||||
extern const unsigned int m_alloc_delete;
|
|
||||||
extern const unsigned int m_alloc_delete_array;
|
|
||||||
extern const unsigned int m_alloc_free;
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Used by the macros
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void m_setOwner(const char *file, const unsigned int line, const char *func);
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Allocation breakpoints
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool &m_breakOnRealloc(void *reportedAddress);
|
|
||||||
bool &m_breakOnDealloc(void *reportedAddress);
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// The meat of the memory tracking software
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void *m_allocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc,
|
|
||||||
const unsigned int allocationType, const size_t reportedSize);
|
|
||||||
void *m_reallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc,
|
|
||||||
const unsigned int reallocationType, const size_t reportedSize, void *reportedAddress);
|
|
||||||
void m_deallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc,
|
|
||||||
const unsigned int deallocationType, const void *reportedAddress);
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Utilitarian functions
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool m_validateAddress(const void *reportedAddress);
|
|
||||||
bool m_validateAllocUnit(const sAllocUnit *allocUnit);
|
|
||||||
bool m_validateAllAllocUnits();
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Unused RAM calculations
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
unsigned int m_calcUnused(const sAllocUnit *allocUnit);
|
|
||||||
unsigned int m_calcAllUnused();
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Logging and reporting
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void m_dumpAllocUnit(const sAllocUnit *allocUnit, const char *prefix = "");
|
|
||||||
void m_dumpMemoryReport(const char *filename = "memreport.log", const bool overwrite = true);
|
|
||||||
sMStats m_getMemoryStatistics();
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Variations of global operators new & delete
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void *operator new(size_t reportedSize);
|
|
||||||
void *operator new[](size_t reportedSize);
|
|
||||||
void *operator new(size_t reportedSize, const char *sourceFile, int sourceLine);
|
|
||||||
void *operator new[](size_t reportedSize, const char *sourceFile, int sourceLine);
|
|
||||||
void operator delete(void *reportedAddress);
|
|
||||||
void operator delete[](void *reportedAddress);
|
|
||||||
|
|
||||||
#endif // _H_MMGR
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Macros -- "Kids, please don't try this at home. We're trained professionals here." :)
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#include "nommgr.h"
|
|
||||||
#define new (m_setOwner (__FILE__,__LINE__,__FUNCTION__),false) ? NULL : new
|
|
||||||
#define delete (m_setOwner (__FILE__,__LINE__,__FUNCTION__),false) ? m_setOwner("",0,"") : delete
|
|
||||||
#define malloc(sz) m_allocator (__FILE__,__LINE__,__FUNCTION__,m_alloc_malloc,sz)
|
|
||||||
#define calloc(sz) m_allocator (__FILE__,__LINE__,__FUNCTION__,m_alloc_calloc,sz)
|
|
||||||
#define realloc(ptr,sz) m_reallocator(__FILE__,__LINE__,__FUNCTION__,m_alloc_realloc,sz,ptr)
|
|
||||||
#define free(ptr) m_deallocator(__FILE__,__LINE__,__FUNCTION__,m_alloc_free,ptr)
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// mmgr.h - End of file
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
@ -1,39 +0,0 @@
|
|||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Copyright 2000, Paul Nettle. All rights reserved.
|
|
||||||
//
|
|
||||||
// You are free to use this source code in any commercial or non-commercial product.
|
|
||||||
//
|
|
||||||
// nommgr.h - Memory manager & tracking software
|
|
||||||
//
|
|
||||||
// The most recent version of this software can be found at: ftp://ftp.GraphicsPapers.com/pub/ProgrammingTools/MemoryManagers/
|
|
||||||
//
|
|
||||||
// [NOTE: Best when viewed with 8-character tabs]
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#ifdef new
|
|
||||||
#undef new
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef delete
|
|
||||||
#undef delete
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef malloc
|
|
||||||
#undef malloc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef calloc
|
|
||||||
#undef calloc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef realloc
|
|
||||||
#undef realloc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef free
|
|
||||||
#undef free
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// nommgr.h - End of file
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------------------
|
|
2057
amxmodx/modules.cpp
2057
amxmodx/modules.cpp
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user