Compare commits

...
Author SHA1 Message Date
BotoX 313c555e2e Add "Restart Current Map" to sm_map menu. 2024-06-09 17:45:27 +02:00
BotoX e5fed0051b Fix GetClientCount(false) 2024-06-09 17:45:27 +02:00
BotoX c2a86c77fd Add damageCustom argument to SDKHooks_TakeDamage native. 2024-06-09 17:45:24 +02:00
BotoX 8c534e770b fix IsMapValid behavior change by a2246af121 2024-06-09 17:41:10 +02:00
BotoX 2c86e8099a Add OnEntitySpawned to SDKHooks. 2024-06-09 17:41:10 +02:00
BotoX 03eeb23ab3 Implement per-client randomized menus with MenuShufflePerClient native.
Add MenuSetClientMapping native.
2024-06-09 17:41:05 +02:00
BotoX a9c85d8842 Changes on sm_*say 2024-06-09 17:39:34 +02:00
BotoX 850ee60a18 Add GetClientIClient native. 2024-06-09 17:39:34 +02:00
Obuss 7cd130904b Logging changes to various base plugins. 2024-06-09 17:39:30 +02:00
BotoX 19019d3a4b Extend function calling API for natives and allow catching exceptions.
Change sourcepawn url.
2024-06-09 17:34:33 +02:00
BotoX b31375f087 Fix @spec not targeting clients in unassigned team. 2024-06-09 17:33:19 +02:00
BotoX 1d999c3984 Added hack to make plugins open a menu with all possible targets on ReplyToTargetError COMMAND_TARGET_AMBIGUOUS.
Explanation:
There are two clients in the server, one named gene, the other one "Ene ~special characters~".
An admin issues "sm_slay Ene" and gets following error message: More than one client matched the given pattern.
What this hack will do is: Use GetCmdArg(0, ...); to get the command name "sm_slay".
Use GetCmdArgString(...); to get the arguments supplied to the command.
Use GetLastProcessTargetString(...); (which was implemented in this commit) to retrieve the arguments that were passed to the last ProcessTargetString call.
It will then pass this data to the DynamicTargeting plugin through its AmbiguousMenu native.
The plugin will open up a menu on the client and list all targets which match the pattern that was supplied to ProcessTargetString.
If the client selects a menu entry, FakeClientCommand will be used to re-execute the command with the correct target.
2024-06-09 17:33:16 +02:00
BotoX fdcbdb6918 Add more macros to CDetour. 2024-06-09 17:32:32 +02:00
d42a8c7c1e Move Safetyhook mess into a mirror repo (#2163)
* Bring in safetyhook mirror repo

* Add proper submodule

* Update submodule for linux fixes

* Update submodule again

* Change the method of compiling safetyhook (#2167)

Co-authored-by: Kenzzer <[email protected]>

* Update submodule

* Update submodule for -fPIC

---------

Co-authored-by: Benoist <[email protected]>
Co-authored-by: Kenzzer <[email protected]>
2024-06-08 20:05:29 +00:00
BenoistandKenzzer 11d3cf94f7 Add GetFilePermissions (#2177)
Co-authored-by: Kenzzer <[email protected]>
2024-06-08 14:17:50 +00:00
Nick Hastings 0e4b1ca4cf Revert "Update sourcepawn submodule (#2146)"
This reverts commit 1bcc5b8a44.
2024-06-08 09:26:13 -04:00
suza 1bcc5b8a44 Update sourcepawn submodule (#2146)
Update SourcePawn and AMTL.
2024-06-04 16:24:22 -07:00
BenoistandKenzzer 7df2f8e045 Reconcile the concept of Edict & Networkable across the codebase (#1903)
* Reconcile the concept of Edict & Networkable across the codebase

* There's no need to check this, it's done elsewhere. Also could be null (segfault)

* This was never needed

* Pseudo review changes

Re-added removed null checks, and added new ones.

Changed the error messages in Get/SetProp natives to better reflect reality.

* Don't change the behaviour of GetEntityNetClass

* Overload IGameHelpers::FindServerClass

* Make error messages more accurate

* Fix a dev comment

* Rename FindServerClass

---------

Co-authored-by: Kenzzer <[email protected]>
2024-06-01 14:07:55 +00:00
1mpulse 9f3584a056 fix VDECODE_FLAG_ALLOWNOTINGAME flag (#2000)
Corrects the check for the VDECODE_FLAG_ALLOWNOTINGAME flag
2024-06-01 13:57:07 +00:00
BenoistandKenzzer 4e73713fab Fix rare crash with logs (#2161)
* Fix rare crash with logs

* Nullcheck instead

* Update smn_filesystem.cpp

---------

Co-authored-by: Kenzzer <[email protected]>
2024-05-24 13:10:24 +02:00
e07c120cab CDetour safetyhook (#2162)
* Add safetyhook, remove libudis86

Co-authored-by: bottiger1 <[email protected]>

* Add modified CDetour

Co-authored-by: bottiger1 <[email protected]>

* Add CDetour [Safetyhook] to build script

* Re-enable loader/core/corelogic, and fix new C++20 error

* Reenable all extensions (except dhooks)

* Make cstrike compile against new CDetour

* Remove unused variable in sdktools output?

* Make sdktools compile against new cdetour

* Downgrade to C++17

* remove auto

* fix compilation on linux

* Re-enable dhooks

* Re-authorise old compilers

* Fix invalid downgrade of std::optional

* readd libudis86 for dhooks only

---------

Co-authored-by: Kenzzer <[email protected]>
Co-authored-by: bottiger1 <[email protected]>
2024-05-21 01:53:44 +00:00
Kaela e3734803f0 sdkhooks: retain vtable hook until level end (#2094)
* Band-aid for Bulk SDKHooks performance impact on linux

Platform specific changes.

* Oops forgot about header

* Simplified/improved LevelShutdown code
2024-05-18 12:30:20 +01:00
Nick Hastings 7c757ac119 Trigger build for hl2sdk-l4d2 changes 2024-05-15 09:36:23 -04:00
sappho c5425def7f Trigger build for L4D2 changes (#2155) 2024-05-14 17:09:03 -07:00
ojlandersandOdin Landers e60c672485 Add OnServerHibernationUpdate forward (closes #1483) (#2151)
* Add OnServerHibernationUpdate forward (closes #1483)

* Clarify hibernation state

* make it 2 forwards instead of 1

---------

Co-authored-by: Odin Landers <[email protected]>
2024-05-07 01:44:56 +00:00
rtldg 908ffdb523 make RenameFile() on Windows also replace the file (#2060)
* make RenameFile() on Windows also replace the file

* Add MOVEFILE_COPY_ALLOWED to MoveFileExA
2024-05-05 22:20:46 +00:00
Rushaway d56dc62e03 i18n: Czech Translations (#2120) 2024-05-05 21:19:11 +00:00
Kit o' Rifty f08f1ef0d6 Fix passing variant_t parameters + fix codegen stack on Win64 (#2117)
* Fix 64-bit JIT not allocating stack space for params on stack
Fix wrong cond check for passing objects by value

* Fix wrong FireOutput detour proto on win64
2024-05-05 21:17:59 +00:00
bottiger1 5cb2d68fd7 AcceptEntityInput 64bit fix (#2149)
* Fix AcceptEntityInput on 64 bit by using struct from SDK instead of pointer math.

* Fix from Malifox. Not sure what it does but it is supposedly related to the AcceptEntityInput crash.

* Fix episode1 and darkm sdk paths
2024-05-05 20:06:06 +00:00
caxanga334 96d0959db1 Update HL2SDK Manifests Submodule (#2150) 2024-05-05 17:14:15 +00:00
5a6b2c8ebf 64bit gamedata fixes (#2141)
* save as of now

* save as of now

* progress

* hint towards comments

Please for the love of god, put comments for updating these in the future will be even more annoying.
i dont even know what LevelShutdown it wants.

* forgot

* fix

* fixes

* Update engine.ep2v.txt

* Update engine.ep2v.txt

* Update sm-tf2.games.txt

---------

Co-authored-by: Benoist <[email protected]>
Co-authored-by: Nicholas Hastings <[email protected]>
2024-05-05 16:13:39 +00:00
Adrian-Stefan Mares 343f64f6b7 Fix IsClientSourceTV in L4D2 with a custom tv_name (#2143) 2024-04-29 00:17:10 +01:00
Oliver John HitchcockandKyle Sanderson f9ad35badf Stop EntRefToEntIndex returning garbage if a bad parameter is passed (#1323)
* Stop EntRefToEntIndex returning garbage if a bad parameter is passed

Seen multiple bad usage of this function that works only because whatever was passed in was returned as it wasnt an entity reference.
This code should have worked and would be expected to have returned something invalid but instead the the input was returned which allowed the code to work when really it is bad code.
See for one such case https://discordapp.com/channels/335290997317697536/335290997317697536/736518488314871868

* Update documentation of EntRefToEntIndex

Added the error text saying what shall be returned when a invalid parameter is passed.

* Validate entity index instead of just returning INVALID_EHANDLE_INDEX

Not sure if it needs this much validation but this just mirrors how IsValidEntity works, so the entity index returned should be valid else INVALID_EHANDLE_INDEX is returned.

* EntRefToEntIndex improve doc comments to better represent functionality

---------

Co-authored-by: Kyle Sanderson <[email protected]>
2024-04-25 23:19:04 +00:00
Nick Hastings 60b6a8dfb0 Revert "Trigger build for hl2sdk-tf2 changes"
This reverts commit ee51162c3f.
2024-04-22 21:31:14 -04:00
Nick Hastings 00f3970036 Revert "Trigger build for hl2sdk-tf2 changes"
This reverts commit 123ad7aab1.
2024-04-22 18:24:19 -04:00
Alienmario 7d78c141e7 Fix SDKHooks IEntityListener (#2138) 2024-04-21 19:21:47 +00:00
Nick Hastings 123ad7aab1 Trigger build for hl2sdk-tf2 changes
(https://github.com/alliedmodders/hl2sdk/issues/231)
2024-04-21 12:04:44 -04:00
Nick Hastings ee51162c3f Trigger build for hl2sdk-tf2 changes
https://github.com/alliedmodders/hl2sdk/issues/231
2024-04-20 14:04:26 -04:00
Adrian-Stefan Mares af93d819c6 Handle INVALID_FUNCTION mismatches at plugin boundaries, redux (#2136) 2024-04-19 21:56:48 -04:00
CookieCat d426d1f04f x32 Windows Gamedata Fixes for 4/18/2024 TF2 Update (#2137)
* sm-tf2-games

* FireOutput
2024-04-19 18:00:30 -07:00
6cac489fce Prevent recursion in sm_ServerCommandEx (fixes #967) (#2133)
* Prevent recursion in sm_ServerCommandEx (fixes #967)

* Update core/smn_console.cpp to fix style

Co-authored-by: Erin <[email protected]>

---------

Co-authored-by: Odin Landers <[email protected]>
Co-authored-by: Erin <[email protected]>
2024-04-18 11:42:37 +00:00
Peak 5c507cc35c Implement File.Size (#2131)
* Implement file size method for already open files

* Switch from fseek/ftell to fileno/fstat size reading
2024-04-13 18:14:52 +00:00
Rain dbec0b165c Neotokyo: Add "SetOwnerEntity" gamedata (#2126)
This adds game support for `SetOwnerEntity`, `SetEntityCollisionGroup`.
2024-03-21 00:11:59 +00:00
Rushaway 4e8b66bf99 fix: sorted alphabetically, remove duplicate 'ko' (#2121)
* fix: sorted alphabetically, remove duplicate 'ko'

* 'KoreanA' is a valid value
2024-03-05 01:20:40 +00:00
CookieCat 8dcbe14ea0 Throw an error when attempting to remove worldspawn in RemoveEntity/RemoveEdict (#2104)
* Check for worldspawn in RemoveEntity and RemoveEdict

* A little more info
2024-02-20 16:14:00 +01:00
Peak 06dcb991e8 Allow topmenu config file to sort with subcategories (#1757) 2024-02-18 11:46:48 +01:00
Mart e262064fd8 Update game.nucleardawn.txt (#2116)
add missing GetAttachment offset for ND
2024-02-14 23:22:26 +00:00
dependabot[bot] a80b9c5c0f Bump actions/cache from 3 to 4 (#2103)
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-12 14:01:26 +01:00
BenoistandKenzzer 638aae0040 Fix sdktools gamedata (#2113)
Co-authored-by: Kenzzer <[email protected]>
2024-02-08 00:02:01 +00:00
BenoistandKenzzer 35ac74c7a7 Update gamedata for l4d2 (#2111)
* update gamedata for l4d2

* undo findentitybyclassname sig change

* update gEntList offset accordingly

---------

Co-authored-by: Kenzzer <[email protected]>
2024-02-02 21:10:42 +00:00
Ryan Blackham 7bb9da2a26 Fixed typo in reservedslots.sp (#2109) 2024-02-01 10:36:28 +01:00
BenoistandKenzzer b5b9b8388c Fixup entinfo offset + sdktools tf2 x64 gamedata (#2108)
* fixup entinfo offset

* added missing tf gamedata

---------

Co-authored-by: Kenzzer <[email protected]>
2024-01-29 01:08:33 +00:00
BenoistandKenzzer e7e92d4e40 update manifests (#2106)
Co-authored-by: Kenzzer <[email protected]>
2024-01-26 21:18:14 +00:00
BenoistandKenzzer 33e869a4e5 Update gamedata for TF2 x64 (#2105)
Co-authored-by: Kenzzer <[email protected]>
2024-01-26 13:30:08 +00:00
NotnHeavy 0bc9aa46e6 Update checkout-deps files to install hl2sdk-mock (#2102) 2024-01-22 15:30:15 +00:00
Angel Bot 80ad76a563 Fix teleportation offsets for tf2classic (#2100) 2024-01-01 23:55:23 +00:00
NotnHeavy 7e29f22f8f Fix typo in ArrayList.Clone docs (#2098)
very useful update of: grammar in comment
2023-12-22 20:35:26 +01:00
daniandNicholas Hastings a9eb3a0d45 Add gamedata for Pre-Fortress 2 (#2091)
* Added gamedated for pf2

* added support for beta testing

---------

Co-authored-by: Nicholas Hastings <[email protected]>
2023-12-18 23:59:41 +00:00
Ivan Zaitsev ab6b45b81c Add void function prototypes to NativeCall and MenuHandler (#2081)
* Add void prototype to NativeCall typeset

`void` prototype can be used for simple natives which don't return any value.
This is done to silence compiler warnings 209 (`function has explicit 'int' tag but does not return a value`) and 242 (`function "NativeCallback" should return an explicit value`).

* Make MenuHandler into typeset and add void prototype

This can be used for basic menu handlers that don't return modified item styles and don't redraw menu items.
2023-12-18 23:57:58 +00:00
bt 385eae892c Add gmod9 gamedata. (#2093) 2023-12-18 23:52:54 +00:00
dependabot[bot] 5f309f45f8 Bump actions/setup-python from 4 to 5 (#2095)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-18 23:18:36 +00:00
dependabot[bot] a2e5e2a442 Bump actions/upload-artifact from 3 to 4 (#2097)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-18 23:17:52 +00:00
Nicholas Hastings b42e5ac922 Convert AMBuild scripts to use hl2sdk-manifests (#2096)
* Add hl2sdk-manifests submodule

* Update AMBuild scripts to utilize hl2sdk-manifests

* Add build*/ to .gitignore
2023-12-18 23:15:44 +00:00
Nick Hastings 544204654d Hack fix for broken --gen=vs 2023-12-16 12:19:10 -05:00
sapphoandazzy 5c971fd51b add gamedata for tf2classic (#2088)
* add gamedata skeleton for tf2classic

* Update game.tf2classic.txt

* Update game.tf2classic.txt

---------

Co-authored-by: azzy <[email protected]>
2023-12-05 00:50:08 +00:00
B3none 6507d947cc Updated sourcepawn.php to latest array syntax 2023-11-30 21:58:49 -08:00
B3none 30415e299e Updated ProfFileParser.class.php to PSR-12 2023-11-30 21:58:49 -08:00
Mart 8eeea2aba1 Update funcommands.games.txt (#2085)
Changes for Nuclear Dawn

*Correct beacon team colors (Consortium = blue / Empire = red)
*Change beacon .vmt sprite to an existing one similar to the usual "laser.vmt" (white and 32x64 size)
2023-11-28 21:59:54 +00:00
Nick Hastings bb1431cd3b Fix Windows FireOutput signature for Nuclear Dawn (fixes #2084) 2023-11-27 09:53:25 -05:00
rop_rop a2aec9b42e Update Hebrew translation phrases (#2050)
* Update basebans.phrases.txt

added all the missing Phrase

* Update basebans.phrases.txt

update of the missing phrase as a parameter
2023-11-24 16:56:14 +01:00
Nick Hastings ef74b51c8b Probably fix build 2023-11-20 19:54:41 -05:00
Nick Hastings e74aa099bc Add debugging to bootstrap script 2023-11-20 19:40:09 -05:00
Nick Hastings 8140cb2d6b Tweak build script 🐍 2023-11-20 19:37:22 -05:00
Nick Hastings d981e252d2 Fix regression that breaks loading on mcv, blade, and csgo (fixes #2082) 2023-11-20 09:23:02 -05:00
Nick Hastings e6a04abc9e Remove unused var 2023-11-20 09:21:00 -05:00
Nick Hastings c90477a720 Fix warning in build script 2023-11-20 09:20:38 -05:00
11c8084ccd Deprecate CreateInterface (#2001)
* Deprecate CreateInterface

Co-authored-by: KitRifty <[email protected]>

* Expose the 'newer' data

* Update smsdk_ext.cpp

---------

Co-authored-by: Kenzzer <[email protected]>
Co-authored-by: KitRifty <[email protected]>
2023-11-11 16:59:22 +00:00
Nick Hastings 7747beb4cf Add remaining SDKHooks gamedata for Dystopia 2023-11-07 19:35:34 -05:00
Rain 9fa7421122 Update gamedata for Dystopia (#2080)
Add the offsets for OnTakeDamage and OnTakeDamage_Alive for the game Dystopia, for Linux and Windows platforms. This change adds game support for the SDKHook_OnTakeDamage, and its variants.
2023-11-07 13:20:45 +00:00
bauxite f2ca671d1f Update basetriggers.sp for Dystopia compatibility (#2075)
* Update basetriggers.sp for Dystopia compatibility

Dystopia has a built-in command called nextmap which breaks due to the Sourcemod nextmap command. This modification is intended to restore Dystopia compatibility.

* Update basetriggers.sp

* Update basetriggers.sp

* Update basetriggers.sp

* Update basetriggers.sp
2023-11-06 16:10:46 +00:00
sappho d4da21b07f Add more context to Format etc documentation (#2079) 2023-11-06 16:07:00 +00:00
David Anderson 4b2d8b53fa Fix macOS scripting SDK build.
This also enables universal spcomp binaries with arm64 support.
2023-11-04 23:01:44 -07:00
David Anderson 7bfd5e521e Update SourcePawn.
This updates float.inc and smn_float.cpp to compensate for alias
removal.
2023-11-03 17:46:48 -10:00
David Anderson 060c832f89 Update SourcePawn.
This brings in a few breaking changes.

One, INVALID_FUNCTION is now 0 instead of -1. This is long overdue.
Plugins should transparently work except in two cases:

  1. Third-party extensions that have a hardcoded test for -1 will no
     longer work. A new API has been provided for this,
     GetFunctionByIdOrNull.
  2. If a plugin "framework" uses INVALID_FUNCTION anywhere in its
     exported API, then all plugins using that framework need to be
     recompiled together, so they agree on the value of
     INVALID_FUNCTION.

Hopefully the damage here is minimal. The core plugin version has been
bumped to 7 to try and limit conflicts.

Second, braceless functions are no longer supported. There wasn't really
any way around this and it's better to bite the bullet now. This affects
source compatibility, but not binary compatibility.

Third, the "using" keyword is no longer implemented. SourceMod now has a
Handle methodmap again. Plugins compiled against this new methodmap will
require a "Handle.~Handle" native, which 1.12 now provides.
2023-11-02 18:38:30 -10:00
PlayBoy31 8c9fd3746b Fix missing submodules (#2074)
* add --recursive for missing submodules
2023-11-02 21:02:15 -07:00
Nick Hastings 314184beea Merge branch 'master' of https://github.com/alliedmodders/sourcemod 2023-10-21 19:03:09 -04:00
Nicholas Hastings 17462cbe5a Fix build using wrong dir in bootstrapping 2023-10-21 19:02:51 -04:00
David Anderson ae4e043c3e Enable C++17. 2023-10-21 19:02:51 -04:00
David Anderson 6def79ff23 Merge pull request #2063 from alliedmodders/cxx17
Enable C++17.
2023-10-19 20:33:14 -07:00
Jonathan 1ba7024a3a Fix Japanese translations (#2053) 2023-10-17 12:50:55 +02:00
rop_rop 44aaaf8b10 Update Hebrew playercommands.phrases.txt (#2051)
added the missing Phrase
2023-10-17 12:35:36 +02:00
XeroX 62754333cd Increase lastMap buffer (#2062)
Fixes #2061
2023-10-17 12:31:04 +02:00
Rain 8938a29904 Ignore chat triggers for interactive ban reason (#2067)
* Ignore chat triggers for interactive ban reason

If the admin types a chat trigger for a command while BaseBans is
waiting for them to type a ban reason, don't treat that message as the
ban reason.

This fixes a problem where the admin decides to cancel their ban with
"!abortban", "/abortban" etc, but ends up accidentally banning the
player with the ban reason "!abortban" (or by attempting to access any
other command via a chat trigger before typing the ban reason).

* Optimize

Check if we're actually waiting for chat reason before calling the native
2023-10-16 19:43:00 +02:00
Nick Hastings 2c6ef5825f Update from Clang 13 to Clang 14 for Linux build 2023-10-16 13:21:02 -04:00
sappho b090aa36bf Add support for open fortress (#2057)
* Run timers every tick instead of arbitrarily on 100ms thinks, adding a significantly higher amount of precision

* undo force push

* add open fortress support

* undo leftover timersys changes

* Add fireoutput sig and remove engine gamedata

* Update master.games.txt

* Update master.games.txt
2023-10-16 00:29:44 +00:00
David Anderson cb1dae5aab Fix minimal rebuilds on buildbot. 2023-10-13 21:28:33 -07:00
David Anderson c9e824632f Enable C++17. 2023-10-13 21:25:24 -07:00
David Anderson 0436fb0ab3 Fix linkage. 2023-10-13 20:59:55 -07:00
David Anderson 767c5cf468 Fix build. 2023-10-13 15:32:45 -07:00
David Anderson f01ad5317a Fix linker issues on Linux. 2023-10-13 15:26:05 -07:00
David Anderson fac3138ff5 Fix typo. 2023-10-13 14:14:47 -07:00
David Anderson ab9e86910c Switch bootstrap.pl to Python. 2023-10-13 14:04:56 -07:00
peace-maker e88e9342ef Update SourcePawn (#2052)
* Update SourcePawn

* Fix using SourceMod version as SourcePawn version
2023-10-06 22:47:11 +02:00
dysphie e3a01b0e1a Update game.nmrih.txt (#2056) 2023-10-02 23:24:09 +00:00
Kit o' Rifty 07d928dbad Fix sound flags enumeration (#2040)
* Fix sound flags

* Change to bit shifts like in SDK
2023-09-27 17:03:03 +02:00
BoinkandFyren a402b3cceb Prevent commands from being run on the client with sm_play (#1832)
* Prevent command injection

* Empty to commit to try to kick CI.

* Improve filename sanitisation

---------

Co-authored-by: Fyren <[email protected]>
2023-09-27 16:51:07 +02:00
幸運心andpeace-maker 99dbe06d8a Japanese translations (#2042)
* Japanese translations

Japanese translation corrections.

* Fix phrase format parameter index off-by-one

---------

Co-authored-by: peace-maker <[email protected]>
2023-09-27 16:36:11 +02:00
Mikusch 29694ec13b Add block parameter to various ArrayList functions (#1656)
* Add block parameter to FindString

* Add block parameter for GetString & GetArray

* Fix buffer overflow issues

* Fix wrong return

* Add size parameter to SetArrayString
2023-09-27 16:05:43 +02:00
Mikusch 1e8db957bf Add more functions to ArrayStack (#2019)
* Add more functions to ArrayStack

* Make formatting consistent with other functions

* Don't remove the element for TopArray

* Replace 4 with sizeof(cell_t)
2023-09-27 15:43:04 +02:00
Rain 0656696251 Neotokyo: Add gamedata for LookupEntityAttachment & GetEntityAttachment (#2049)
Add the "LookupAttachment" and "GetAttachment" signature and offsets for
Neotokyo, which adds game support for the SM LookupEntityAttachment and
GetEntityAttachment natives.
2023-09-25 22:19:47 +00:00
dependabot[bot] af04c964fe Bump tibdex/github-app-token from 1.8.0 to 2.1.0 (#2048)
Bumps [tibdex/github-app-token](https://github.com/tibdex/github-app-token) from 1.8.0 to 2.1.0.
- [Release notes](https://github.com/tibdex/github-app-token/releases)
- [Commits](https://github.com/tibdex/github-app-token/compare/b62528385c34dbc9f38e5f4225ac829252d1ea92...3beb63f4bd073e61482598c45c71c1019b59b73a)

---
updated-dependencies:
- dependency-name: tibdex/github-app-token
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-25 17:35:50 +02:00
Nick Hastings bc81361319 MCV: fix Linux tier0/vstdlib bin names 2023-09-24 13:31:55 -04:00
Nicholas Hastings 853bcf703a Update MCV platform support. (#2046) 2023-09-24 16:23:10 +00:00
dependabot[bot] c81248004a Bump actions/checkout from 3 to 4 (#2045)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-13 18:29:18 +02:00
throwaway47777 79787cb868 Fix admin-flatfile.sp includes (#2043)
* Move admin-flatfile to plugins dir

* Fix admin-flatfile sp includes
2023-09-13 18:28:35 +02:00
peace-maker 20aae06f12 NPOTB: Update Github Actions using dependabot (#2035) 2023-07-31 23:38:49 -07:00
hydrogen-mvm a20eb08dc6 Fix replay workaround not triggering (#2033) 2023-07-29 20:53:17 +00:00
Nicholas Hastings 8d60a46358 Revert "Update sourcepawn (#2011)" (#2032)
This reverts commit cb8541548b.
2023-07-29 16:01:25 +00:00
Nick Hastings 4c376cbcb7 Update PLAPI version for NormalSHook signature change (MAXPLAYERS increase) 2023-07-27 08:15:02 -04:00
sappho d83c498a8f [1.12] update maxplayers define for 07-25-23 tf2 update (#2026) 2023-07-26 20:13:31 +00:00
Mikusch 531b053096 TF2: Add TFCond_ImmuneToPushback condition (#2023) 2023-07-26 02:10:08 +00:00
Mikusch 0dafe04899 TF2: Update StunPlayer signature (#2024) (fixes #2022) 2023-07-26 02:08:48 +00:00
rtldg 7170a8f11c Fix typo in DHookRaw docs (#2020) 2023-07-21 09:58:14 +02:00
peace-maker 2ef874dbc9 Run basic native tests using hl2sdk-mock in CI (#2015)
This tests the sorting.inc API similar to the existing test plugin in
the plugins/testsuite folder. Tests fail if the srcds output contains "FAIL".
2023-07-12 22:58:28 +02:00
peace-maker cb8541548b Update sourcepawn (#2011)
* Update sourcepawn

* Remove #pragma rational Float
2023-07-12 22:55:40 +02:00
peace-maker 46e3de8d24 Fix minor translation typos (#2017)
No need to know the languages for those.
2023-07-12 13:38:12 +02:00
Corey D 5addaffa56 Add ParseTime (strptime) native (#1697)
* Add GetTimeStamp (strptime) native

* Fix description

* Fix typos

* Fix issues

* Rewrite ParseTime

* Fix docstrings

* Fix ParseTime

* Clarify docs
2023-07-04 13:42:45 +02:00
Erin f40ae82df4 Clear sm_nextmap so we don't get stuck in a loop (#1545)
* Pure C++ solution

* Pure SourcePawn solution
2023-07-03 20:48:01 +02:00
Dominik Adrian Grzywak 6ebf04b75d Add missing Polish translations (#2004) 2023-06-15 10:17:39 +02:00
Lukáš Čeremeta e93dd7af3f Update Slovak basetriggers.phrases.txt (#2002)
* Update Slovak basetriggers.phrases.txt

Added missing phrase

* Update basetriggers.phrases.txt

* Update basetriggers.phrases.txt

Remove #format
2023-06-13 10:11:23 +02:00
Lukáš Čeremeta 4dc2383fe3 Update Slovak nominations.phrases.txt (#2003)
* Update Slovak nominations.phrases.txt

Added missing phrase

* Update nominations.phrases.txt

* Update nominations.phrases.txt

Remove #format
2023-06-13 10:10:50 +02:00
bottiger1 5f827089d3 Fix mismatched memory release in regex clearmatch (#2005)
subject is created with strdup which should be freed with C free and not C++ delete
2023-06-12 22:34:57 +02:00
Kroytz 8a7f8c5cbd Fix translation for SChinese (#1996)
* Fix Trans: funcommands

* Fix trans: mapchooser

* Add missing phrase for basecomm

* Update common.phrases.txt

* Update nominations.phrases.txt

* Update basetriggers.phrases.txt

* Incorrect param pos
2023-05-25 15:28:42 +02:00
walliski dae8aba554 Add missing Finnish translations (#1992)
Credits to "rapu chan" and "mäyrä77" for helping with translations.
2023-05-25 15:25:46 +02:00
walliski b9029dedff Update Swedish translations (#1990)
* Add missing Swedish translations

* Remove extra whitespaces

Matches the whitespace around strings with what is found in the English
translations.

* Fix format of error message

Matches the English translations, which also matches what the code is
looking for.

* Change 'bana' to 'karta'

To use the same word for the English word "map" in all translations.
2023-05-25 15:24:17 +02:00
Rushaway 1a375bcc17 fix: Latvian translations (#1989)
* fix: Latvian translations

https://github.com/orgs/alliedmodders/projects/1/views/1?pane=issue&itemId=24307197

Try to solve issue: Includes a "#format" key
And Phrase missing in common.phrases.txt

* Fix + Add missing Arabic translations

https://github.com/orgs/alliedmodders/projects/1/views/1?pane=issue&itemId=24307177
Thanks to arabic teachers `Skynet #2058` & `x sooonta#8948`

* Revert "Fix + Add missing Arabic translations"

This reverts commit 899c0fb783be99020ac2bef3b824766aee485581.
2023-05-25 15:22:42 +02:00
Suza eaccec3e4a Add missing Italian translations (#1988)
* Update plugin.basecommands.txt

* Update common.phrases.txt

* Update nominations.phrases.txt

* Update basetriggers.phrases.txt

* Update plugin.basecommands.txt

* Update common.phrases.txt

* Update nominations.phrases.txt

* Update plugin.basecommands.txt
2023-05-25 15:21:21 +02:00
Rushaway 5fff988a8f Add missing Portuguese translations (#1987)
https://github.com/orgs/alliedmodders/projects/1/views/1?pane=issue&itemId=24307202
Thanks to 'Ş Ŧ Ř Ɨ Ҝ € Ř'#1692 for translations
2023-05-25 15:20:23 +02:00
Rushawayandwalliski 1a1bb54c4f Add missing Danish translations (#1986)
* Add missing Danish translations

https://github.com/orgs/alliedmodders/projects/1/views/1?pane=issue&itemId=24307184

* fix: better vocabulary

Co-Authored-By: walliski <[email protected]>

---------

Co-authored-by: walliski <[email protected]>
2023-05-25 15:18:22 +02:00
Dysphie 97f2fc9d7f Increase Cookie.GetInt/SetInt buffer size (#1995)
Current implementation does not account for negative sign or null term
2023-04-22 01:19:36 -07:00
Vauff 2e1235a585 A2S_Rules fix: Move MTU patch value to gamedata (#1829)
* A2S_Rules fix: Move MTU patch value to gamedata and increase it

* Revert MTU value back to 5k
2023-04-19 15:28:40 +00:00
Corey D 426c1a090f Fix CommandListener ignoring Plugin_Handled (#1819) 2023-04-19 16:44:34 +02:00
Corey D 50b4ad4e11 Make KeyValues.Rewind traversal-stack clearing optional (#1993) 2023-04-17 13:10:02 +01:00
Rushaway a330d0a1bf Add missing french translations (#1985) 2023-04-15 18:18:44 +01:00
peace-maker 4e6774befb Add sanity check for syntax errors in translations (#1978)
The pull request should be blocked on basic typos breaking the SMC file.
2023-04-09 19:25:50 +02:00
crashzk b1b993989a Update Brazilian Phrases (#1974)
* update: Translations rockthevote.phrases.txt

* update: Translations nominations.phrases.txt

* update: Translations basetriggers.phrases.txt

* update: Small changes in translations

* fix: Small corrections in the translation

* update: lower case

* fix: Minors

* fix: Translations Slot Reserved & Fun Votes

* Update funvotes.phrases.txt
2023-04-09 15:13:59 +00:00
Mikhail Buchka 2e59202ea4 Added missing phrases and parameter (#1977) 2023-04-09 15:13:46 +00:00
aept 4a6d29c9e2 Add missing latam phrases (#1968)
* Add missing latam phrases

* Fix latam phrases

Fixed some latam phrases to fit Latam dialect, previously were Spanish from Spain.
2023-04-09 15:09:43 +00:00
rcon_password e746fdf1fb missing translation added (#1982) 2023-04-09 14:55:25 +00:00
rcon_password cac7793f15 translations updated (#1981)
I removed the word Aptauja since in this context it isn't the right word to use https://tezaurs.lv/aptauja:1 and changed it to this word https://tezaurs.lv/balso%C5%A1ana:1 

Example: I was asked  by a stranger on the street to participate in the "Aptaujā" 
Example 2: I went to the biggest shopping mall in Latvia to participate in the "Balsošānā", the year's best actor.
2023-04-09 14:55:16 +00:00
rcon_password e0c95674c8 missing translation added + fix (#1979)
Added missing translation + Can't Nominate Current Map translation was changed because The sentence in Latvian doesn't sound good + the chosen word wasn't the best option in this sentence.
2023-04-09 14:55:06 +00:00
rcon_password bc42cef765 missing translation (#1980) 2023-04-09 14:54:54 +00:00
Nicholas Hastings 680a198fa2 Fix quotes in UA translation. 2023-04-07 21:30:20 +00:00
peace-maker 38f7be7664 Update Ukrainian phrases (#1970)
Thank you to VAC#1643 on Discord!
2023-04-07 23:18:16 +02:00
peace-maker 94f5b5d06c Add missing german phrases (#1966) 2023-04-07 06:59:48 +02:00
XeroX f66a904c31 Update SDKCall documentation for string return type (#1961)
* Update SDKCall return information

This adds the information that if the return value is a string then SDKCall will return the number of bytes written.

* Update description

* Add info if the string is null
2023-04-02 23:46:53 +02:00
Forgetest 8e0039aaec [DHooks] Fix NaN return when superceding pre-detour (#1967)
* Update hook.cpp

* Update hook.cpp
2023-03-31 18:19:04 +02:00
Kyle Sanderson dd1e5997f3 spanish fixups (#1965)
* Update basetriggers.phrases.txt

* Update rockthevote.phrases.txt

* Update nominations.phrases.txt
2023-03-30 14:05:55 +02:00
Corey D bc6e920213 Improve HasEntProp performance (#1908) 2023-03-29 21:40:30 -07:00
MichaelandPeace-Maker a28c3cac9b cstrike.csgo: Add native to retrieve loadout slot of weapon (#1241)
* Add native to retrieve loadout slot of weapon

* Mention the native is for CS:GO only

---------

Co-authored-by: Peace-Maker <[email protected]>
2023-03-29 21:27:45 -07:00
fakuivanandpeace-maker 6670b93cc6 keyvalues: adjust KvSavePosition return value to implementation (#757)
The current ``KvSavePosition`` definition does not reflect the behaviour seen in [core/smn_keyvalues.cpp#L973-L981](https://github.com/alliedmodders/sourcemod/blob/404e96ad456531e9029f3b02b243a5284efd9691/core/smn_keyvalues.cpp#L973-L981). This can cause problems if some procedure on sp expects ``KvSavePosition`` to always add one node to the stack, no matter if there is no higher node.

Co-authored-by: peace-maker <[email protected]>
2023-03-29 21:06:36 -07:00
aept 8826663186 translations: add missing phrases to Spanish language (#1964)
* Added corresponding format parameters

* Added missing phrase

* Added missing phrase to basetriggers
2023-03-29 20:43:03 -07:00
Corey D c5087d7a39 database: flip to recursive_mutex to allow nested locks (#1937)
* Fix crash from db locking

* Change db lock to use recursive_mutex
2023-03-29 20:03:03 -07:00
FlaminSarge 5ba9816377 nominations: implement map not in pool phrase (#597)
New English text is “Map ‘%s’ is not in the nominations pool.”
2023-03-29 18:39:54 -07:00
peace-maker 4eecc80b9a Fix translations workflow (#1963)
* Fix translations workflow

* Temporarily trigger workflow for PRs

* Trigger without a PR

* Just work please

* Update github-app-token dependency

* Update workflow step name

* Disable on PRs again
2023-03-30 02:28:03 +02:00
peace-maker 008fbf78a5 Cleanup the translation files (#1962)
* Remove obsolete slapslay.phrases.txt

That plugin isn't in the stock arsenal since forever.

* Remove "Dead Player Rename" phrase

Unused since #313

* Remove nominations phrases from rockthevote

Those phrases were moved to their own nominations.phrases.txt

* Remove "Next Map" phrase from nextmap.phrases.txt

It was moved to basetriggers.phrases.txt

* Remove unused phrases from common.phrases.txt

Only "Slapped Player" was moved to funvotes.phrases.txt

* Delete empty phrase files

* Fix workflow python version selection

3.10 would select Python 3.1 and fail

* Deduplicate "Please select a map" phrase

Only keep it in the plugin.basecommands.txt file and remove it from the basevotes.phrases.txt.

Both plugins using the phrase load the basecommands phrases.

* Allow manual triggering of translations action

* Actually use the nextmap phrases

They were never referenced in the plugin. The "ago" phrase doesn't work the way it is and needs more rethinking.
2023-03-30 01:13:40 +02:00
Kyle SandersonandPeace-Maker 48150e0c7a Bring languages into the tree (#1625)
* translations: bring languages into tree

* Update translation phrases changed since 2021

* Update packaging script to include all translations

* Update languages.cfg

* Add Latin American Spanish translations

This is a copy of spanish for now.

* Ignore "en" when looking for translation folders

English is the default and doesn't use a subfolder.

* Only add each translation folder once

Korean "ko" is in there twice.

* Compare language coverage to english

All phrases are compared to the english baseline files and any differences
are reported. The differences are pushed to a Github Project as well for
an easier overview.

Thank you to @nosoop for sharing the Python SMC parser!

* Add link to README

---------

Co-authored-by: Peace-Maker <[email protected]>
2023-03-29 16:23:05 +02:00
peace-maker d8fd60b562 Update clang-8 CI run to Ubuntu 20.04 (#1960)
The Ubuntu 18.04 runner image is deprecated and will be unsupported on 2023/04/01. It appears Ubuntu 20.04 has a package for clang-8, so just do the switch.
2023-03-28 13:50:19 +02:00
sappho 178658912e fix mismatched delete [] in regex extension (#1941)
* fix mismatched delete []

* strdup needs to be free'd, not deleted
2023-03-27 15:50:31 +02:00
Mikusch 5539484f92 Add support for float modulo operator (#1953) 2023-03-19 16:19:42 +00:00
data-bomb a9a1939f75 Add LookupAttachment signature for ND (#1942)
Adds the LookupAttachment signature for Nuclear Dawn
2023-03-04 05:05:55 +00:00
Alienmario 850f96b986 Allow void return type in timer callbacks (#1916) 2023-03-02 21:28:42 -08:00
Dysphie 693e584dcd Fix LookupAttachment signature for NMRiH (#1940) 2023-03-01 16:31:56 +00:00
Nick Hastings 397b70add0 Enable ShowMenu support for Reactive Drop (see #1938)
Note: Currently only works on beta version of game
2023-02-26 12:39:22 -05:00
Corey D a0eb6a9550 Fix LookupAttachment signature (#1933) 2023-02-13 02:02:48 +00:00
Nicholas Hastings 6bd49ff415 Protect against server crash when DHooks cannot load from SDKHooks not being loaded. (#1930) 2023-02-09 00:10:14 +00:00
Corey D 43cdc65708 Add Ghidra MakeSig script (#1926) 2023-02-05 04:46:52 +00:00
Nicholas Hastings cd6886319c Fix crash with IgniteEntity on MCV (#1924)
* Fix crash with IgniteEntity on MCV.

* Formatting.
2023-02-04 16:09:46 +00:00
Poggu 6e839a95c6 Fix EntityFactoryCaller signature (#1925) 2023-02-04 16:06:38 +00:00
El Diablo 2dcee81f22 Linux [SDKTOOLS] Sigscan for FireOutput FIX (#1923)
Addie said:
test the signatures:
\x55\x89\xE5\x57\x56\x53\x81\xEC\x8C\x01\x00\x00\x8B\x55\x08
or
digby's \x55\x89\xE5\x57\x56\x53\x81\xEC\x8C\x01\x00\x00\x8B\x55\x2A\x65\xA1

\x55\x89\xE5\x57\x56\x53\x81\xEC\x8C\x01\x00\x00\x8B\x55\x08 fixed the issue for linux server.
2023-02-04 14:46:57 +00:00
GAMMACASE a253d35bcd Gamedata update after 2/2/2023 CSGO update (#1921) 2023-02-03 17:38:37 +00:00
Poggu 02e9d214b4 Update Military Conflict: Vietnam gamedata (#1915)
Revert whitespace removal


Revert ignite offset
2023-01-30 23:04:53 +00:00
Nicholas Hastings 30a2160839 Fix gamedata library search order in some cases. (#1914) 2023-01-29 20:24:34 +00:00
rtldg d57d7e7401 Enable math functions in sqlite (#1886) 2023-01-29 17:30:15 +00:00
Impact 1f5b735dbd Add note about automatic unhook (#1910) 2023-01-22 10:23:40 +01:00
Nick Hastings d5a26adc49 Regression fix for CS:GO GivePlayerItem.
Regressed in https://github.com/alliedmodders/sourcemod/pull/1887
2023-01-20 10:09:22 -05:00
Rushaway 221d34f809 fix: Print full map name in Log instead of args (#1907) 2023-01-15 13:32:41 -05:00
Nicholas Hastings 8922ed0c5d Add TE_WriteEnt and TE_ReadEnt natives to SDKTools. (#1905) 2023-01-14 14:48:05 +00:00
nosoop 27b1817b10 Update TF2 gamedata for version 7757534 (2023-01-05) (#1901) 2023-01-05 23:54:37 +00:00
Nick Hastings 3a488f7041 Fix typo in b77e8c50 causing regression in loading on some games.
Fixes #1898
2023-01-01 20:04:56 -05:00
ambacaandUNLOZE 8f7a1641fc Friendly Fire support L4D(2) games. (#1530)
Support L4D(2) Friendly Fire In Basetriggers.sp #1522

- Games have cvar mp_friendlyfire min. and max. bounds set to 1
- Removing mp_friendlyfire lower bound and set to 0, cvar have no purpose on friendly fire damage.
- FF works from z_difficulty and each difficult level have FF damage ration cvars:
survivor_friendly_fire_factor_easy
survivor_friendly_fire_factor_normal
survivor_friendly_fire_factor_hard
survivor_friendly_fire_factor_expert

Update added PRINT_TO_ things from previous update.

Co-authored-by: Bacardi <>
2022-12-29 14:00:58 +00:00
Nicholas Hastings b0799d3336 Move menu sound selection from core config to gamedata. (#1896) 2022-12-29 04:10:51 +00:00
nosoop 2130c60fd9 Implement raw entity handle accessors (#1830)
* Implement raw entity handle accessors

* Fix FromPseudoAddress calls on 64-bit

* fixup: Remove unnecessary ent deref

* fixup: Correct param index in thrown error
2022-12-29 03:57:47 +00:00
Nicholas Hastings ecb707e38d Add support for other engine binaries in game configs (#1414). (#1626)
* Add support for other engine binaries in game configs (#1414).

* Add engine bin path for CRC bin lookup and filter out addons from GAMEBIN.

* MAX_PATH -> PLATFORM_MAX_PATH.

* Fix library lookup on Linux.

Before this, there was a bad assumption that, like on Windows, POSIX module
handle pointers were within the module's address space (and thus usable
with dladdr). That's not true!

Instead, to get a usable address on all platforms, we'll do a lookup of the
CreateInterface function that exists in all modules. This also has the
(arguable) benefit of further locking this implementation to modules owned
by the game.

To get a valid address inside the module now on both p
2022-12-28 22:58:30 +00:00
Nicholas Hastings 7e94bfb307 Fix asm.c compiler warnings on Windows. (#1897) 2022-12-28 22:50:51 +00:00
Rain 51bba0b894 Fix incorrect behaviour in SDKHooks_DropWeapon's "bypassHooks" parameter (#1877) 2022-12-27 19:31:02 +00:00
Nicholas Hastings 775d4f04f2 Add missing set of CBaseEntity::Teleport param on newer games (#1894)
* Add setting of missing CBaseEntity::Teleport param on newer games

* Rearrange SOURCE_ENGINE defines of games between Portal 2 and CS:GO.
2022-12-27 19:29:22 +00:00
peace-maker 4320d7b17a Get sdktools and sdkhooks/dhooks to load on hl2sdk-mock (#1892)
* Build SDKTools for hl2sdk-mock

* Fix loading of extensions using advanced naming scheme for hl2sdk-mock

* Fix error on missing sv_visiblemaxplayers convar

* Build SDKHooks for hl2sdk-mock

* Fix x86_64 SourcePawn VM filename

* SDKHooks: Ignore missing IEntityListeners list in hl2sdk-mock
2022-12-22 18:39:12 +01:00
TrueProfesional 174bf307a2 Add weapon_bayonet to the list of blocked knives (#1758) 2022-12-20 22:17:22 +00:00
BenoistandKenzzer f8349e846a Fix SetEntityHealth to support 'any' entities (#1846)
Co-authored-by: Kenzzer <[email protected]>
2022-12-20 22:07:57 +00:00
zer0.k ef7d3abefd Add missing null pointer check to protobuf messages (#1883) 2022-12-20 21:50:57 +00:00
Nicholas Hastings b77e8c50ac Add support for Military Conflict: Vietnam (#1887) 2022-12-20 21:46:18 +00:00
clague 0d6179299c Fix ReadMapList ignoring file's last modified time (#1891) 2022-12-20 21:26:57 +00:00
Nicholas Hastings 515df38b72 Throw error in ShowHudText or ShowSyncHudText if HudText params not yet set (#1890) 2022-12-20 01:26:38 +00:00
Nicholas Hastings c5e69900f9 Add "sm_dsay" command to basechat for sending HUD messages (#1889)
* Add "sm_dsay" command to basechat for sending HUD messages

* Add missing SetHudTextParams call
2022-12-20 00:00:43 +00:00
Nicholas Hastings 2d5bc4007f Add clarification to documentation for hud messages and engine dialogs (#1888)
with regard to game support.
2022-12-19 23:49:48 +00:00
zer0.k 3a315e88c2 Update MM:S version in CI, dependency checkout scripts and sample extensions (#1885)
* Update MM:S version in CI, dependency checkout scripts and sample extensions

* Update MM:S version in CI, dependency checkout scripts and sample extensions

* Fix EOL problems
2022-12-19 18:15:45 +01:00
nosoop 6c5a3fdaf2 entitylump: Output separator as spaces instead of tabs (#1873)
On NMRiH and possibly other games that use the Maphacks system,
entries that are modified using that system are rendered with tab
characters stripped out - see CNMRiHMapHackManager::GetEntDataString.

That results in there being no separators at all between keys and
values, as Maphacks receives the serialized string from Entity Lump
Manager.

This commit changes the key / value separator character to use
spaces instead.

This discovery upsets me greatly.

Fixes #1833.
2022-12-05 13:14:54 +01:00
peace-maker 02f188899e Add CommandIterator.ConVarFlags property (#1869)
* Add CommandIterator.ConVarFlags property

Allow to access the convar flags `FCVAR_*` value from the iterator.
The CommandIterator.Flags property should have been called `AdminFlags`,
but it's too late to change that now.

* Switch admin help menu to use CommandIterator.ConVarFlags

No need to lookup the convar again.

* Deprecate CommandIterator.Flags

Rename it to .AdminFlags now that we have two kinds of flags exposed
on the iterator.
2022-12-04 12:24:56 +01:00
peace-maker aab8c6ac9f Fix SDKHook_[Use|Spawn|GetMaxHealth] callback result value handling (#1872)
* Fix SDKHook_Use callback result handling

The returned result of the last callback in the list was used instead
of the highest value. This differs from the behavior of the other hooks.

* Fix SDKHook_Spawn callback result handling

The returned result of the last callback in the list was used instead
of the highest value. This differs from the behavior of the other hooks.

* Fix SDKHook_GetMaxHealth callback result handling

The returned result of the last callback in the list was used instead
of the highest value. This differs from the behavior of the other hooks.
The returned health is only changed if no other plugin wants to block the callback.
2022-12-04 12:12:42 +01:00
Corey D 5d391fda07 Add SMCParser.ParseString (#1817) 2022-12-02 16:55:08 +01:00
vanz666 8538233985 Expose custom sdktools trace types from hl2sdk (#1822)
* Update trnatives.cpp

* Update sdktools_trace.inc

* Update trnatives.cpp
2022-12-02 14:11:05 +01:00
Corey D 3b4a343274 Add natives to get chat triggers (#1816) 2022-12-02 13:55:32 +01:00
Erin f90b7ade76 Trigger build for TF2 SDK update 2022-12-02 08:50:18 +00:00
Nick Hastings 83a29cf82b Trigger build against SDK update 2022-12-01 22:37:50 -05:00
Nick Hastings 89bd4d7329 Update TF2 gamedata. 2022-12-01 19:33:09 -05:00
Batfoxkid ed662dc8cf Block Hidden Commands from Help Command (#1831)
Allows using `FCVAR_HIDDEN` to block commands from appearing in `sm_help` and `sm_searchcmd` which helps with creating alias to commands without filling up the list with those aliases.

For example:
```sourcepawn
RegAdminCmd("sm_setmyperk", MyCommand, ADMFLAG_CHEATS);
RegAdminCmd("sm_setmyperks", MyCommand, ADMFLAG_CHEATS, _, FCVAR_HIDDEN);

RegConsoleCmd("ff2_boss", MyCommand);
RegConsoleCmd("ff2boss", MyCommand, _, FCVAR_HIDDEN);
```
2022-12-01 22:04:59 +01:00
Spirrwell 6574dd8273 Update PVKII FireOutput Linux Signature (#1866) 2022-11-27 03:18:19 +00:00
zer0.k 63f8ea89ca Return the full list of exts/plugins with "sm exts/plugins" client commands (#1862) 2022-11-25 19:00:48 +00:00
nosoop 34c8220e5d Ensure gameconfig file uniqueness when reading master.games (#1859)
The extended gameconfig format reads the master gameconf file twice;
once each for the base engine and actual engine.  The file list
isn't checked for duplicates, so 'common.games.txt' is loaded in
twice, resulting in any 'common' file values potentially overriding
values listed under '#default' in other files due to
bShouldBeReadingDefault.  This happens in the case when matching
game versions by CRC (such as public game branches).

Required for #1857.
2022-11-25 16:47:11 +00:00
peace-maker 3595525f12 Update Github Action workflow versions (#1858)
The currently used versions use deprecated features and Node 12 which is EOL. Switch to newer versions as adviced.

https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/
https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
2022-11-07 15:09:54 +01:00
Maxime Leroy 4989666d72 Add logging to all basevote vote results (#1794) 2022-10-30 23:26:17 +01:00
Erin f7fda0023c Enable CI on release branches (#1854) 2022-10-29 17:36:04 +01:00
Erin 13be211e9a Bump minimum MM:S version for build to 1.12 (#1855)
PVKII changes require at least MM:S 1.12 to build SM.
2022-10-29 15:48:38 +01:00
Spirrwell f6b39720ec Make sure 'pvkii' gets 'GetDataDescMap' offset (#1852) 2022-10-27 21:57:21 +00:00
Maxim Telezhenko 764e38a58f Fix DHooks jit code stack memory alignment (#1849) 2022-10-26 20:41:40 +02:00
Spirrwell e34e9b9869 Split PVKII into its own engine branch (#1847)
* Initial PVKII branch support

* Change PVKII code to 23, DOTA uses 22 in MM

* Bunch more SE_PVKII preprocessor that was missed

* Add some missing SOURCE_ENGINE_PVKII cases

* Update PVKII FireOutput signature for Linux

* Update checkout-deps with 'pvkii'

* Fix FireOutput signature for PVKII, accidentally used one from newer build

* Change PVKII code to 10, and bump others by 1

* Only check against SE_SDK2013 here, like Metamod

* More SE_PVKII preprocessor cleanup
2022-10-24 19:27:32 +00:00
Nick Hastings 721f348684 Trigger build for hl2sdk-csgo update 2022-10-23 18:24:24 -04:00
Vauff 9ddcd335af Correct missed team offsets in CheckRestartRound (#1844) 2022-10-22 09:30:33 -05:00
Nick Hastings eda9a42ee2 Trigger build for hl2sdk-csgo update 2022-10-21 22:28:35 -04:00
Vauff 22a964d89a Update gamedata for 2022/10/21 CS:GO update (#1842) 2022-10-21 20:13:57 -05:00
nosoop 855ece1d3b entitylump: Fix behavior of append (#1836)
This change ensures that the iterator values used by `std::distance`
is correct.  Having the emplace within leads to the possibility of
`m_Entities.begin()` being invalidated due to reallocations.
2022-09-20 16:24:08 +02:00
Vauff 568da23c96 Allow gamedata to use vscript binary (#1826) 2022-09-20 09:46:03 +02:00
Bara 4015f9c1c9 Replace old link with newer working one (#1837) 2022-09-19 22:35:49 +02:00
nosoop 21740d9a26 Add functions for working with entity lumps (#1673) 2022-09-05 15:44:58 -07:00
Impact 05aa3fd39d Update CreateDirectory (#1813)
* Update CreateDirectory docs

Add default arguments and a note about deep paths.

* Update note

* Add note about use_valve_fs
2022-08-27 01:59:43 +02:00
Vladimir 3100e23b87 Add support for gamedata lookups from soundemittersystem library (#1787)
* Add `soundemittersystem` library to game config signatures

* Remove `GAMEBIN` by `soundemittersystem` module load
2022-08-04 16:32:26 +02:00
David Anderson da3e868df5 Merge pull request #1812 from alliedmodders/revert-pbproxy
Revert "Introduce a pbproxy library to solve macOS linker issues."
2022-07-31 11:50:56 -07:00
David Anderson 63e0e2bc82 Fix build. 2022-07-31 11:22:10 -07:00
David Anderson a35ecde538 Revert "Introduce a pbproxy library to solve macOS linker issues."
This reverts commit e5ddbd9886.
2022-07-31 11:17:42 -07:00
David Anderson 81ad870def Revert "Fix use-after-free when creating custom user messages"
This reverts commit 15450a6d0c.
2022-07-31 11:16:50 -07:00
eyal282 24f1c89b96 Add Clientprefs helpers for integers and strings (#1727)
* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc

* Update clientprefs.inc
2022-07-31 11:59:25 +02:00
Kevin Yonan a761194917 Update operator% forwards to newdecls (#1763) 2022-07-28 18:12:00 -07:00
Corey D 9321229321 Add GetClientOriginalLanguage (#1810)
Creates a native which will return the language the client connected with.
2022-07-28 18:10:51 -07:00
Accelerator e5ebd65176 Exposed SDKCall_Engine call type to use CVEngineServer methods (#1648)
* Update vdecoder.h

* Update vcaller.cpp

* Update sdktools.inc
2022-07-26 22:14:49 +02:00
Dysphie 5f7b22d2a4 Allow using sm_nominate without args from console (#1803) 2022-07-26 22:09:48 +02:00
David Anderson 52da989762 Update SourcePawn on master. 2022-07-09 18:32:51 -07:00
42 625c7a98f2 Fix support for SDKCall returning non-networked entity (#1797) 2022-07-08 14:33:43 +00:00
Mikusch 278998f7d0 SDKTools: Add explode parameter to ForcePlayerSuicide native (#1782)
* Expose CommitSuicide params

* A single space

* Validate param count

* Set force param to true by default
2022-07-07 14:14:50 +02:00
peace-maker c29e185d2a Bump version to 1.12 for manual builds (#1795) 2022-07-05 15:13:52 +02:00
David Anderson 5c66a78763 Bump master to 1.12. 2022-07-02 17:02:08 -07:00
peace-maker 5e3a189642 Log a notice if the geoip database gets too old (#1791)
Since we ship an ancient version of the database, help server operators keep track of the database version.
2022-06-30 08:22:51 +02:00
peace-maker 7b89f5fab3 Update SQLite library to 3.38.5 (#1792)
Bring in the changes of the last four years of SQLite development.

Fixes #1728
Fixes #1592
2022-06-30 08:22:28 +02:00
Nick Hastings b0e7407552 Trigger build against hl2sdk-csgo changes. 2022-06-26 11:01:39 -04:00
Nick Hastings 407c24cb14 Trigger build against hl2sdk-csgo changes.
(cherry picked from commit 5714e7695a653dcade1832cb482855e77b5f13dd)
2022-06-24 10:00:36 -04:00
Nick Hastings 65cb76e2f6 Merge branch 'master' of https://github.com/alliedmodders/sourcemod 2022-06-24 10:00:13 -04:00
dysphie 678ad74bf4 Add sdktools gamerules support for NMRiH (#1784) 2022-06-24 10:00:02 -04:00
David Anderson 12e20eecf7 Update SourcePawn. 2022-06-24 10:00:02 -04:00
Margen67 a5ae01a2f4 .gitmodules: Make submodules shallow (#1769) 2022-06-24 10:00:02 -04:00
Vauff 614c7d8332 Expand ShowHudText message buffer for Protobuf games (#1777)
* Expand ShowHudText message buffer for CS:GO

* Expand buffer on Blade Symphony too
2022-06-24 10:00:02 -04:00
peace-maker 9121472061 DHooks: Error on argument passflags for detours (#1773)
The passflags are only supported by SourceHook for virtual hooks and are ignored for detours with DynamicDetours. This caused confusion, so throw an error when trying to set e.g. the DHookPass_ByRef flag on detour arguments.
2022-06-24 10:00:02 -04:00
peace-maker 54fd778830 DHooks: Fix changing of byref vector parameters (#1772)
We always created a new vector object instead of changing the passed in vector directly. This works for the function being called using our changed values - but the caller doesn't see the changed values if it's passing a vector by reference.

Only create a new vector if there isn't one being passed in and set the values directly in the passed in vector otherwise.
2022-06-24 10:00:01 -04:00
Deathreus 37c2a83523 Add a PluginIterator methodmap (#1779)
* Add a PluginIterator methodmap

* Follow convention

* Update sourcemod.inc

* Turn method ReadPlugin into property Plugin

* Requested change

* Update sourcemod.inc

* Curse you VSC

* Follow behavior of other iterators instead of the natives

* Fix a stray space

* Implement a hacked CPluginIterator

* Oops

Copy paste go brr

* Revert a change made before the custom impl
2022-06-24 11:46:03 +02:00
Nick Hastings 28a5d4b342 Merge branch 'master' of https://github.com/alliedmodders/sourcemod 2022-06-21 21:48:36 -04:00
Nick Hastings 0dcfdf3d7e Update TF2 gamedata. 2022-06-21 21:48:25 -04:00
dysphie 0f7f9dad97 Add sdktools gamerules support for NMRiH (#1784) 2022-06-20 16:47:11 +00:00
David Anderson 4276301499 Update SourcePawn. 2022-06-18 15:35:30 -07:00
Margen67 d41ffaad7e .gitmodules: Make submodules shallow (#1769) 2022-06-15 13:49:57 +02:00
Vauff 5c0ae11a46 Expand ShowHudText message buffer for Protobuf games (#1777)
* Expand ShowHudText message buffer for CS:GO

* Expand buffer on Blade Symphony too
2022-06-06 12:45:35 +00:00
peace-maker 7424deefb9 DHooks: Error on argument passflags for detours (#1773)
The passflags are only supported by SourceHook for virtual hooks and are ignored for detours with DynamicDetours. This caused confusion, so throw an error when trying to set e.g. the DHookPass_ByRef flag on detour arguments.
2022-05-31 14:58:36 +02:00
peace-maker c92354debb DHooks: Fix changing of byref vector parameters (#1772)
We always created a new vector object instead of changing the passed in vector directly. This works for the function being called using our changed values - but the caller doesn't see the changed values if it's passing a vector by reference.

Only create a new vector if there isn't one being passed in and set the values directly in the passed in vector otherwise.
2022-05-31 14:55:47 +02:00
Nick Hastings 50eca8e60c Update Reactive Drop gamedata (closes #1771) 2022-05-30 20:28:55 -04:00
Headline c570150318 Lift raw pointers out of DatabaseConfBuilder (#1637)
* Lift raw pointers out of DatabaseConfBuilder

* Maybe: not
2022-05-24 11:41:15 +02:00
David Anderson 3bafc1e2f4 Update SourcePawn. 2022-05-11 13:20:41 -07:00
Vauff e28bf30b7d Update WriteBaselines signature for CS:GO update (#1766) 2022-05-09 21:08:11 -07:00
Bone 7becdc48d3 fix WeaponPrice offset on windows (#1765) 2022-05-07 06:43:13 -04:00
Psykotikism 7a3d4e70bf Add "DispatchKeyValueInt" stock (#1764) 2022-05-06 14:53:57 +01:00
Arron Vinyard 6e73aba250 Remove unnecessary timer typeset entry (#1735) 2022-05-03 19:34:20 -07:00
Arron Vinyard 5797411b2b NPOTB: Use camel casing for variables in adminhelp.sp (#1750)
This is a stylistic change to ensure more adhered-to consistency throughout base plugins
2022-05-03 18:45:45 -07:00
Sikari d2c4257c36 Prevent workshop prefix from showing in nominations results menu (#1737)
Prevents workshop prefixes from being shown instead of the display names in results menus when items are disabled
2022-05-03 02:10:10 -07:00
domino_ b057580a62 Add a OnPlayerRunCmdPre forward (#1760)
Adds an OnPlayerRunCmdPre forward in order for plugins to be able to hook OnPlayerRunCmd with the guarantee that none of the parameters have been modified by other plugins. As such, OnPlayerRunCmdPre's parameters cannot be modified and are read-only. 

Plugins that wish to use OnPlayerRunCmdPre can maintain backwards compatibility with SourceMod 1.10 by falling back to OnPlayerRunCmd if the Pre variant was never fired.
2022-04-25 14:00:53 -07:00
Mikusch a1ad9e1acf Fix TF2_OnIsHolidayActive forward not getting called after map change (#1752)
* Fix TF2_IsHolidayActive forward not getting called after map change

* Rename function to Unhook
2022-04-22 11:49:46 +02:00
Mikusch a877a4475b SDKTools: Clear gamerules pointer on level shutdown (#1755)
* Clear gamerules pointer on level shutdown

* Move LevelShutdown up
2022-04-22 11:48:21 +02:00
Alienmario 441259e36a Add recent gamedata for BMS, HL2DM (#1756) 2022-04-21 21:49:19 +00:00
Kyle ab8bbbd118 Honor AUTOLOAD_EXTENSIONS in clientprefs include (#1718)
* Optional autoload extensions

* revert autoload for cstrike/tf2
2022-04-21 13:44:24 +02:00
peace-maker 39d604ae6c DHooks: Allow setting CBaseEntity* param to NULL #1751 (#1754)
* DHooks: Allow setting CBaseEntity* param to NULL #1751

The param had to be a valid entity and wasn't allowed to be set to NULL. Behave similar to SetReturn which maps INVALID_ENT_REFERENCE (or -1) to NULL.

* Update include documentation
2022-04-20 15:32:37 +02:00
peace-maker a7cb35c2af Add -m flag to checkout-deps to avoid downloading MySQL (#1753)
If you just want to build an extension or SourceMod core and not the MySQL extension, don't download the large MySQL library archive.
2022-04-20 14:34:47 +02:00
XeroX ff558b32e5 ZPS Update offsets for 3.2.4 (#1746)
* Update offsets for ZPS 3.2

Zombie Panic! Source Version 3.2 released and these are the updated offsets.

* Update offsets for 3.2

ZPS 3.2 has been release and these are the updated offsets / signatures.

* ZPS: Add missing offsets.

Adds support for OnTakeDamage_Alive, GetMaxHealth, Blocked, Reload and GroundEntChanged.
I wasn't aware these were missing entirely or I would have pushed them with the previous PR.

* ZPS Add missing offsets.

Adds support for GivePlayerAmmo.
Wasn't aware these were missing the first place.

* Fix ForcePlayerSuicide not properly working in ZPS

ZPS requires the second bool parameter to be true otherwise it won't do anything for players in the lobby or delayed for players on either team 2 or team 3.

* Fixed breaking code for other mods.

Added bForce which is set to true for zps.

* Update offsets for ZPS 3.2.4

Updates the offset
2022-04-16 14:07:46 +00:00
XeroX 6b588fff61 ZPS: Add missing offsets (#1719)
* Update offsets for ZPS 3.2

Zombie Panic! Source Version 3.2 released and these are the updated offsets.

* Update offsets for 3.2

ZPS 3.2 has been release and these are the updated offsets / signatures.

* ZPS: Add missing offsets.

Adds support for OnTakeDamage_Alive, GetMaxHealth, Blocked, Reload and GroundEntChanged.
I wasn't aware these were missing entirely or I would have pushed them with the previous PR.

* ZPS Add missing offsets.

Adds support for GivePlayerAmmo.
Wasn't aware these were missing the first place.

* Fix ForcePlayerSuicide not properly working in ZPS

ZPS requires the second bool parameter to be true otherwise it won't do anything for players in the lobby or delayed for players on either team 2 or team 3.

* Fixed breaking code for other mods.

Added bForce which is set to true for zps.
2022-04-16 14:07:16 +00:00
MartLegion 3f3f1b8914 Moved pvkii section for better readbility (#1744)
Moved pvkii section above for better readbility
(requested by psychonic)
2022-04-12 14:09:33 +00:00
MartLegion 05e48ef866 Added PVKII game with related team colors (beacon) (#1743)
Spectators = Yellow
Pirates = Red
Vikings = Green
Knights = Blue
2022-04-12 13:57:18 +00:00
Gaben 6e1f095186 Allow h-flag admins to bypass vote delay (#1733) 2022-04-12 11:19:54 +01:00
Arron Vinyard 852703ccca Add GetCmdArgFloat(Ex) stocks (#1742) 2022-04-12 11:17:05 +01:00
David Anderson 01203a5a44 Update SourcePawn. 2022-03-09 18:00:54 -08:00
Mikusch 96ae65a96c Remove misleading note on DynamicHook.RemoveHook docs (#1725) 2022-03-07 12:34:25 -05:00
James Dickens 9df93b0708 Fix Int64ToString producing incorrect output (#1723) 2022-03-04 03:03:35 -08:00
rtldg f307e44b79 Correct some function docs that return char count (#1721) 2022-02-25 15:20:12 -08:00
V dc8a22a76a Inline one-expression single-use functions (#1700) 2022-02-25 10:39:45 +01:00
XeroX 8579e873ca ZPS: Update Offsets & Signatures for 3.2 (#1717)
* Update offsets for ZPS 3.2

Zombie Panic! Source Version 3.2 released and these are the updated offsets.

* Update offsets for 3.2

ZPS 3.2 has been release and these are the updated offsets / signatures.
2022-02-19 14:33:15 +00:00
Corey D addfb3c8a1 Add MAX_AUTHID_LENGTH (#1696) 2022-02-15 10:21:35 +00:00
Erik Minekus 358bcca3a2 Database.Format destination buffer should not be marked const (#1714) 2022-02-14 07:39:03 -05:00
Corey D b209279589 Add bitwise SetBitFlags for AdminId and GroupId (#1677)
* Add bitwise SetFlags for AdminId

* Inline SetFlags natives
2022-02-12 13:14:57 +01:00
XeroX 5479084039 ZPS: Add LookupEntityAttachment and GetEntityAttachment Gamedata (#1706)
* Add LookupAttachment and GetAttachment

Offset and Signature for Zombie Panic! Source.

* Fix Gamerules not being available

This fixes the issue that would throw an error when trying to use SDKCall with type SDKCall_GameRules.

* Add SetOwnerEntity offset

Add SetOwnerEntity offset
2022-02-08 17:56:31 -08:00
Asher Baker 95ab60c4eb Stop SQLite results being used before being fetched (#1709)
The DB API requires FetchRow to be called before accessing any values
from a row, but the SQLite driver did not enforce that requirement and
alowed accessing the first row immediately. A plugin developer hit this
when developing against SQLite locally but using MySQL in production,
where the API misuse threw an error as expected.

Resolves #1691
2022-02-06 16:34:14 +00:00
Asher Baker 2111e90540 Fix FindSendPropOffs with SendPropArray props (#1708)
FindSendPropOffs is deprecated and FindSendPropInfo behaves correctly
here, but there are still a lot of old plugins using FindSendPropOffs.
One of the SendPropArray props broken by the changes here is
m_hViewModel which there are known plugins in the wild accessing.
2022-02-06 15:56:52 +00:00
Alienmario dc9c52bfd6 Enable nextmap for Black Mesa (#1695) 2022-02-04 13:50:26 +00:00
Ҝℴţأķ f5461df28c Remove hardcoded question mark from sm_vote (#1699) 2022-02-03 10:56:25 +00:00
e5afdb4181 adminhelp.sp -> Switch to the new CommandIterator() (#1388)
* Switch to the new CommandIterator() methodmap

`ReadCommandIterator` 
->
```
CmdIter.GetName(Name, sizeof(Name));
Flags = CmdIter.Flags;
CmdIter.GetDescription(Desc, sizeof(Desc));
```

* PeaceMaker fixes

* Don't fetch unused properties

Co-authored-by: Michael Flaherty <[email protected]>
Co-authored-by: Peace-Maker <[email protected]>
2022-02-01 19:13:06 +01:00
Arron Vinyard 250dc1b206 Update dhooks.inc documentation for consistency (#1658)
* Update dhooks.inc documentation for consistency

- Modifies whitespace (change tabs to spaces for non initial indents, fix alignments, create consistency with rest of SM docs)
- Change `/*` to `/**` for consistency and to indicate comment doc
- Removes incorrect `@noreturn` doc

* Split long comments across multiple lines

* Remove `@noreturn` in IGameConfigs.h

* Remove `@noreturn` from IGameHelpers.h

* Remove `@noreturn` from asm.c

* Add `@noreturn` to ThrowError

* Add `@noreturn` and `@error` to ThrowNativeError
2022-02-01 18:46:59 +01:00
komashchenko f5f26e2dfe Fix GetGameSoundParams in CSGO (#1631)
* Fix GetGameSoundParams CSGO

* Added preprocessor comments

* Revert InternalPrecacheScriptSound
2022-02-01 17:14:53 +01:00
peace-maker f7c54e9027 Fix silent error on large ArrayList startsize (#1705)
If there isn't enough memory to resize the ArrayList to the startsize on construction, throw an error instead of ignoring the OOM.

Fixes #1551
2022-01-31 22:07:32 +01:00
dysphie 1ce828b6c8 Add NMRiH support for new collision and attachment natives (#1702)
- Add "GetAttachment" offset
- Add "SetOwnerEntity" offset
- Add "LookupAttachment" signature
2022-01-26 19:51:37 +01:00
Corey D c471e41dc7 Add ArrayStack.Clear native (#1676) 2022-01-22 03:26:21 -08:00
Mikusch afc9310704 Add LookupEntityAttachment & GetEntityAttachment natives (#1653)
Using the virtual `CBaseAnimating::GetAttachment(int, matrix3x4_t &)` was a deliberate choice because virtual offsets are generally easier to maintain than signatures. The `matrix3x4_t` is converted to world position and world angles internally.
Some of the other overloads are also inlined on a few games, making this the best choice.

Since this call can only be used on classes inheriting `CBaseAnimating`, we check if the `DT_BaseAnimating` SendTable exists on the entity, throwing a native error if it doesn't.
This safeguard could be greatly improved with a call to `CBaseEntity::GetBaseAnimating`, but would require more gamedata (maybe something to consider for the future?)
2022-01-03 13:13:54 +00:00
Corey D bf898dd45f Fix ArrayList return types (#1679)
ArrayList.SetString and ArrayList.SetArray both have int return types but their methodmap natives use void.
2021-12-27 12:17:04 +01:00
naydef 7d6eb2bd81 Fix crash in non-bypass-hooks DropWeapon implementation (#1672)
Fixes #1670
2021-12-15 10:41:55 +00:00
Nick Hastings 547ac5b026 Fix helpers module path lookup on newer Perl versions. 2021-12-13 13:16:14 -05:00
Nick Hastings 7328ce657b Missing ;s. 2021-12-13 12:59:20 -05:00
Nicholas Hastings 14c9ac8fdb [Buildbot] Delete package after successful upload. (#1665)
* [Buildbot] Delete package after successful upload.

* Use autodie.

* ;
2021-12-13 17:52:26 +00:00
Nick Hastings 93cd78a6c5 Remove dead code. 2021-12-13 10:00:42 -05:00
Nick Hastings b62f332611 Use SteamWorks C++ API in CStrike RulesFix, for better interface compatibility. 2021-12-13 09:34:00 -05:00
Asher Baker 47f135534d Upload libsourcepawn Breakpad symbols as well 2021-12-12 15:04:40 +00:00
Asher Baker bb095097a2 Upload libsourcepawn debug symbols 2021-12-12 14:43:32 +00:00
David Anderson c873e1aafb Update SourcePawn/AMTL to fix build. 2021-12-11 16:28:04 -08:00
Fyren 455bb14589 Update SP. 2021-12-11 04:13:59 -05:00
Headline e786ff54f7 Prevent enum shadowing & pin sourcemod for build fixes (#1661) 2021-12-10 14:22:04 -08:00
David Anderson af3c10b173 Update AMTL. 2021-12-09 18:14:28 -08:00
David Anderson 351ac171d2 Merge branch 'fix-menu-vote-handler' 2021-12-09 18:13:30 -08:00
David Anderson 96c74651db Fix vote menu handler to work with direct arrays. 2021-12-09 18:10:35 -08:00
Benoist 329d587214 Fix ShouldCollide originalResult behaviour (#1657) 2021-11-30 09:24:56 +00:00
David Anderson 4e3df76358 Update SourcePawn.
Fix fix an hl2sdk-mock build error.
2021-11-23 00:11:48 -08:00
Stanislav Polshyn 161084e6f8 gamedata: Add SetEntityOwner L4D1 offset (#1649) 2021-11-22 16:46:07 -08:00
b38c9824fe sdktools: Add EntityCollisionRulesChanged & SetEntityOwner natives (#1620)
* Add EntityCollisionRulesChanged & SetEntityOwner natives

* fix win build, and unpushed changes

* Fixed bad world loop

* Requested changes + csgo offsets

* small copy paste mistake

* Strip the debug log lines

* Tiny clean up in comments

* line

* <dvander> try again

* sdktools: add default Param for owner.

Co-authored-by: Kenzzer <[email protected]>
Co-authored-by: Kyle Sanderson <[email protected]>
2021-11-21 23:03:35 -08:00
Adrián 4e4c2a7bb0 menusys: Correct GetMenuExitBackButton returncode (#1646) 2021-11-20 16:52:40 -08:00
peace-maker 1c30b88069 Cache copy of library on first symbol/signature lookup (#1642)
Always perform signature searches on an unaltered copy of the binary. This avoids signature mismatches if the same function is detoured twice and thus the first bytes of the function were replaced by the detour.
2021-11-18 17:55:32 +01:00
David Anderson 31f6c0cb18 Dedent some menu code for readability. 2021-11-17 18:19:40 -08:00
Peace-Maker 9cb693d8a3 Ignore all build* folders in .gitignore
I frequently have one like `buildwin` and `buildlin` for the different OS in WSL.
2021-11-17 13:17:39 +01:00
Peace-Maker 896e92264f Use SourceMod's version number 2021-11-17 13:17:39 +01:00
Peace-Maker f32b210ec9 Print OS errors if mprotect fails
This helped catch a bug in DHooks before, so it's worth adding it in here as well.
2021-11-17 13:17:39 +01:00
Peace-Maker 8f7ecf66a4 Use JMP patching of CDetour 2021-11-17 13:17:39 +01:00
Peace-Maker 581068c09b Add copyright headers 2021-11-17 13:17:39 +01:00
Peace-Maker 0f5f1a814e Import DHooks + Dynamic Detouring
This is the latest DHooks version from https://github.com/peace-maker/DHooks2/tree/1314f2d1b4d870677a1b9f628c770f2799878f9b
2021-11-17 13:17:39 +01:00
Adrián 18f9d65938 Fix translations getting truncated prematurely (#1640) 2021-11-16 16:09:30 +00:00
Nick Hastings 589fc96bc9 Update Contagion SDKHooks gamedata. 2021-11-15 21:26:23 -05:00
Nick Hastings 5787fca029 Disable Reserved Slots plugin on Contagion.
(It doesn't have sv_visiblemaxplayers).
2021-11-15 20:53:09 -05:00
Nick Hastings 09ea982bbd Make separate copy of makesig script for IDA 7.x. 2021-11-15 20:52:37 -05:00
Mikusch e3569edb65 Update Team Fortress 2 gamedata
Shift virtual offsets up by 3
2021-11-15 20:43:51 -05:00
Nick Hastings 3db7116620 Update Contagion SDKTools gamedata. 2021-11-15 20:31:54 -05:00
dysphie 83672a6ce0 Fix "ForcePlayerSuicide" linux offset in NMRiH (#1627) 2021-11-12 09:19:41 +01:00
David Anderson 90fec5c6df Add support for ASAN. 2021-11-11 23:41:42 -08:00
David Anderson 257535daf2 Update SourcePawn.
This fixes a few more regressions found in the new compiler.
2021-11-07 18:16:20 -08:00
David Anderson eb0878be2b Update SourcePawn.
This fixes a recent stability regression.
2021-11-02 10:51:00 -07:00
Nick Hastings f229badbfc Fix server binary name for CRC lookups. 2021-11-01 13:04:23 -04:00
Nick Hastings 9a6866d14a Invert CRC to match most popular implementations. 2021-11-01 13:04:23 -04:00
dysphie 8991b557ab Update gamedata for NMRiH 1.12 (#1623)
* Fix NMRiH's sdktools gamedata

* Fix NMRiH's sdkhooks gamedata

* Fix GroundEntChanged linux offset
2021-11-01 01:42:45 +00:00
David Anderson be60a55aa3 Update SourcePawn. 2021-10-31 12:30:51 -10:00
David Anderson 10795fbed5 Switch to clang-8.
This is the new minimum supported Clang version going forward.
2021-10-27 09:44:19 -10:00
FortyTwoFortyTwo 9d7e720f33 Fix compiling with tf2_stocks 2021-10-27 07:51:33 -04:00
David Anderson 7605940994 Fix build. 2021-10-26 23:33:00 -07:00
David Anderson 94ff26bdf1 Fix error return of FormatNativeString. (#1613) 2021-10-26 22:31:58 -07:00
David Anderson 2a06680252 Update to the new SourcePawn compiler.
This imports the brand new SourcePawn compiler. The new compiler is much
faster to compile and generates significantly improved code around
array generation and array access.

There are a number of compatibility changes in the new compiler. Most of
these are due to improved type checking and error detection. The full
list of notes can be found here:

https://github.com/alliedmodders/sourcepawn/blob/master/docs/upgrading-1.11.md

Additionally, .smx files generated by the new compiler will NOT load on
earlier versions of SourceMod, including earlier versions of 1.11. Old
plugins will continue to load as normal.
2021-10-26 17:45:48 -10:00
Nick Hastings 38a069b97a Throw error if unknown SDK call type specified. 2021-10-26 17:32:25 -04:00
Nick Hastings 4b58b9f673 Reorder SDKCallType enum for better compatibility with existing plugins. 2021-10-26 17:32:02 -04:00
dragokas ffc23a1a1e Exposed SDKCall_Server call type to use CBaseServer methods 2021-10-26 17:18:16 -04:00
David Anderson cab60f7385 Bump handle limit to 1MB.
This bumps the handle bits to 20 and reduces the serial/cookie bits to
12. A warning is emitted if a single owner creates more than 100k
handles.

Tested on mock srcds with sm_dump_handles.
2021-10-26 07:05:34 -10:00
Kyle 92ce0fe814 Update TerminateRound signature for CSGO 2021-10-26 09:46:21 -04:00
Vladimir 79d594aca3 Add OnClientLanguageChanged() forward (#1597) 2021-10-25 19:45:24 +01:00
Asher Baker a343410793 Fix build against released MM:S branches (#1607)
`SOURCE_ENGINE_MOCK` is part of the MM:S API and only available in 1.12
which is the dev branch of MM:S. We can build the mock SM build without
it anyway, but this is still a little gross as it is just missing loader
support which could be confusing.

This also changes AMBuildScript to first look for a checkout of MM:S
1.11 which has been the stable branch for a while, 1.10 is still allowed
as a fallback as that seems to still build without issue.
2021-10-25 19:42:51 +01:00
Nick Hastings 3332da3489 Fix up OnClientSettingsChange logic order.
- Fixes bot name cache not getting updated (see #1579)
- Fixes IClientListener::OnClientSettingsChanged not being called for bots.
2021-10-24 10:07:55 -04:00
Nick Hastings 1a65b308d1 Add support for other Steam ID formats to admin-sql-threaded (#1520). 2021-10-24 09:57:03 -04:00
Nick Hastings f9309c83d2 Don't cache replay_enable value when evaling whether to use FileExists hook.
Speculative fix for #1581
2021-10-24 08:54:15 -05:00
Nick Hastings 636161e183 Mark unloaded extensions as not fully loaded (fixes #1574). 2021-10-24 08:52:32 -05:00
Charles 897878f8ae Removed incorrect parameter RemoveChangeHook desc 2021-10-23 11:28:23 -05:00
Charles 7650cee459 Removed incorrect parameter in description 2021-10-23 11:28:23 -05:00
Corey D 30c764e4b3 Use words instead of quotes for better clarity
As suggested by sneak-it
2021-10-23 11:25:10 -05:00
Corey D dc92335fbe Missed Database.Escape 2021-10-23 11:25:10 -05:00
Corey D 8c625ca87d Clarify SQL_EscapeString usage
It's hard to see the difference between 2 single-quotes and 1 double-quote unless you highlight it.
2021-10-23 11:25:10 -05:00
Nick Hastings 536750b428 Add missing parameters for CSWeaponDrop. 2021-10-22 23:42:45 -04:00
GAMMACASE 11e7bb10f1 Fix CS_OnCSWeaponDrop after latest CSGO update (21/10/21) (#1602) 2021-10-22 16:20:54 +01:00
Vauff f7cd28cfd3 Update HandleCommand_Buy_Internal sig and related offsets for CS:GO Win 2021-10-21 21:21:36 -05:00
Vauff 83c7bdf872 Update CSWeaponDropBB signature for CS:GO Linux 2021-10-21 19:46:20 -05:00
Nick Hastings 97383028e5 Add option to not bypass hooks with TakeDamage and DropWeapon natives. 2021-10-13 12:56:26 -04:00
Nick Hastings 4a6d263dad Remove obsolete core-legacy checks. 2021-10-13 12:56:26 -04:00
Nick Hastings 549e881ba4 Fix attempting to link win32 libprotobuf on win64. 2021-10-13 12:05:51 -04:00
Nick Hastings c72ea03a86 Use MM:S master for Windows builds (already doing for Linux/Mac). 2021-10-13 10:36:36 -04:00
Nicholas Hastings 9fed0724f7 Typo fix. 2021-10-13 09:57:09 -04:00
Nick Hastings ed96da1afc Fix incorrect param types in CS:GO GNI (otherwise broken for x64). 2021-10-12 20:56:51 -04:00
Nick Hastings da3146e294 Remove manual ptr math in vnatives for params not mapped to cell params. 2021-10-12 20:56:51 -04:00
Nick Hastings 5aa0cdfd45 Fix Blade Symphony GiveNamedItem call on x64. 2021-10-12 20:56:51 -04:00
Nick Hastings 0be7813398 Add ValveType_Object type.
This is for the few cases where we have function parameters to objects that
don't fit our other predefined types (CBaseEntity, CBasePlayer, string).

Most calls currently pass those as POD (which is incorrect, but works on
x86), or one of the other pointer types (which is also incorrect, and can
lead to confusion, but works on x86 and x86-64).

This type only works when manually buffering the parameter for calls, and
is not supported for return types.
2021-10-12 20:56:51 -04:00
Nick Hastings de84f47503 On Linux, link against server libs instead of client (fixes META_CONPRINT). 2021-10-12 20:56:51 -04:00
Nick Hastings 115e3d4392 Update multiple SDKTools calls to be x64-safe [sizeof(void*) != sizeof(int)] 2021-10-12 20:56:51 -04:00
Nick Hastings 9f101ce67f Add missing WriteBaselines signatures for Blade Symphony. 2021-10-12 20:56:51 -04:00
Nick Hastings 9295bc4fbb Fix crash with IBinTools calls on x64 for functions with void return. 2021-10-12 20:56:51 -04:00
Nick Hastings 9e083ec668 Use new GetIServer call and updated IServerTools calls on Blade Symphony. 2021-10-12 20:56:51 -04:00
Nick Hastings 68c8857410 Enable more CS:GO engine logic for Blade Symphony. 2021-10-12 20:56:51 -04:00
Nick Hastings 9323d1094f Blade Symphony gamedata updates, round 1. 2021-10-12 20:56:51 -04:00
Nick Hastings dc2967b2e7 Fix CS:GO transposing of GiveNamedItem last param and return. 2021-10-12 20:56:51 -04:00
Nick Hastings 6d85c09e69 Enable 64-bit builds for Blade Symphony. 2021-10-12 20:56:51 -04:00
Nick Hastings 6a8177145d Add .vs and .vscode dirs to .gitignore. 2021-10-12 20:38:44 -04:00
dysphie baf686c6c4 Fix NMRiH's 'GivePlayerAmmo' offset on Windows (#1593) 2021-10-06 20:20:04 +00:00
naydef 34c5eed867 Update float.inc (#1591) 2021-10-02 20:23:43 +00:00
A1m` 59840685a4 Fix 'GiveNamedItem' in the game left4dead2. (#1590)
* Fix 'GiveNamedItem' in the game left4dead2.

The method 'CCSPlayer::GiveNamedItem(char const*, int, CBaseEntity*)' does not work in game left4dead2, any given weapon and object immediately falls to the ground, besides, the code is missing a parameter to call this method (even with the added parameter does not give a weapon to hands). Another method 'CTerrorPlayer::GiveNamedItem(char const*, int, bool, CBaseEntity*)' works great, besides it makes it possible to give out all the items that exist in the game.

* Add x64 support

Add x64 support

* Changed argument type to bool.

Changed argument type to bool.
2021-10-02 14:45:18 +00:00
David Anderson c4e33cab8c Update bootstrap.pl 2021-09-27 20:27:21 -07:00
David Anderson bf0741e48a Use master for Metamod:Source builds. 2021-09-27 20:27:21 -07:00
David Anderson 51b5bbac0d Don't require hl2sdk-mock if sdks=all 2021-09-27 17:11:33 -07:00
pedrotski 03699a4a9e Update CS:GO Reload gamedata (#1585) 2021-09-23 11:44:15 +01:00
nosoop 57a38636fc TF2Tools: Prevent CalcIsAttackCriticalHelper* from being called twice (#1573)
* Ensure CalcIsAttackCriticalHelper only gets called once

* fixup: move origReturnValue up
2021-09-23 12:00:52 +02:00
David Anderson a5f99c57e1 Add support for hl2sdk-mock. 2021-09-22 12:36:44 -07:00
David Anderson 1b0c7bc1b8 Add support for hl2sdk-mock. 2021-09-22 12:36:44 -07:00
GAMMACASE d84fd76070 Update gamedata after latest CSGO update (22/09/21) (#1583) 2021-09-22 09:37:22 +01:00
Nick Hastings 677697a168 Trigger build for TF2 SDK INetChannel changes. 2021-09-16 22:07:57 -04:00
Nick Hastings 0fd4fa7066 Trigger build for TF2 SDK changes. 2021-09-16 21:05:01 -04:00
Bara 0932d78d26 Update sourcepawn 2021-09-13 23:44:14 -07:00
Vladimir 106f807b68 Fix crash in FindSendPropInfo() when the prop was DPT_DataTable (#1575) 2021-09-06 18:42:04 -07:00
Asher Baker c3e6428ff7 Revert "Switch internal SM concept of frames to use Think (#1540)" (#1572)
This reverts commit b383302128.
2021-08-25 19:59:57 +01:00
Asher Baker 78cb89938d Remove OnEntitySpawned forward (#1571)
`OnEntitySpawned` is 1.11 only, so this is fine given our API stability guarantees.

Unfortunately the forward name clashes with quite a few plugins using the same name for their SDKHook callback. Normally we'd just put up with this but there are difficult to solve binary compatibility issues where those plugins will get the callback double-called, and there is a separate issue where the forward isn't called for all entity spawns (unlike the SDKHook), so most plugins can't switch to the forward anyway.

Resolves #1558.

This reverts commit 7bab9cc344.
2021-08-23 21:36:20 +01:00
999 changed files with 115277 additions and 31725 deletions
+8
View File
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"
+10 -8
View File
@@ -3,14 +3,16 @@ on:
push:
branches:
- master
- '[0-9]+.[0-9]+-dev'
pull_request:
branches:
- master
- '[0-9]+.[0-9]+-dev'
jobs:
test:
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-latest, windows-latest]
os: [ubuntu-20.04, ubuntu-latest, windows-latest]
include:
- os: windows-latest
os_short: win
@@ -19,10 +21,10 @@ jobs:
os_short: linux
compiler_cc: clang
compiler_cxx: clang++
- os: ubuntu-18.04
- os: ubuntu-20.04
os_short: linux
compiler_cc: clang-3.9
compiler_cxx: clang++-3.9
compiler_cc: clang-8
compiler_cxx: clang++-8
fail-fast: false
runs-on: ${{ matrix.os }}
name: ${{ matrix.os_short }}-${{ matrix.compiler_cc }}
@@ -32,15 +34,15 @@ jobs:
DEPENDENCIES_FOLDER: dependencies
DEPENDENCIES_ROOT: ${{ github.workspace }}/dependencies
MYSQL_VERSION: '5.5'
MMSOURCE_VERSION: '1.10'
MMSOURCE_VERSION: '1.12'
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: recursive
path: sourcemod
- name: Cache dependencies
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: hl2sdk-mysql-mmsource
with:
@@ -51,7 +53,7 @@ jobs:
${{ runner.os }}-build-${{ env.cache-name }}-mysql${{ env.MYSQL_VERSION }}-
# Setup Python for AMBuild
- uses: actions/setup-python@v2
- uses: actions/setup-python@v5
name: Setup Python 3.8
with:
python-version: 3.8
+104
View File
@@ -0,0 +1,104 @@
name: hl2sdk-mock tests
on:
push:
branches:
- master
- '[0-9]+.[0-9]+-dev'
pull_request:
branches:
- master
- '[0-9]+.[0-9]+-dev'
jobs:
mock:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
name: Clone sourcemod
with:
submodules: recursive
path: sourcemod
- uses: actions/checkout@v4
name: Clone metamod-source
with:
repository: alliedmodders/metamod-source
submodules: recursive
path: metamod-source
- uses: actions/checkout@v4
name: Clone hl2sdk-mock
with:
repository: alliedmodders/hl2sdk-mock
submodules: recursive
path: hl2sdk-mock
- uses: actions/setup-python@v5
name: Setup Python 3.10
with:
python-version: "3.10"
- name: Install AMBuild
run: |
python -m pip install --upgrade pip setuptools wheel
pip install git+https://github.com/alliedmodders/ambuild
- name: Build MetaMod:Source
working-directory: metamod-source
run: |
python configure.py --enable-optimize --sdks=mock --targets=x86_64
ambuild objdir
- name: Build SourceMod
working-directory: sourcemod
run: |
python configure.py --no-mysql --enable-optimize --sdks=mock --targets=x86_64
ambuild objdir
- name: Build hl2sdk-mock
working-directory: hl2sdk-mock
run: |
python configure.py --enable-optimize --targets=x86_64
ambuild objdir
- name: Setup gamedir
working-directory: hl2sdk-mock
shell: bash
run: |
mkdir ../gamedir
./build_gamedir.sh ../gamedir ../metamod-source/objdir/package
./build_gamedir.sh ../gamedir ../sourcemod/objdir/package
- name: Compile testsuite
working-directory: hl2sdk-mock
shell: bash
run: |
mkdir ../gamedir/addons/sourcemod/plugins/optional
for f in ../sourcemod/plugins/testsuite/mock/*.sp; do
echo "Compiling $(basename $f)"
../gamedir/addons/sourcemod/scripting/spcomp64 -i ../gamedir/addons/sourcemod/scripting/include -o "../gamedir/addons/sourcemod/plugins/optional/$(basename $f .sp).smx" -E "$f"
done
- name: Test
working-directory: hl2sdk-mock
shell: bash
run: |
for f in ../gamedir/addons/sourcemod/plugins/optional/*.smx; do
echo "==================================="
echo "Running $(basename $f)..."
echo "==================================="
timeout 60 ./objdir/dist/x86_64/srcds -game_dir ../gamedir +map de_thunder -command "sm plugins load optional/$(basename $f)" -run -run-ticks 20 |
{
failed=0
while IFS= read -r line; do
echo "$line"
if [[ "$line" == *"FAIL"* ]]; then
failed=1
fi
done
if [ "$failed" = "1" ]; then
echo "$(basename $f) failed."
exit 1
fi
}
done
+6 -5
View File
@@ -3,6 +3,7 @@ on:
push:
branches:
- master
- '[0-9]+.[0-9]+-dev'
paths:
- 'plugins/include/*'
- 'sourcepawn/**'
@@ -26,12 +27,12 @@ jobs:
env:
ARCH: x86,x86_64
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: recursive
# Setup Python for AMBuild
- uses: actions/setup-python@v2
- uses: actions/setup-python@v5
name: Setup Python 3.8
with:
python-version: 3.8
@@ -40,9 +41,9 @@ jobs:
python -m pip install --upgrade pip setuptools wheel
pip install git+https://github.com/alliedmodders/ambuild
- name: Build only for x64 on macOS
- name: Build universal x64/arm64 on macOS
if: startsWith(runner.os, 'macOS')
run: echo "ARCH=x86_64" >> $GITHUB_ENV
run: echo "ARCH=x86_64,arm64" >> $GITHUB_ENV
- name: Install Linux dependencies
if: startsWith(runner.os, 'Linux')
@@ -72,7 +73,7 @@ jobs:
echo "SM_VERSION=$(cat ../product.version)" >> $GITHUB_ENV
- name: Archive tooling
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: sourcemod-tooling-${{ env.SM_VERSION }}-${{ matrix.os_short }}
path: build/package
+42
View File
@@ -0,0 +1,42 @@
name: Update translation project
on:
push:
branches:
- master
paths:
- 'translations/**'
workflow_dispatch:
jobs:
update_translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v5
name: Setup Python 3.10
with:
python-version: "3.10"
- name: Install Python dependencies
working-directory: tools/language_check
run: |
python -m pip install --upgrade -r requirements.txt
- name: Generate token
id: generate_token
uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a
with:
app_id: ${{ secrets.APP_ID }}
private_key: ${{ secrets.APP_PEM }}
- name: Update translation project
working-directory: tools/language_check
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
ORGANIZATION: alliedmodders
PROJECT_NUMBER: 1
run: |
python ./compare_translation_phrases.py
@@ -0,0 +1,29 @@
name: Sanity check translation phrases
on:
push:
branches:
- master
paths:
- 'translations/**'
pull_request:
branches:
- master
paths:
- 'translations/**'
workflow_dispatch:
jobs:
check_translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
name: Setup Python 3.10
with:
python-version: "3.10"
- name: Check translation phrases syntax
working-directory: tools/language_check
run: |
python ./sanity_check.py
+5 -1
View File
@@ -28,7 +28,6 @@ LIB-Debug/
[Tt]humbs.db
# AMBuild build directories
build/
obj-*/
*~
*.rej
@@ -37,3 +36,8 @@ obj-*/
*.swp
*.gdb_history
objdir
# Not standardized, but common name for build directories
build*/
.vs/*
.vscode/*
+8
View File
@@ -1,6 +1,14 @@
[submodule "public/amtl"]
path = public/amtl
url = https://github.com/alliedmodders/amtl
shallow = true
[submodule "sourcepawn"]
path = sourcepawn
url = https://github.com/alliedmodders/sourcepawn
shallow = true
[submodule "hl2sdk-manifests"]
path = hl2sdk-manifests
url = https://github.com/alliedmodders/hl2sdk-manifests.git
[submodule "public/safetyhook"]
path = public/safetyhook
url = https://github.com/alliedmodders/safetyhook
+156 -242
View File
@@ -1,70 +1,7 @@
# vim: set sts=2 ts=8 sw=2 tw=99 et ft=python:
import collections
import os, sys
import traceback
class SDK(object):
def __init__(self, sdk, ext, aDef, name, platform, dir):
self.folder = 'hl2sdk-' + dir
self.envvar = sdk
self.ext = ext
self.code = aDef
self.define = name
self.platform = platform
self.name = dir
self.path = None # Actual path
self.platformSpec = platform
# By default, nothing supports x64.
if type(platform) is list:
self.platformSpec = {p: ['x86'] for p in platform}
else:
self.platformSpec = platform
def shouldBuild(self, targets):
for cxx in targets:
if cxx.target.platform in self.platformSpec:
if cxx.target.arch in self.platformSpec[cxx.target.platform]:
return True
return False
WinOnly = ['windows']
WinLinux = ['windows', 'linux']
WinLinuxMac = ['windows', 'linux', 'mac']
CSGO = {
'windows': ['x86'],
'linux': ['x86', 'x86_64'],
'mac': ['x86_64']
}
SDKMap = {
'episode1': SDK('HL2SDK', '2.ep1', '1', 'EPISODEONE', WinLinux, 'episode1'),
'ep2': SDK('HL2SDKOB', '2.ep2', '3', 'ORANGEBOX', WinLinux, 'orangebox'),
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
'hl2dm': SDK('HL2SDKHL2DM', '2.hl2dm', '7', 'HL2DM', WinLinuxMac, 'hl2dm'),
'dods': SDK('HL2SDKDODS', '2.dods', '8', 'DODS', WinLinuxMac, 'dods'),
'sdk2013': SDK('HL2SDK2013', '2.sdk2013', '9', 'SDK2013', WinLinuxMac, 'sdk2013'),
'tf2': SDK('HL2SDKTF2', '2.tf2', '11', 'TF2', WinLinuxMac, 'tf2'),
'l4d': SDK('HL2SDKL4D', '2.l4d', '12', 'LEFT4DEAD', WinLinuxMac, 'l4d'),
'nucleardawn': SDK('HL2SDKND', '2.nd', '13', 'NUCLEARDAWN', WinLinuxMac, 'nucleardawn'),
'l4d2': SDK('HL2SDKL4D2', '2.l4d2', '15', 'LEFT4DEAD2', WinLinuxMac, 'l4d2'),
'darkm': SDK('HL2SDK-DARKM', '2.darkm', '2', 'DARKMESSIAH', WinOnly, 'darkm'),
'swarm': SDK('HL2SDK-SWARM', '2.swarm', '16', 'ALIENSWARM', WinOnly, 'swarm'),
'bgt': SDK('HL2SDK-BGT', '2.bgt', '4', 'BLOODYGOODTIME', WinOnly, 'bgt'),
'eye': SDK('HL2SDK-EYE', '2.eye', '5', 'EYE', WinOnly, 'eye'),
'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', CSGO, 'csgo'),
'portal2': SDK('HL2SDKPORTAL2', '2.portal2', '17', 'PORTAL2', [], 'portal2'),
'blade': SDK('HL2SDKBLADE', '2.blade', '18', 'BLADE', WinOnly, 'blade'),
'insurgency': SDK('HL2SDKINSURGENCY', '2.insurgency', '19', 'INSURGENCY', WinLinuxMac, 'insurgency'),
'contagion': SDK('HL2SDKCONTAGION', '2.contagion', '14', 'CONTAGION', WinOnly, 'contagion'),
'bms': SDK('HL2SDKBMS', '2.bms', '10', 'BMS', WinLinux, 'bms'),
'doi': SDK('HL2SDKDOI', '2.doi', '20', 'DOI', WinLinuxMac, 'doi'),
}
# Stable sorting for command equivalence in AMBuild.
PossibleSDKs = collections.OrderedDict()
for key in sorted(SDKMap.keys()):
PossibleSDKs[key] = SDKMap[key]
import subprocess
def ResolveEnvPath(env, folder):
if env in os.environ:
@@ -95,9 +32,15 @@ def SetArchFlags(compiler):
if compiler.target.arch == 'x86_64':
compiler.defines += ['WIN64']
SdkHelpers = builder.Eval('hl2sdk-manifests/SdkHelpers.ambuild', {
'Project': 'sourcemod'
})
class SMConfig(object):
def __init__(self):
self.sdk_manifests = []
self.sdks = {}
self.sdk_targets = []
self.binaries = []
self.spvm = []
self.extensions = []
@@ -105,12 +48,14 @@ class SMConfig(object):
self.mms_root = None
self.mysql_root = {}
self.spcomp = None
self.spcomp_bins = None
self.spcomp_bins = []
self.smx_files = {}
self.versionlib = None
self.all_targets = []
self.target_archs = set()
self.enable_asan = getattr(builder.options, 'enable_asan', False)
self.asan_libs = {}
self.libsafetyhook = {}
if builder.options.targets:
target_archs = builder.options.targets.split(',')
@@ -152,41 +97,38 @@ class SMConfig(object):
import re
with open(os.path.join(builder.sourcePath, 'product.version'), 'r') as fp:
productContents = fp.read()
m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents)
m = re.match(r'(\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 findSdkPath(self, sdk_name):
dir_name = 'hl2sdk-{}'.format(sdk_name)
if builder.options.hl2sdk_root:
sdk_path = os.path.join(builder.options.hl2sdk_root, dir_name)
if os.path.exists(sdk_path):
return sdk_path
return ResolveEnvPath('HL2SDK{}'.format(sdk_name.upper()), dir_name)
def shouldIncludeSdk(self, sdk):
return not sdk.get('source2', False)
def detectSDKs(self):
sdk_list = builder.options.sdks.split(',')
use_none = sdk_list[0] == 'none'
use_all = sdk_list[0] == 'all'
use_present = sdk_list[0] == 'present'
sdk_list = [s for s in builder.options.sdks.split(',') if s]
SdkHelpers.sdk_filter = self.shouldIncludeSdk
SdkHelpers.find_sdk_path = self.findSdkPath
SdkHelpers.findSdks(builder, self.all_targets, sdk_list)
for sdk_name in PossibleSDKs:
sdk = PossibleSDKs[sdk_name]
if sdk.shouldBuild(self.all_targets):
if builder.options.hl2sdk_root:
sdk_path = os.path.join(builder.options.hl2sdk_root, sdk.folder)
else:
sdk_path = ResolveEnvPath(sdk.envvar, sdk.folder)
if sdk_path is None or not os.path.isdir(sdk_path):
if use_all or sdk_name in sdk_list:
raise Exception('Could not find a valid path for {0}'.format(sdk.envvar))
continue
if use_all or use_present or sdk_name in sdk_list:
sdk.path = Normalize(sdk_path)
self.sdks[sdk_name] = sdk
if len(self.sdks) < 1 and len(sdk_list) and not use_none:
raise Exception('No applicable SDKs were found, nothing to do')
self.sdks = SdkHelpers.sdks
self.sdk_manifests = SdkHelpers.sdk_manifests
self.sdk_targets = SdkHelpers.sdk_targets
if builder.options.mms_path:
self.mms_root = builder.options.mms_path
else:
self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10')
self.mms_root = ResolveEnvPath('MMSOURCE112', 'mmsource-1.12')
if not self.mms_root:
self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'metamod-source')
if not self.mms_root:
@@ -224,7 +166,14 @@ class SMConfig(object):
def configure(self):
builder.AddConfigureFile('pushbuild.txt')
if not set(self.target_archs).issubset(['x86', 'x86_64']):
allowed_archs = ['x86_64']
if builder.host.platform == 'mac':
if getattr(builder.options, 'scripting_only', False):
allowed_archs += ['arm64']
else:
allowed_archs += ['x86']
if not set(self.target_archs).issubset(allowed_archs):
raise Exception('Unknown target architecture: {0}'.format(self.target_archs))
for cxx in self.all_targets:
@@ -232,14 +181,14 @@ class SMConfig(object):
def configure_cxx(self, cxx):
if cxx.family == 'msvc':
if cxx.version < 1900:
raise Exception('Only MSVC 2015 and later are supported, c++14 support is required.')
if cxx.family == 'gcc':
if cxx.version < 'gcc-4.9':
raise Exception('Only GCC versions 4.9 or greater are supported, c++14 support is required.')
if cxx.family == 'clang':
if cxx.version < 'clang-3.4':
raise Exception('Only clang versions 3.4 or greater are supported, c++14 support is required.')
if cxx.version < 1914 and builder.options.generator != 'vs':
raise Exception(f'Only MSVC 2017 15.7 and later are supported, full C++17 support is required. ({str(cxx.version)} < 1914)')
elif cxx.family == 'gcc':
if cxx.version < 'gcc-9':
raise Exception('Only GCC versions 9 or later are supported, full C++17 support is required.')
elif cxx.family == 'clang':
if cxx.version < 'clang-5':
raise Exception('Only clang versions 5 or later are supported, full C++17 support is required.')
if cxx.like('gcc'):
self.configure_gcc(cxx)
@@ -294,19 +243,18 @@ class SMConfig(object):
'-Wno-unused',
'-Wno-switch',
'-Wno-array-bounds',
'-msse',
'-fvisibility=hidden',
]
if cxx.target.arch in ['x86', 'x86_64']:
cxx.cflags += ['-msse']
if cxx.version == 'apple-clang-6.0' or cxx.version == 'clang-3.4':
cxx.cxxflags += ['-std=c++1y']
else:
cxx.cxxflags += ['-std=c++14']
cxx.cxxflags += ['-std=c++17']
cxx.cxxflags += [
'-fno-threadsafe-statics',
'-Wno-non-virtual-dtor',
'-Wno-overloaded-virtual',
'-Wno-register',
'-fvisibility-inlines-hidden',
]
@@ -336,6 +284,11 @@ class SMConfig(object):
cxx.cxxflags += ['-Wno-deprecated']
cxx.cflags += ['-Wno-sometimes-uninitialized']
if self.enable_asan:
if not have_clang:
raise Exception('--enable-asan only supported when using Clang')
self.configure_asan(cxx)
# Work around SDK warnings.
if cxx.version >= 'clang-10.0' or cxx.version >= 'apple-clang-12.0':
cxx.cflags += [
@@ -348,12 +301,18 @@ class SMConfig(object):
cxx.cflags += ['-Wno-maybe-uninitialized']
if builder.options.opt == '1':
cxx.cflags += ['-O3']
if self.enable_asan:
cxx.cflags += ['-O1']
else:
cxx.cflags += ['-O3']
# Don't omit the frame pointer.
cxx.cflags += ['-fno-omit-frame-pointer']
def configure_msvc(self, cxx):
if self.enable_asan:
raise Exception('--enable-asan only supported when using Clang')
if builder.options.debug == '1':
cxx.cflags += ['/MTd']
cxx.linkflags += ['/NODEFAULTLIB:libcmt']
@@ -372,6 +331,7 @@ class SMConfig(object):
'/EHsc',
'/GR-',
'/TP',
'/std:c++17',
]
cxx.linkflags += [
'kernel32.lib',
@@ -399,8 +359,31 @@ class SMConfig(object):
# Don't omit the frame pointer.
cxx.cflags += ['/Oy-']
def configure_asan(self, cxx):
if cxx.target.platform != 'linux':
raise Exception('--enable-asan only supported on Linux')
cxx.cflags += ['-fsanitize=address']
cxx.linkflags += ['-fsanitize=address']
if cxx.target.arch == 'x86':
libclang_rt = 'libclang_rt.asan-i386.so'
else:
libclang_rt = 'libclang_rt.asan-x86_64.so'
try:
argv = cxx.cxx_argv + ['--print-file-name', libclang_rt]
output = subprocess.check_output(argv)
output = output.decode('utf-8')
output = output.strip()
except:
raise Exception('Could not find {}'.format(libclang_rt))
print('ASAN library for {}: {}'.format(cxx.target.arch, output))
print('You will need to LD_PRELOAD this into srcds.')
self.asan_libs[cxx.target.arch] = os.path.dirname(output)
def configure_linux(self, cxx):
cxx.defines += ['_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
cxx.defines += ['LINUX', '_LINUX', 'POSIX', '_FILE_OFFSET_BITS=64']
cxx.linkflags += ['-lm']
if cxx.family == 'gcc':
cxx.linkflags += ['-static-libgcc']
@@ -410,9 +393,9 @@ class SMConfig(object):
def configure_mac(self, cxx):
cxx.defines += ['OSX', '_OSX', 'POSIX', 'KE_ABSOLUTELY_NO_STL']
cxx.cflags += ['-mmacosx-version-min=10.7']
cxx.cflags += ['-mmacosx-version-min=10.15']
cxx.linkflags += [
'-mmacosx-version-min=10.7',
'-mmacosx-version-min=10.15',
'-stdlib=libc++',
'-lc++',
]
@@ -447,7 +430,7 @@ class SMConfig(object):
'-current_version', self.productVersion
]
if self.use_auto_versioning():
binary.compiler.linkflags += [self.versionlib[binary.compiler.target.arch]]
binary.compiler.postlink += [self.versionlib[binary.compiler.target.arch]]
binary.compiler.sourcedeps += SM.generated_headers
return binary
@@ -456,6 +439,14 @@ class SMConfig(object):
self.AddVersioning(binary)
if binary.compiler.like('msvc'):
binary.compiler.linkflags += ['/SUBSYSTEM:WINDOWS']
self.AddCxxCompat(binary)
# Dumb clang behavior means we have to manually find libclang_rt.
if self.enable_asan:
binary.compiler.linkflags += [
'-shared-libsan',
'-Wl,-rpath={}'.format(self.asan_libs[binary.compiler.target.arch]),
]
return binary
def ProgramBuilder(self, compiler, name):
@@ -463,6 +454,8 @@ class SMConfig(object):
self.AddVersioning(binary)
if '-static-libgcc' in binary.compiler.linkflags:
binary.compiler.linkflags.remove('-static-libgcc')
if self.enable_asan:
binary.compiler.linkflags.append('-static-libsan')
if '-lgcc_eh' in binary.compiler.linkflags:
binary.compiler.linkflags.remove('-lgcc_eh')
if binary.compiler.like('gcc'):
@@ -506,6 +499,12 @@ class SMConfig(object):
self.ConfigureForExtension(context, binary.compiler)
return binary
def AddCxxCompat(self, binary):
if binary.compiler.target.platform == 'linux':
binary.sources += [
os.path.join(builder.sourcePath, 'public', 'amtl', 'compat', 'stdcxx.cpp'),
]
def ConfigureForHL2(self, context, binary, sdk):
compiler = binary.compiler
SetArchFlags(compiler)
@@ -515,137 +514,24 @@ class SMConfig(object):
os.path.join(self.mms_root, 'core', 'sourcehook'),
]
defines = ['SE_' + PossibleSDKs[i].define + '=' + PossibleSDKs[i].code for i in PossibleSDKs]
compiler.defines += defines
for other_sdk in self.sdk_manifests:
compiler.defines += ['SE_{}={}'.format(other_sdk['define'], other_sdk['code'])]
paths = [
['public'],
['public', 'engine'],
['public', 'mathlib'],
['public', 'vstdlib'],
['public', 'tier0'],
['public', 'tier1']
]
if sdk.name == 'episode1' or sdk.name == 'darkm':
paths.append(['public', 'dlls'])
paths.append(['game_shared'])
else:
paths.append(['public', 'game', 'server'])
paths.append(['public', 'toolframework'])
paths.append(['game', 'shared'])
paths.append(['common'])
compiler.defines += ['SOURCE_ENGINE=' + sdk.code]
if sdk.name in ['sdk2013', 'bms'] and compiler.like('gcc'):
# The 2013 SDK already has these in public/tier0/basetypes.h
compiler.defines.remove('stricmp=strcasecmp')
compiler.defines.remove('_stricmp=strcasecmp')
compiler.defines.remove('_snprintf=snprintf')
compiler.defines.remove('_vsnprintf=vsnprintf')
if compiler.like('msvc'):
compiler.defines += ['COMPILER_MSVC']
if compiler.target.arch == 'x86':
compiler.defines += ['COMPILER_MSVC32']
elif compiler.target.arch == 'x86_64':
compiler.defines += ['COMPILER_MSVC64']
compiler.linkflags += ['legacy_stdio_definitions.lib']
else:
compiler.defines += ['COMPILER_GCC']
if compiler.target.arch == 'x86_64':
compiler.defines += ['X64BITS', 'PLATFORM_64BITS']
# For everything after Swarm, this needs to be defined for entity networking
# to work properly with sendprop value changes.
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
compiler.defines += ['NETWORK_VARS_ENABLED']
if sdk.name in ['css', 'hl2dm', 'dods', 'sdk2013', 'bms', 'tf2', 'l4d', 'nucleardawn', 'l4d2']:
if compiler.target.platform in ['linux', 'mac']:
compiler.defines += ['NO_HOOK_MALLOC', 'NO_MALLOC_OVERRIDE']
if compiler.target.platform == 'linux':
if sdk.name in ['csgo', 'blade']:
compiler.linkflags.remove('-static-libstdc++')
compiler.defines += ['_GLIBCXX_USE_CXX11_ABI=0']
for path in paths:
compiler.cxxincludes += [os.path.join(sdk.path, *path)]
if compiler.target.platform == 'linux':
if sdk.name == 'episode1':
lib_folder = os.path.join(sdk.path, 'linux_sdk')
elif sdk.name in ['sdk2013', 'bms']:
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'linux32')
elif compiler.target.arch == 'x86_64':
lib_folder = os.path.join(sdk.path, 'lib', 'linux64')
else:
lib_folder = os.path.join(sdk.path, 'lib', 'linux')
elif compiler.target.platform == 'mac':
if sdk.name in ['sdk2013', 'bms']:
lib_folder = os.path.join(sdk.path, 'lib', 'public', 'osx32')
elif compiler.target.arch == 'x86_64':
lib_folder = os.path.join(sdk.path, 'lib', 'osx64')
else:
lib_folder = os.path.join(sdk.path, 'lib', 'mac')
if compiler.target.platform in ['linux', 'mac']:
if sdk.name in ['sdk2013', 'bms'] or compiler.target.arch == 'x86_64':
compiler.postlink += [
os.path.join(lib_folder, 'tier1.a'),
os.path.join(lib_folder, 'mathlib.a')
]
else:
compiler.postlink += [
os.path.join(lib_folder, 'tier1_i486.a'),
os.path.join(lib_folder, 'mathlib_i486.a')
]
if sdk.name in ['blade', 'insurgency', 'doi', 'csgo']:
if compiler.target.arch == 'x86_64':
compiler.postlink += [os.path.join(lib_folder, 'interfaces.a')]
else:
compiler.postlink += [os.path.join(lib_folder, 'interfaces_i486.a')]
dynamic_libs = []
if compiler.target.platform == 'linux':
if sdk.name in ['css', 'hl2dm', 'dods', 'tf2', 'sdk2013', 'bms', 'nucleardawn', 'l4d2', 'insurgency', 'doi']:
dynamic_libs = ['libtier0_srv.so', 'libvstdlib_srv.so']
elif compiler.target.arch == 'x86_64' and sdk.name in ['csgo', 'blade']:
dynamic_libs = ['libtier0_client.so', 'libvstdlib_client.so']
elif sdk.name in ['l4d', 'blade', 'insurgency', 'doi', 'csgo']:
dynamic_libs = ['libtier0.so', 'libvstdlib.so']
else:
dynamic_libs = ['tier0_i486.so', 'vstdlib_i486.so']
elif compiler.target.platform == 'mac':
compiler.linkflags.append('-liconv')
dynamic_libs = ['libtier0.dylib', 'libvstdlib.dylib']
elif compiler.target.platform == 'windows':
libs = ['tier0', 'tier1', 'vstdlib', 'mathlib']
if sdk.name in ['swarm', 'blade', 'insurgency', 'doi', 'csgo']:
libs.append('interfaces')
for lib in libs:
if compiler.target.arch == 'x86':
lib_path = os.path.join(sdk.path, 'lib', 'public', lib) + '.lib'
elif compiler.target.arch == 'x86_64':
lib_path = os.path.join(sdk.path, 'lib', 'public', 'win64', lib) + '.lib'
compiler.linkflags.append(lib_path)
for library in dynamic_libs:
source_path = os.path.join(lib_folder, library)
output_path = os.path.join(binary.localFolder, library)
# Ensure the output path exists.
context.AddFolder(binary.localFolder)
output = context.AddSymlink(source_path, output_path)
compiler.weaklinkdeps += [output]
compiler.linkflags[0:0] = [library]
SdkHelpers.configureCxx(context, binary, sdk)
return binary
def AddCDetour(self, binary):
public_path = os.path.join(builder.sourcePath, 'public')
binary.sources += [ os.path.join(public_path, 'CDetour', 'detours.cpp') ]
binary.compiler.cxxincludes += [ os.path.join(public_path, 'safetyhook', 'include') ]
for task in self.libsafetyhook:
if task.target.arch == binary.compiler.target.arch:
binary.compiler.linkflags += [task.binary]
return
raise Exception('No suitable build of safetyhook was found.')
def HL2Library(self, context, compiler, name, sdk):
binary = self.Library(context, compiler, name)
self.ConfigureForExtension(context, binary.compiler)
@@ -653,13 +539,15 @@ class SMConfig(object):
def HL2Config(self, project, context, compiler, name, sdk):
binary = project.Configure(compiler, name,
'{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch))
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
self.AddCxxCompat(binary)
self.AddVersioning(binary)
return self.ConfigureForHL2(context, binary, sdk)
def HL2ExtConfig(self, project, context, compiler, name, sdk):
binary = project.Configure(compiler, name,
'{0} - {1} {2}'.format(self.tag, sdk.name, compiler.target.arch))
'{0} - {1} {2}'.format(self.tag, sdk['name'], compiler.target.arch))
self.AddCxxCompat(binary)
self.AddVersioning(binary)
self.ConfigureForHL2(context, binary, sdk)
self.ConfigureForExtension(context, binary.compiler)
@@ -692,7 +580,19 @@ if SM.use_auto_versioning():
{ 'SM': SM }
)
class SafetyHookShim(object):
def __init__(self):
self.all_targets = {}
self.libsafetyhook = {}
SafetyHook = SafetyHookShim()
SafetyHook.all_targets = SM.all_targets
builder.Build('public/safetyhook/AMBuilder', {'SafetyHook': SafetyHook })
SM.libsafetyhook = SafetyHook.libsafetyhook
class SPRoot(object):
def __init__(self):
self.generated_headers = SM.generated_headers
# SourcePawn's build scripts are always one-offs, and attach the current target
# to the builder, so we have to provide a shim to our StaticLibrary() method.
def StaticLibrary(self, builder, name):
@@ -720,11 +620,24 @@ SP = builder.Build('sourcepawn/AMBuildScript', {
'external_amtl': os.path.join(builder.sourcePath, 'public', 'amtl'),
'external_build': SP_build_parts,
})
if len(SP.spcomp) > 1:
SM.spcomp = SP.spcomp['x86']
else:
SM.spcomp = SP.spcomp[list(SP.spcomp.keys())[0]]
SM.spcomp_bins = list(SP.spcomp.values())
def IsBetterDefaultSpcomp(spcomp, other):
if other is None:
return True
if spcomp.target.arch == 'universal':
return True
if other.target.arch == 'universal':
return False
return spcomp.target.arch == 'x86'
for spcomp in SP.spcomp:
if IsBetterDefaultSpcomp(spcomp, SM.spcomp):
SM.spcomp = spcomp
SM.spcomp_bins.append(spcomp)
# If we have a universal binary, ignore all other spcomps.
if SM.spcomp.target.arch == 'universal':
SM.spcomp_bins = [SM.spcomp]
if not getattr(builder.options, 'scripting_only', False):
for cxx in SM.all_targets:
@@ -746,6 +659,7 @@ else:
'extensions/clientprefs/AMBuilder',
'extensions/curl/AMBuilder',
'extensions/cstrike/AMBuilder',
'extensions/dhooks/AMBuilder',
'extensions/geoip/AMBuilder',
'extensions/mysql/AMBuilder',
'extensions/pgsql/AMBuilder',
+1
View File
@@ -16,6 +16,7 @@ Development
- [SourcePawn scripting](https://wiki.alliedmods.net/Category:SourceMod_Scripting): SourcePawn examples and introduction to the language
- [SourceMod plugin API](https://sm.alliedmods.net/new-api): Online SourceMod plugin API reference generated from the include files
- [SourceMod extension development](https://wiki.alliedmods.net/Category:SourceMod_Development): C++ examples and introduction to various extension interfaces
- [Translation project](https://github.com/orgs/alliedmodders/projects/1): Help [translate SourceMod](https://wiki.alliedmods.net/Translations_(SourceMod_Scripting)) into your language
Contact
-------
+2 -1
View File
@@ -3,6 +3,7 @@ image: Visual Studio 2015
clone_folder: c:/projects/sourcemod
clone_depth: 1
install:
- cmd: set PATH=C:\Python38;C:\Python38\Scripts;%PATH%
- cmd: git submodule update --init --recursive
- cmd: git pull --recurse-submodules
- cmd: cd ..
@@ -12,5 +13,5 @@ build_script:
- cmd: call "%VS140COMNTOOLS%/vsvars32.bat"
- cmd: mkdir build
- cmd: cd build
- cmd: c:\python27\python.exe ../configure.py --enable-optimize --no-mysql --sdks=episode1,css,tf2,l4d2,csgo
- cmd: python.exe ../configure.py --enable-optimize --no-mysql --sdks=episode1,css,tf2,l4d2,csgo
- cmd: ambuild
+2 -3
View File
@@ -86,9 +86,6 @@ public:
const char *gamesuffix;
/* Data */
ServerGlobals *serverGlobals;
void * serverFactory;
void * engineFactory;
void * matchmakingDSFactory;
SMGlobalClass * listeners;
// ConVar functions.
@@ -115,6 +112,8 @@ public:
virtual void ConsolePrint(const char *fmt, ...) = 0;
virtual void ConsolePrintVa(const char *fmt, va_list ap) = 0;
virtual void FormatSourceBinaryName(const char *basename, char *buffer, size_t maxlength) = 0;
// Game engine helper functions.
virtual bool IsClientConVarQueryingSupported() = 0;
virtual int QueryClientConVar(int client, const char *cvar) = 0;
+2
View File
@@ -44,6 +44,7 @@ public:
virtual char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) = 0;
virtual bool EndOfFile(FileHandle_t file) = 0;
virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0;
virtual unsigned int Size(FileHandle_t file) = 0;
virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0;
virtual int Read(void* pOutput, int size, FileHandle_t file) = 0;
virtual int Write(void const* pInput, int size, FileHandle_t file) = 0;
@@ -56,6 +57,7 @@ public:
virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
virtual int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) = 0;
};
} // namespace SourceMod
+3
View File
@@ -73,6 +73,9 @@ struct sm_logic_t
void (*FreeCellArray)(ICellArray *arr);
void * (*FromPseudoAddress)(uint32_t pseudoAddr);
uint32_t (*ToPseudoAddress)(void *addr);
void (*SetEntityLumpWritable)(bool writable);
bool (*ParseEntityLumpString)(const char *entityString, int &status, size_t &position);
const char * (*GetEntityLumpString)();
IScriptManager *scripts;
IShareSys *sharesys;
IExtensionSys *extsys;
-18
View File
@@ -53,24 +53,6 @@
* passwords to work, for security reasons.
*/
"PassInfoVar" "_password"
/**
* Specifies the sound that gets played when an item is selected from a menu.
*/
"MenuItemSound" "buttons/button14.wav"
/**
* Specifies the sound that gets played when an "Exit" button is selected
* from a menu.
*/
"MenuExitSound" "buttons/combine_button7.wav"
/**
* Specifies the sound that gets played when an "Exit Back" button is selected
* from a menu. This is the special "Back" button that is intended to roll back
* to a previous menu.
*/
"MenuExitBackSound" "buttons/combine_button7.wav"
/**
* Enables or disables whether SourceMod reads a client's cl_language cvar to set
+35 -1
View File
@@ -1,4 +1,38 @@
"Languages"
{
"en" "English"
"ar" "Arabic" // Arabic
"bg" "Bulgarian" // Bulgarian
"chi" "SChinese" // Chinese (Simplified)
"cze" "Czech" // Czech
"da" "Danish" // Danish
"de" "German" // German
"el" "Greek" // Greek
"en" "English" // English
"es" "Spanish" // Spanish
"fi" "Finnish" // Finnish
"fr" "French" // French
"he" "Hebrew" // Hebrew
"hu" "Hungarian" // Hungarian
"it" "Italian" // Italian
"jp" "Japanese" // Japanese
"ko" "Korean" // Korean
"ko" "KoreanA" // Korean (https://bugs.alliedmods.net/show_bug.cgi?id=4667)
"las" "LatAm" // Latin American Spanish
"lt" "Lithuanian" // Lithuanian
"lv" "Latvian" // Latvian
"nl" "Dutch" // Dutch
"no" "Norwegian" // Norwegian
"pl" "Polish" // Polish
"pt" "Brazilian" // Brazilian Portuguese
"pt_p" "Portuguese" // Portuguese
"ro" "Romanian" // Romanian
"ru" "Russian" // Russian
"sk" "Slovak" // Slovak
"sv" "Swedish" // Swedish
"th" "Thai" // Thai
"tr" "Turkish" // Turkish
"ua" "Ukrainian" // Ukrainian
"vi" "Vietnamese" // Vietnamese
"zho" "TChinese" // Chinese (Traditional)
}
+19 -17
View File
@@ -1,30 +1,30 @@
# vim: set ts=2 sw=2 tw=99 noet:
import sys
try:
from ambuild2 import run, util
from ambuild2 import run, util
except:
try:
import ambuild
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
except:
sys.stderr.write('AMBuild must be installed to build this project.\n')
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
sys.exit(1)
try:
import ambuild
sys.stderr.write('It looks like you have AMBuild 1 installed, but this project uses AMBuild 2.\n')
sys.stderr.write('Upgrade to the latest version of AMBuild to continue.\n')
except:
sys.stderr.write('AMBuild must be installed to build this project.\n')
sys.stderr.write('http://www.alliedmods.net/ambuild\n')
sys.exit(1)
# Hack to show a decent upgrade message, which wasn't done until 2.2.
ambuild_version = getattr(run, 'CURRENT_API', '2.1')
if ambuild_version.startswith('2.1'):
sys.stderr.write("AMBuild 2.2 or higher is required; please update\n")
sys.exit(1)
sys.stderr.write("AMBuild 2.2 or higher is required; please update\n")
sys.exit(1)
parser = run.BuildParser(sourcePath=sys.path[0], api='2.2')
parser.options.add_argument('--hl2sdk-root', type=str, dest='hl2sdk_root', default=None,
help='Root search folder for HL2SDKs')
help='Root search folder for HL2SDKs')
parser.options.add_argument('--mysql-path', type=str, dest='mysql_path', default=None,
help='Path to MySQL 5')
help='Path to MySQL 5')
parser.options.add_argument('--mysql64-path', type=str, dest='mysql64_path', default=None,
help='Path to 64-bit MySQL 5')
help='Path to 64-bit MySQL 5')
parser.options.add_argument('--mms-path', type=str, dest='mms_path', default=None,
help='Path to Metamod:Source')
parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug',
@@ -37,11 +37,13 @@ parser.options.add_argument('-s', '--sdks', default='present', dest='sdks',
help='Build against specified SDKs; valid args are "none", "all", "present",'
' or comma-delimited list of engine names')
parser.options.add_argument('--breakpad-dump', action='store_true', dest='breakpad_dump',
default=False, help='Dump and upload breakpad symbols')
default=False, help='Dump and upload breakpad symbols')
parser.options.add_argument('--disable-auto-versioning', action='store_true', dest='disable_auto_versioning',
default=False, help='Disable the auto versioning script')
parser.options.add_argument('--targets', type=str, dest='targets', default=None,
help="Override the target architecture (use commas to separate multiple targets).")
help="Override the target architecture (use commas to separate multiple targets).")
parser.options.add_argument('--scripting-only', action='store_true', dest='scripting_only', default=False,
help="Only build and package the files required for scripting in SourcePawn.")
help="Only build and package the files required for scripting in SourcePawn.")
parser.options.add_argument('--enable-asan', action='store_true', dest='enable_asan',
default=False, help='Enable ASAN (clang only)')
parser.Configure()
+114 -140
View File
@@ -4,164 +4,138 @@ import os
project = builder.LibraryProject('sourcemod')
project.sources += [
'MenuStyle_Valve.cpp',
'logic_bridge.cpp',
'smn_entities.cpp',
'sm_stringutil.cpp',
'MenuVoting.cpp',
'smn_events.cpp',
'frame_hooks.cpp',
'smn_nextmap.cpp',
'sourcemm_api.cpp',
'ChatTriggers.cpp',
'smn_player.cpp',
'sourcemod.cpp',
'concmd_cleaner.cpp',
'HalfLife2.cpp',
'NextMap.cpp',
'ConCmdManager.cpp',
'ConVarManager.cpp',
'ConsoleDetours.cpp',
'CoreConfig.cpp',
'EventManager.cpp',
'GameHooks.cpp',
'HalfLife2.cpp',
'Logger.cpp',
'MenuManager.cpp',
'MenuStyle_Base.cpp',
'MenuStyle_Radio.cpp',
'MenuStyle_Valve.cpp',
'MenuVoting.cpp',
'NextMap.cpp',
'PlayerManager.cpp',
'TimerSys.cpp',
'UserMessages.cpp',
'concmd_cleaner.cpp',
'frame_hooks.cpp',
'logic_bridge.cpp',
'pb_handle.cpp',
'sm_autonatives.cpp',
'sm_stringutil.cpp',
'smn_commandline.cpp',
'smn_console.cpp',
'smn_entities.cpp',
'smn_events.cpp',
'CoreConfig.cpp',
'Logger.cpp',
'smn_halflife.cpp',
'smn_console.cpp',
'UserMessages.cpp',
'MenuManager.cpp',
'smn_hudtext.cpp',
'smn_keyvalues.cpp',
'smn_nextmap.cpp',
'smn_player.cpp',
'smn_usermsgs.cpp',
'MenuStyle_Base.cpp',
'smn_keyvalues.cpp',
'smn_vector.cpp',
'sourcemm_api.cpp',
'sourcemod.cpp',
'EventManager.cpp',
'MenuStyle_Radio.cpp',
'sm_autonatives.cpp',
'ConsoleDetours.cpp',
'smn_commandline.cpp',
'GameHooks.cpp',
]
for sdk_name in SM.sdks:
sdk = SM.sdks[sdk_name]
for cxx in builder.targets:
if not cxx.target.arch in sdk.platformSpec[cxx.target.platform]:
continue
# SDK name to shipping gamedir
pb_gamedir_map = {
'csgo': 'csgo',
'blade': 'berimbau',
'mcv': 'vietnam',
}
binary_name = 'sourcemod.' + sdk.ext
# SDK name to source code gamedir
pb_gamesrcdir_map = {
'csgo': 'cstrike15',
'blade': 'berimbau',
'mcv': 'vietnam',
}
binary = SM.HL2Config(project, builder, cxx, binary_name, sdk)
SM.ConfigureForExtension(builder, binary.compiler)
for sdk_target in SM.sdk_targets:
sdk = sdk_target.sdk
cxx = sdk_target.cxx
compiler = binary.compiler
binary_name = 'sourcemod.' + sdk['extension']
needs_protobuf = sdk['name'] in ['csgo', 'blade', 'mcv']
binary = SM.HL2Config(project, builder, cxx, binary_name, sdk)
SM.ConfigureForExtension(builder, binary.compiler)
compiler = binary.compiler
compiler.cxxincludes += [
builder.sourcePath
]
if needs_protobuf:
compiler.cxxincludes += [
builder.sourcePath
os.path.join(sdk['path'], 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk['path'], 'public', 'engine', 'protobuf'),
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf')
]
if compiler.like('msvc'):
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
if cxx.target.platform == 'linux':
compiler.postlink += ['-lpthread', '-lrt']
if needs_protobuf:
if compiler.target.platform == 'linux':
if compiler.target.arch == 'x86':
lib_path = os.path.join(sdk['path'], 'lib', 'linux32', 'release', 'libprotobuf.a')
elif compiler.target.arch == 'x86_64':
lib_path = os.path.join(sdk['path'], 'lib', 'linux64', 'release', 'libprotobuf.a')
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
elif compiler.target.platform == 'mac':
if compiler.target.arch == 'x86':
lib_path = os.path.join(sdk['path'], 'lib', 'osx32', 'release', 'libprotobuf.a')
elif compiler.target.arch == 'x86_64':
lib_path = os.path.join(sdk['path'], 'lib', 'osx64', 'release', 'libprotobuf.a')
elif compiler.target.platform == 'windows':
msvc_ver = compiler.version
vs_year = ''
platform = ''
if compiler.target.arch == 'x86':
platform = 'win32'
elif compiler.target.arch == 'x86_64':
platform = 'win64'
if 1900 <= msvc_ver < 2000:
vs_year = '2015'
else:
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
if 'DEBUG' in compiler.defines:
lib_path = os.path.join(sdk['path'], 'lib', platform, 'debug', 'vs' + vs_year, 'libprotobuf.lib')
else:
lib_path = os.path.join(sdk['path'], 'lib', platform, 'release', 'vs' + vs_year, 'libprotobuf.lib')
compiler.linkflags.insert(0, lib_path)
if needs_protobuf:
binary.sources += ['smn_protobuf.cpp']
else:
binary.sources += ['smn_bitbuffer.cpp']
if sdk['name'] != 'blade':
binary.sources += [
'vprof_tool.cpp',
]
pb_includes = []
if sdk.name == 'csgo':
pb_includes = [
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
]
elif sdk.name == 'blade':
pb_includes = [
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf')
]
compiler.cxxincludes += pb_includes
if compiler.like('msvc'):
compiler.defines += ['_ALLOW_KEYWORD_MACROS']
if cxx.target.platform == 'linux':
compiler.postlink += ['-lpthread', '-lrt']
if sdk.name in ['csgo', 'blade']:
if compiler.target.platform == 'linux':
if compiler.target.arch == 'x86':
lib_path = os.path.join(sdk.path, 'lib', 'linux32', 'release', 'libprotobuf.a')
elif compiler.target.arch == 'x86_64':
lib_path = os.path.join(sdk.path, 'lib', 'linux64', 'release', 'libprotobuf.a')
compiler.linkflags += ['-Wl,--exclude-libs=libprotobuf.a']
elif compiler.target.platform == 'mac':
if compiler.target.arch == 'x86':
lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf-libcxx.a')
elif compiler.target.arch == 'x86_64':
lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf-libcxx.a')
elif compiler.target.platform == 'windows':
msvc_ver = compiler.version
vs_year = ''
if 1900 <= msvc_ver < 2000:
vs_year = '2015'
else:
raise Exception('Cannot find libprotobuf for MSVC version "' + str(compiler.version) + '"')
if 'DEBUG' in compiler.defines:
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'debug', 'vs' + vs_year, 'libprotobuf.lib')
else:
lib_path = os.path.join(sdk.path, 'lib', 'win32', 'release', 'vs' + vs_year, 'libprotobuf.lib')
compiler.linkflags.insert(0, lib_path)
if sdk.name in ['csgo', 'blade']:
binary.sources += ['smn_protobuf.cpp']
else:
binary.sources += ['smn_bitbuffer.cpp']
if sdk.name != 'blade':
if needs_protobuf:
binary.sources += [
os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessages.pb.cc'),
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_usermessage_helpers.cpp'),
]
if sdk['name'] == 'mcv':
binary.sources += [
'vprof_tool.cpp',
]
pb_sources = []
if sdk.name == 'csgo':
pb_sources = [
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf', 'cstrike15_usermessage_helpers.cpp'),
]
elif sdk.name == 'blade':
pb_sources = [
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf', 'berimbau_usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'berimbau', 'protobuf', 'berimbau_usermessage_helpers.cpp'),
]
if len(pb_sources):
binary.sources += pb_sources
binary.compiler.cxxdefines += ['PROTOBUF_ENABLE']
if cxx.target.platform == 'mac' and sdk.name in ['csgo']:
# We need a proxy library since the game uses libstdc++.
pb_binary = SM.HL2Library(builder, cxx, 'pbproxy.' + sdk.ext, sdk)
pb_binary.sources += pb_sources
pb_binary.sources += ['pb_proxy.cpp']
pb_binary.compiler.cxxincludes += pb_includes
# Switch from libc++ to libstdc++.
pb_binary.compiler.cxxflags.remove('-stdlib=libc++')
pb_binary.compiler.linkflags.remove('-lc++')
pb_binary.compiler.linkflags.remove('-stdlib=libc++')
pb_binary.compiler.cxxflags.append('-stdlib=libstdc++')
pb_binary.compiler.linkflags.append('-lstdc++')
pb_binary.compiler.linkflags.append('-stdlib=libstdc++')
if '-std=c++1y' in pb_binary.compiler.cxxflags:
pb_binary.compiler.cxxflags.remove('-std=c++1y')
elif '-std=c++14' in pb_binary.compiler.cxxflags:
pb_binary.compiler.cxxflags.remove('-std=c++14')
if cxx.target.arch == 'x86':
pb_lib_path = os.path.join(sdk.path, 'lib', 'osx32', 'release', 'libprotobuf.a')
elif cxx.target.arch == 'x86_64':
pb_lib_path = os.path.join(sdk.path, 'lib', 'osx64', 'release', 'libprotobuf.a')
pb_binary.compiler.linkflags.append(pb_lib_path)
SM.binaries += [builder.Add(pb_binary)]
binary.compiler.cxxdefines += [
'PROTOBUF_PROXY_ENABLE',
'PROTOBUF_PROXY_BINARY_NAME="pbproxy.{}"'.format(sdk.ext),
os.path.join(sdk['path'], 'public', 'game', 'shared', pb_gamedir_map[sdk['name']], 'protobuf', pb_gamesrcdir_map[sdk['name']] + '_gcmessages.pb.cc'),
os.path.join(sdk['path'], 'public', 'engine', 'protobuf', 'engine_gcmessages.pb.cc'),
]
SM.binaries += builder.Add(project)
+20
View File
@@ -461,3 +461,23 @@ bool ChatTriggers::WasFloodedMessage()
{
return m_bWasFloodedMessage;
}
const char *ChatTriggers::GetPublicChatTrigger()
{
if (!m_PubTrigger.length())
{
return NULL;
}
return m_PubTrigger.c_str();
}
const char *ChatTriggers::GetPrivateChatTrigger()
{
if (!m_PrivTrigger.length())
{
return NULL;
}
return m_PrivTrigger.c_str();
}
+2
View File
@@ -63,6 +63,8 @@ public:
unsigned int SetReplyTo(unsigned int reply);
bool IsChatTrigger();
bool WasFloodedMessage();
const char *GetPublicChatTrigger();
const char *GetPrivateChatTrigger();
private:
enum ChatTriggerType {
ChatTrigger_Public,
+1 -1
View File
@@ -115,7 +115,7 @@ void GameHooks::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *pPla
const char *cvarName, const char *cvarValue){
int client = IndexOfEdict(pPlayer);
# if SOURCE_ENGINE == SE_CSGO
# if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
if (g_Players.HandleConVarQuery(cookie, client, result, cvarName, cvarValue))
return;
# endif
+76 -26
View File
@@ -47,6 +47,8 @@
#include <cstrike15_usermessages.pb.h>
#elif SOURCE_ENGINE == SE_BLADE
#include <berimbau_usermessages.pb.h>
#elif SOURCE_ENGINE == SE_MCV
#include <vietnam_usermessages.pb.h>
#endif
typedef ICommandLine *(*FakeGetCommandLine)();
@@ -183,7 +185,9 @@ void CHalfLife2::InitLogicalEntData()
|| SOURCE_ENGINE == SE_CSS \
|| SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_BMS \
|| SOURCE_ENGINE == SE_NUCLEARDAWN
|| SOURCE_ENGINE == SE_BLADE \
|| SOURCE_ENGINE == SE_NUCLEARDAWN \
|| SOURCE_ENGINE == SE_PVKII
if (g_SMAPI->GetServerFactory(false)("VSERVERTOOLS003", nullptr))
{
@@ -409,6 +413,17 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname)
return pInfo->sc;
}
ServerClass *CHalfLife2::FindEntityServerClass(CBaseEntity *pEntity)
{
IServerNetworkable* pNetwork = ((IServerUnknown *)pEntity)->GetNetworkable();
if (pNetwork == nullptr)
{
return nullptr;
}
return pNetwork->GetServerClass();
}
DataTableInfo *CHalfLife2::_FindServerClass(const char *classname)
{
DataTableInfo *pInfo = NULL;
@@ -441,20 +456,25 @@ bool CHalfLife2::FindSendPropInfo(const char *classname, const char *offset, sm_
return false;
}
if (!pInfo->lookup.retrieve(offset, info))
{
sm_sendprop_info_t temp_info;
DataTableInfo::SendPropInfo temp;
if (!UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp_info, 0))
if (!pInfo->lookup.retrieve(offset, &temp))
{
bool found = UTIL_FindInSendTable(pInfo->sc->m_pTable, offset, &temp.info, 0);
temp.name = offset;
pInfo->lookup.insert(offset, temp);
if (found)
{
return false;
*info = temp.info;
}
pInfo->lookup.insert(offset, temp_info);
*info = temp_info;
return found;
}
return true;
*info = temp.info;
return info->prop != nullptr;
}
SendProp *CHalfLife2::FindInSendTable(const char *classname, const char *offset)
@@ -488,15 +508,25 @@ bool CHalfLife2::FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatab
m_Maps.add(i, pMap, new DataMapCache());
DataMapCache *cache = i->value;
DataMapCacheInfo temp;
if (!cache->retrieve(offset, pDataTable))
if (!cache->retrieve(offset, &temp))
{
if (!UTIL_FindDataMapInfo(pMap, offset, pDataTable))
return false;
cache->insert(offset, *pDataTable);
bool found = UTIL_FindDataMapInfo(pMap, offset, &temp.info);
temp.name = offset;
cache->insert(offset, temp);
if (found)
{
*pDataTable = temp.info;
}
return found;
}
return true;
*pDataTable = temp.info;
return pDataTable->prop != nullptr;
}
void CHalfLife2::SetEdictStateChanged(edict_t *pEdict, unsigned short offset)
@@ -537,7 +567,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
char buffer[253];
ke::SafeSprintf(buffer, sizeof(buffer), "%s\1\n", msg);
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
CCSUsrMsg_SayText *pMsg;
if ((pMsg = (CCSUsrMsg_SayText *)g_UserMsgs.StartProtobufMessage(m_SayTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@@ -564,7 +594,7 @@ bool CHalfLife2::TextMsg(int client, int dest, const char *msg)
}
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
CCSUsrMsg_TextMsg *pMsg;
if ((pMsg = (CCSUsrMsg_TextMsg *)g_UserMsgs.StartProtobufMessage(m_MsgTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@@ -601,7 +631,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
{
cell_t players[] = {client};
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
CCSUsrMsg_HintText *pMsg;
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, 1, USERMSG_RELIABLE)) == NULL)
{
@@ -631,7 +661,7 @@ bool CHalfLife2::HintTextMsg(int client, const char *msg)
bool CHalfLife2::HintTextMsg(cell_t *players, int count, const char *msg)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
CCSUsrMsg_HintText *pMsg;
if ((pMsg = (CCSUsrMsg_HintText *)g_UserMsgs.StartProtobufMessage(m_HinTextMsg, players, count, USERMSG_RELIABLE)) == NULL)
{
@@ -666,7 +696,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
int count = 0;
cell_t players[] = {client};
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
CCSUsrMsg_VGUIMenu *pMsg;
if ((pMsg = (CCSUsrMsg_VGUIMenu *)g_UserMsgs.StartProtobufMessage(m_VGUIMenu, players, 1, USERMSG_RELIABLE)) == NULL)
{
@@ -691,7 +721,7 @@ bool CHalfLife2::ShowVGUIMenu(int client, const char *name, KeyValues *data, boo
SubKey = data->GetFirstSubKey();
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
pMsg->set_name(name);
pMsg->set_show(show);
@@ -1080,8 +1110,26 @@ int CHalfLife2::ReferenceToIndex(cell_t entRef)
return hndl.GetEntryIndex();
}
else
{
CEntInfo *pInfo = LookupEntity(entRef);
if (!pInfo)
{
return INVALID_EHANDLE_INDEX;
}
IServerUnknown *pUnk = static_cast<IServerUnknown *>(pInfo->m_pEntity);
if (!pUnk)
{
return INVALID_EHANDLE_INDEX;
}
CBaseEntity *pEntity = pUnk->GetBaseEntity();
if (!pEntity)
{
return INVALID_EHANDLE_INDEX;
}
return entRef;
return entRef;
}
}
cell_t CHalfLife2::EntityToBCompatRef(CBaseEntity *pEntity)
@@ -1233,7 +1281,7 @@ bool IsWindowsReservedDeviceName(const char *pMapname)
}
#endif
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK
// This frees memory allocated by the game using the game's CRT on Windows,
// avoiding a crash due to heap corruption (issue #910).
template< class T, class I >
@@ -1338,7 +1386,7 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_
}
#elif SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM \
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_PVKII
static IVEngineServer *engine23 = (IVEngineServer *)(g_SMAPI->GetEngineFactory()("VEngineServer023", nullptr));
if (engine23)
{
@@ -1384,7 +1432,7 @@ bool CHalfLife2::IsMapValid(const char *map)
if (!map || !map[0])
return false;
return FindMap(map) != SMFindMapResult::NotFound;
return FindMap(map) == SMFindMapResult::Found;
}
#if SOURCE_ENGINE < SE_ORANGEBOX
@@ -1525,7 +1573,9 @@ uint64_t CHalfLife2::GetServerSteamId64() const
|| SOURCE_ENGINE == SE_DOI \
|| SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_ALIENSWARM \
|| SOURCE_ENGINE == SE_TF2
|| SOURCE_ENGINE == SE_TF2 \
|| SOURCE_ENGINE == SE_PVKII \
|| SOURCE_ENGINE == SE_MCV
const CSteamID *sid = engine->GetGameServerSteamID();
if (sid)
{
+27 -10
View File
@@ -74,7 +74,7 @@ using namespace SourceMod;
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_INSURGENCY || SOURCE_ENGINE == SE_DOI
#define SOURCE_BIN_PREFIX "lib"
#define SOURCE_BIN_SUFFIX "_srv"
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
#elif SOURCE_ENGINE >= SE_LEFT4DEAD || SOURCE_ENGINE == SE_PVKII
#define SOURCE_BIN_PREFIX "lib"
#define SOURCE_BIN_SUFFIX ""
#else
@@ -89,16 +89,24 @@ using namespace SourceMod;
struct DataTableInfo
{
struct SendPropPolicy
struct SendPropInfo
{
static inline bool matches(const char *name, const sm_sendprop_info_t &info)
static inline bool matches(const char *name, const SendPropInfo &info)
{
return strcmp(name, info.prop->GetName()) == 0;
return strcmp(name, info.name.c_str()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
SendPropInfo()
: name(), info{nullptr, 0}
{
}
std::string name;
sm_sendprop_info_t info;
};
static inline bool matches(const char *name, const DataTableInfo *info)
@@ -116,22 +124,30 @@ struct DataTableInfo
}
ServerClass *sc;
NameHashSet<sm_sendprop_info_t, SendPropPolicy> lookup;
NameHashSet<SendPropInfo> lookup;
};
struct DataMapCachePolicy
struct DataMapCacheInfo
{
static inline bool matches(const char *name, const sm_datatable_info_t &info)
static inline bool matches(const char *name, const DataMapCacheInfo &info)
{
return strcmp(name, info.prop->fieldName) == 0;
return strcmp(name, info.name.c_str()) == 0;
}
static inline uint32_t hash(const detail::CharsAndLength &key)
{
return key.hash();
}
DataMapCacheInfo()
: name(), info{nullptr, 0}
{
}
std::string name;
sm_datatable_info_t info;
};
typedef NameHashSet<sm_datatable_info_t, DataMapCachePolicy> DataMapCache;
typedef NameHashSet<DataMapCacheInfo> DataMapCache;
struct DelayedFakeCliCmd
{
@@ -205,6 +221,7 @@ public: //IGameHelpers
bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info);
datamap_t *GetDataMap(CBaseEntity *pEntity);
ServerClass *FindServerClass(const char *classname);
ServerClass *FindEntityServerClass(CBaseEntity *pEntity);
typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset);
bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable);
void SetEdictStateChanged(edict_t *pEdict, unsigned short offset);
@@ -235,7 +252,7 @@ public: //IGameHelpers
bool IsMapValid(const char *map);
SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax);
SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0);
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS
#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS && SOURCE_ENGINE != SE_MOCK
void FreeUtlVectorUtlString(CUtlVector<CUtlString, CUtlMemoryGlobalMalloc<CUtlString>> &vec);
#endif
bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax);
+29 -26
View File
@@ -38,6 +38,7 @@
#include "sourcemm_api.h"
#include "PlayerManager.h"
#include "MenuStyle_Valve.h"
#include <IGameConfigs.h>
#include "sourcemm_api.h"
#include "logic_bridge.h"
@@ -68,6 +69,29 @@ void MenuManager::OnSourceModAllInitialized()
m_StyleType = handlesys->CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
}
void MenuManager::OnSourceModAllInitialized_Post()
{
const char* pTmp;
pTmp = g_pGameConf->GetKeyValue("MenuItemSound");
if (nullptr != pTmp)
{
m_SelectSound = pTmp;
}
pTmp = g_pGameConf->GetKeyValue("MenuExitSound");
if (nullptr != pTmp)
{
m_ExitSound = pTmp;
}
pTmp = g_pGameConf->GetKeyValue("MenuExitBackSound");
if (nullptr != pTmp)
{
m_ExitBackSound = pTmp;
}
}
void MenuManager::OnSourceModAllShutdown()
{
handlesys->RemoveType(m_MenuType, g_pCoreIdent);
@@ -699,30 +723,9 @@ bool MenuManager::MenuSoundsEnabled()
return (sm_menu_sounds.GetInt() != 0);
}
ConfigResult MenuManager::OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength)
std::string *MenuManager::GetMenuSound(ItemSelection sel)
{
if (strcmp(key, "MenuItemSound") == 0)
{
m_SelectSound.assign(value);
return ConfigResult_Accept;
} else if (strcmp(key, "MenuExitBackSound") == 0) {
m_ExitBackSound.assign(value);
return ConfigResult_Accept;
} else if (strcmp(key, "MenuExitSound") == 0) {
m_ExitSound.assign(value);
return ConfigResult_Accept;
}
return ConfigResult_Ignore;
}
const char *MenuManager::GetMenuSound(ItemSelection sel)
{
const char *sound = NULL;
std::string *sound = nullptr;
switch (sel)
{
@@ -732,7 +735,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
{
if (m_SelectSound.size() > 0)
{
sound = m_SelectSound.c_str();
sound = &m_SelectSound;
}
break;
}
@@ -740,7 +743,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
{
if (m_ExitBackSound.size() > 0)
{
sound = m_ExitBackSound.c_str();
sound = &m_ExitBackSound;
}
break;
}
@@ -748,7 +751,7 @@ const char *MenuManager::GetMenuSound(ItemSelection sel)
{
if (m_ExitSound.size() > 0)
{
sound = m_ExitSound.c_str();
sound = &m_ExitSound;
}
break;
}
+6 -10
View File
@@ -36,8 +36,8 @@
#include <sh_vector.h>
#include <sh_stack.h>
#include <sh_list.h>
#include <sh_string.h>
#include "sm_globals.h"
#include <string>
using namespace SourceMod;
using namespace SourceHook;
@@ -55,12 +55,8 @@ public:
MenuManager();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModAllInitialized_Post();
void OnSourceModAllShutdown();
ConfigResult OnSourceModConfigChanged(const char *key,
const char *value,
ConfigSource source,
char *error,
size_t maxlength);
void OnSourceModLevelChange(const char *mapName);
public: //IMenuManager
virtual const char *GetInterfaceName()
@@ -99,7 +95,7 @@ public:
HandleError ReadStyleHandle(Handle_t handle, IMenuStyle **style);
public:
bool MenuSoundsEnabled();
const char *GetMenuSound(ItemSelection sel);
std::string *GetMenuSound(ItemSelection sel);
protected:
Handle_t CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner);
Handle_t CreateStyleHandle(IMenuStyle *style);
@@ -109,9 +105,9 @@ private:
CVector<IMenuStyle *> m_Styles;
HandleType_t m_StyleType;
HandleType_t m_MenuType;
String m_SelectSound;
String m_ExitBackSound;
String m_ExitSound;
std::string m_SelectSound = "";
std::string m_ExitBackSound = "";
std::string m_ExitSound = "";
};
extern MenuManager g_Menus;
+77 -21
View File
@@ -8,7 +8,7 @@
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@@ -99,7 +99,7 @@ void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool
/* Fire callbacks */
mh->OnMenuCancel(menu, client, reason);
/* Only fire end if there's a valid menu */
if (menu)
{
@@ -214,7 +214,7 @@ void BaseMenuStyle::ProcessWatchList()
}
#if defined MENU_DEBUG
logger->LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
logger->LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
m_WatchList.m_Size,
m_WatchList.m_FirstLink,
m_WatchList.m_FreeNodes,
@@ -302,7 +302,7 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
ItemSelection type = states.slots[key_press].type;
/* Check if we should play a sound about the type */
if (g_Menus.MenuSoundsEnabled() &&
if (g_Menus.MenuSoundsEnabled() &&
(!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
{
CellRecipientFilter filter;
@@ -311,9 +311,9 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
clients[0] = client;
filter.Initialize(clients, 1);
const char *sound = g_Menus.GetMenuSound(type);
std::string *sound = g_Menus.GetMenuSound(type);
if (sound != NULL)
if (nullptr != sound && !sound->empty())
{
edict_t *pEdict = PEntityOfEntIndex(client);
if (pEdict)
@@ -323,23 +323,23 @@ void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
if (pCollideable)
{
const Vector & pos = pCollideable->GetCollisionOrigin();
enginesound->EmitSound(filter,
client,
CHAN_AUTO,
enginesound->EmitSound(filter,
client,
CHAN_AUTO,
#if SOURCE_ENGINE >= SE_PORTAL2
sound,
-1,
sound->c_str(),
-1,
#endif
sound,
VOL_NORM,
ATTN_NORM,
sound->c_str(),
VOL_NORM,
ATTN_NORM,
#if SOURCE_ENGINE >= SE_PORTAL2
0,
0,
#endif
0,
PITCH_NORM,
0,
PITCH_NORM,
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2
|| SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
0,
#endif
&pos);
@@ -604,9 +604,9 @@ bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
return true;
}
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
m_pStyle(pStyle), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
m_pStyle(pStyle), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
{
}
@@ -754,6 +754,62 @@ unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
return position;
}
void CBaseMenu::ShufflePerClient(int start, int stop)
{
// limit map len to 255 items since it's using uint8
int length = MIN(GetItemCount(), 255);
if (stop >= 0)
length = MIN(length, stop);
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
{
// populate per-client map ...
m_RandomMaps[i].resize(length);
for (int j = 0; j < length; j++)
m_RandomMaps[i][j] = j;
// ... and random shuffle it
for (int j = length - 1; j > start; j--)
{
int x = rand() % (j - start + 1) + start;
uint8_t tmp = m_RandomMaps[i][x];
m_RandomMaps[i][x] = m_RandomMaps[i][j];
m_RandomMaps[i][j] = tmp;
}
}
}
void CBaseMenu::SetClientMapping(int client, int *array, int length)
{
length = MIN(length, 255);
m_RandomMaps[client].resize(length);
for (int i = 0; i < length; i++)
{
m_RandomMaps[client][i] = array[i];
}
}
bool CBaseMenu::IsPerClientShuffled()
{
for (int i = 1; i < SM_MAXPLAYERS + 1; i++)
{
if(m_RandomMaps[i].length() > 0)
return true;
}
return false;
}
unsigned int CBaseMenu::GetRealItemIndex(int client, unsigned int position)
{
if (client > 0 && position < m_RandomMaps[client].length())
{
position = m_RandomMaps[client][position];
return m_items[position].index;
}
return position;
}
unsigned int CBaseMenu::GetItemCount()
{
return m_items.size();
+6 -6
View File
@@ -8,7 +8,7 @@
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@@ -98,7 +98,7 @@ public:
class CBaseMenu;
class BaseMenuStyle :
class BaseMenuStyle :
public IMenuStyle,
public IClientListener
{
@@ -113,11 +113,11 @@ public: //IClientListener
public: //what derived must implement
virtual CBaseMenuPlayer *GetMenuPlayer(int client) =0;
virtual void SendDisplay(int client, IMenuPanel *display) =0;
public: //what derived may implement
virtual bool DoClientMenu(int client,
CBaseMenu *menu,
public: //what derived may implement
virtual bool DoClientMenu(int client,
CBaseMenu *menu,
unsigned int first_item,
IMenuHandler *mh,
IMenuHandler *mh,
unsigned int time);
virtual bool DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time);
virtual void AddClientToWatch(int client);
+8 -2
View File
@@ -47,6 +47,8 @@
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
#elif SOURCE_ENGINE == SE_BLADE
#include <game/shared/berimbau/protobuf/berimbau_usermessages.pb.h>
#elif SOURCE_ENGINE == SE_MCV
#include <game/shared/vietnam/protobuf/vietnam_usermessages.pb.h>
#endif
extern const char *g_RadioNumTable[];
@@ -182,7 +184,7 @@ void CRadioStyle::OnUserMessage(int msg_id, bf_write *bf, IRecipientFilter *pFil
{
int count = pFilter->GetRecipientCount();
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
int c = ((CCSUsrMsg_ShowMenu &)msg).display_time();
#else
bf_read br(bf->GetBasePointer(), 3);
@@ -500,9 +502,13 @@ void CRadioMenuPlayer::Radio_Refresh()
time = menuHoldTime - (unsigned int)(gpGlobals->curtime - menuStartTime);
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
// TODO: find what happens past 240 on CS:GO
CCSUsrMsg_ShowMenu *msg = (CCSUsrMsg_ShowMenu *)g_UserMsgs.StartProtobufMessage(g_ShowMenuId, players, 1, USERMSG_BLOCKHOOKS);
if (!msg)
{
return;
}
msg->set_bits_valid_slots(display_keys);
msg->set_display_time(time);
msg->set_menu_string(ptr);
+1
View File
@@ -40,6 +40,7 @@
#include "UserMessages.h"
#include "sm_fastlink.h"
#include <sh_stack.h>
#include <sh_string.h>
#include <compat_wrappers.h>
#include "logic/common_logic.h"
#include "AutoHandleRooter.h"
+20 -1
View File
@@ -109,6 +109,8 @@ bool NextMapManager::SetNextMap(const char *map)
return true;
}
static char g_nextMap[PLATFORM_MAX_PATH];
#if SOURCE_ENGINE != SE_DARKMESSIAH
void NextMapManager::HookChangeLevel(const char *map, const char *unknown)
#else
@@ -122,8 +124,16 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
}
const char *newmap = sm_nextmap.GetString();
if (newmap[0] != '\0') {
ke::SafeStrcpy(g_nextMap, sizeof(g_nextMap), newmap);
newmap = g_nextMap;
if (newmap[0] == 0 || !g_HL2.IsMapValid(newmap))
// Clear the value so that if the map load fails later we don't get stuck in a loop.
// This might cause us to go off-cycle for a map, but nextmap will get us back on track.
sm_nextmap.SetValue("");
}
if (newmap[0] == '\0' || !g_HL2.IsMapValid(newmap))
{
RETURN_META(MRES_IGNORED);
}
@@ -142,6 +152,15 @@ void NextMapManager::HookChangeLevel(const char *map, const char *unknown, const
void NextMapManager::OnSourceModLevelChange( const char *mapName )
{
// If we were controlling the map change, reset sm_nextmap to be the name of the map we successfully changed to.
// This maintains an old API contract on the plugin side. We use the real map name even if it was different from
// the expected map name as if the expected map failed to load we let the game take over instead, but the nextmap
// plugin compares the sm_nextmap value to the current map to decide if it should advance the mapcycle.
if (g_nextMap[0] != '\0') {
sm_nextmap.SetValue(mapName);
g_nextMap[0] = '\0';
}
/* Skip the first 'mapchange' when the server starts up */
if (m_tempChangeInfo.startTime != 0)
{
+1 -1
View File
@@ -96,7 +96,7 @@ public:
private:
MapChangeData m_tempChangeInfo;
char lastMap[32];
char lastMap[PLATFORM_MAX_PATH];
};
extern NextMapManager g_NextMap;
+128 -119
View File
@@ -59,6 +59,8 @@ bool g_OnMapStarted = false;
IForward *PreAdminCheck = NULL;
IForward *PostAdminCheck = NULL;
IForward *PostAdminFilter = NULL;
IForward *ServerEnterHibernation = NULL;
IForward *ServerExitHibernation = NULL;
const unsigned int *g_NumPlayersToAuth = NULL;
int lifestate_offset = -1;
@@ -196,12 +198,15 @@ void PlayerManager::OnSourceModAllInitialized()
m_clcommandkv_post = forwardsys->CreateForward("OnClientCommandKeyValues_Post", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
m_clinfochanged = forwardsys->CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
m_clauth = forwardsys->CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
m_cllang = forwardsys->CreateForward("OnClientLanguageChanged", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
m_onActivate = forwardsys->CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
m_onActivate2 = forwardsys->CreateForward("OnMapStart", ET_Ignore, 0, NULL);
PreAdminCheck = forwardsys->CreateForward("OnClientPreAdminCheck", ET_Event, 1, p1);
PostAdminCheck = forwardsys->CreateForward("OnClientPostAdminCheck", ET_Ignore, 1, p1);
PostAdminFilter = forwardsys->CreateForward("OnClientPostAdminFilter", ET_Ignore, 1, p1);
ServerEnterHibernation = forwardsys->CreateForward("OnServerEnterHibernation", ET_Ignore, 0, NULL);
ServerExitHibernation = forwardsys->CreateForward("OnServerExitHibernation", ET_Ignore, 0, NULL);
m_bIsListenServer = !engine->IsDedicatedServer();
m_ListenClient = 0;
@@ -212,6 +217,9 @@ void PlayerManager::OnSourceModAllInitialized()
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdMaxplayersCallback), true);
maxplayersCmd = pCmd;
}
gameevents->AddListener(this, "player_connect", true);
gameevents->AddListener(this, "player_disconnect", true);
}
void PlayerManager::OnSourceModShutdown()
@@ -246,12 +254,15 @@ void PlayerManager::OnSourceModShutdown()
forwardsys->ReleaseForward(m_clcommandkv_post);
forwardsys->ReleaseForward(m_clinfochanged);
forwardsys->ReleaseForward(m_clauth);
forwardsys->ReleaseForward(m_cllang);
forwardsys->ReleaseForward(m_onActivate);
forwardsys->ReleaseForward(m_onActivate2);
forwardsys->ReleaseForward(PreAdminCheck);
forwardsys->ReleaseForward(PostAdminCheck);
forwardsys->ReleaseForward(PostAdminFilter);
forwardsys->ReleaseForward(ServerEnterHibernation);
forwardsys->ReleaseForward(ServerExitHibernation);
delete [] m_Players;
@@ -259,6 +270,8 @@ void PlayerManager::OnSourceModShutdown()
{
SH_REMOVE_HOOK(ConCommand, Dispatch, maxplayersCmd, SH_STATIC(CmdMaxplayersCallback), true);
}
gameevents->RemoveListener(this);
}
ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key,
@@ -512,7 +525,7 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
/* Get the client's language */
if (m_QueryLang)
{
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
pPlayer->m_LangId = translator->GetServerLanguage();
#else
const char *name;
@@ -520,10 +533,13 @@ bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const
{
unsigned int langid;
pPlayer->m_LangId = (translator->GetLanguageByName(name, &langid)) ? langid : translator->GetServerLanguage();
OnClientLanguageChanged(client, pPlayer->m_LangId);
} else {
pPlayer->m_LangId = translator->GetServerLanguage();
}
#endif
pPlayer->m_OriginalLangId = pPlayer->m_LangId;
}
List<IClientListener *>::iterator iter;
@@ -641,7 +657,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
int userId = engine->GetPlayerUserId(pEntity);
#if (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_PVKII)
static ConVar *tv_name = icvar->FindVar("tv_name");
#endif
#if SOURCE_ENGINE == SE_TF2
@@ -664,10 +680,13 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
&& ((!m_bIsReplayActive && newCount == 1)
|| (m_bIsReplayActive && newCount == 2))
&& (m_SourceTVUserId == userId
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_MCV
// It seems likely that MCV will change this at some point, but it's GOTV at the moment.
|| strcmp(playername, "GOTV") == 0
#elif SOURCE_ENGINE == SE_BLADE
|| strcmp(playername, "BBTV") == 0
#elif (SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_LEFT4DEAD2)
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_PVKII)
|| (tv_name && strcmp(playername, tv_name->GetString()) == 0) || (tv_name && tv_name->GetString()[0] == 0 && strcmp(playername, "unnamed") == 0)
#else
|| strcmp(playername, "SourceTV") == 0
@@ -721,7 +740,7 @@ void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername
}
pPlayer->Authorize_Post();
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
else if(m_QueryLang)
{
// Not a bot
@@ -770,6 +789,11 @@ void PlayerManager::OnSourceModLevelEnd()
void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
{
cell_t res;
if (bHibernating)
ServerEnterHibernation->Execute(&res);
else
ServerExitHibernation->Execute(&res);
/* If bots were added at map start, but not fully inited before hibernation, there will
* be no OnClientDisconnect for them, despite them getting booted right before this.
*/
@@ -781,7 +805,7 @@ void PlayerManager::OnServerHibernationUpdate(bool bHibernating)
CPlayer *pPlayer = &m_Players[i];
if (pPlayer->IsConnected() && pPlayer->IsFakeClient())
{
#if SOURCE_ENGINE < SE_LEFT4DEAD || SOURCE_ENGINE >= SE_CSGO || SOURCE_ENGINE == SE_NUCLEARDAWN
#if SOURCE_ENGINE < SE_LEFT4DEAD || SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_NUCLEARDAWN || SOURCE_ENGINE == SE_MCV
// These games have the bug fixed where hltv/replay was getting kicked on hibernation
if (pPlayer->IsSourceTV() || pPlayer->IsReplay())
continue;
@@ -967,8 +991,6 @@ void ClientConsolePrint(edict_t *e, const char *fmt, ...)
void ListExtensionsToClient(CPlayer *player, const CCommand &args)
{
char buffer[256];
unsigned int id = 0;
unsigned int start = 0;
AutoExtensionList extensions(extsys);
if (!extensions->size())
@@ -977,11 +999,6 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
return;
}
if (args.ArgC() > 2)
{
start = atoi(args.Arg(2));
}
size_t i = 0;
for (; i < extensions->size(); i++)
{
@@ -993,17 +1010,6 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
continue;
}
id++;
if (id < start)
{
continue;
}
if (id - start > 10)
{
break;
}
IExtensionInterface *api = ext->GetAPI();
const char *name = api->GetExtensionName();
@@ -1028,31 +1034,14 @@ void ListExtensionsToClient(CPlayer *player, const CCommand &args)
len += ke::SafeSprintf(&buffer[len], sizeof(buffer)-len, ": %s", description);
}
ClientConsolePrint(player->GetEdict(), "%s", buffer);
}
for (; i < extensions->size(); i++)
{
char error[255];
if (extensions->at(i)->IsRunning(error, sizeof(error)))
{
break;
}
}
if (i < extensions->size())
{
ClientConsolePrint(player->GetEdict(), "To see more, type \"sm exts %d\"", id);
}
}
void ListPluginsToClient(CPlayer *player, const CCommand &args)
{
char buffer[256];
unsigned int id = 0;
edict_t *e = player->GetEdict();
unsigned int start = 0;
AutoPluginList plugins(scripts);
if (!plugins->size())
@@ -1061,11 +1050,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
return;
}
if (args.ArgC() > 2)
{
start = atoi(args.Arg(2));
}
SourceHook::List<SMPlugin *> m_FailList;
size_t i = 0;
@@ -1078,18 +1062,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
continue;
}
/* Count valid plugins */
id++;
if (id < start)
{
continue;
}
if (id - start > 10)
{
break;
}
size_t len;
const sm_plugininfo_t *info = pl->GetPublicInfo();
len = ke::SafeSprintf(buffer, sizeof(buffer), " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
@@ -1107,21 +1079,6 @@ void ListPluginsToClient(CPlayer *player, const CCommand &args)
}
ClientConsolePrint(e, "%s", buffer);
}
/* See if we can get more plugins */
for (; i < plugins->size(); i++)
{
if (plugins->at(i)->GetStatus() == Plugin_Running)
{
break;
}
}
/* Do we actually have more plugins? */
if (i < plugins->size())
{
ClientConsolePrint(e, "To see more, type \"sm plugins %d\"", id);
}
}
#if SOURCE_ENGINE >= SE_ORANGEBOX
@@ -1207,7 +1164,7 @@ void PlayerManager::OnClientCommand(edict_t *pEntity)
if (g_ConsoleDetours.IsEnabled())
{
cell_t res2 = g_ConsoleDetours.InternalDispatch(client, &cargs);
if (res2 >= Pl_Stop)
if (res2 >= Pl_Handled)
{
RETURN_META(MRES_SUPERCEDE);
}
@@ -1337,65 +1294,69 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
m_clinfochanged->PushCell(client);
m_clinfochanged->Execute(&res, NULL);
if (pPlayer->IsFakeClient())
{
return;
}
IPlayerInfo *info = pPlayer->GetPlayerInfo();
const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name");
const char *old_name = pPlayer->m_Name.c_str();
#if SOURCE_ENGINE >= SE_LEFT4DEAD
const char *networkid_force;
if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0')
{
unsigned int accountId = pPlayer->GetSteamAccountID();
logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")",
new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress());
pPlayer->Kick("NetworkID spoofing detected.");
RETURN_META(MRES_IGNORED);
}
#endif
if (strcmp(old_name, new_name) != 0)
{
AdminId id = adminsys->FindAdminByIdentity("name", new_name);
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
if (!pPlayer->IsFakeClient())
{
if (!CheckSetAdminName(client, pPlayer, id))
AdminId id = adminsys->FindAdminByIdentity("name", new_name);
if (id != INVALID_ADMIN_ID && pPlayer->GetAdminId() != id)
{
char kickMsg[128];
logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
pPlayer->Kick(kickMsg);
RETURN_META(MRES_IGNORED);
if (!CheckSetAdminName(client, pPlayer, id))
{
char kickMsg[128];
logicore.CoreTranslate(kickMsg, sizeof(kickMsg), "%T", 2, NULL, "Name Reserved", &client);
pPlayer->Kick(kickMsg);
RETURN_META(MRES_IGNORED);
}
}
} else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
if (id == pPlayer->GetAdminId())
{
/* This player is changing their name; force them to drop admin privileges! */
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
else if ((id = adminsys->FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
if (id == pPlayer->GetAdminId())
{
/* This player is changing their name; force them to drop admin privileges! */
pPlayer->SetAdminId(INVALID_ADMIN_ID, false);
}
}
}
pPlayer->SetName(new_name);
}
if (m_PassInfoVar.size() > 0)
if (!pPlayer->IsFakeClient())
{
/* Try for a password change */
const char *old_pass = pPlayer->m_LastPassword.c_str();
const char *new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str());
if (strcmp(old_pass, new_pass) != 0)
if (m_PassInfoVar.size() > 0)
{
pPlayer->m_LastPassword.assign(new_pass);
if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
/* Try for a password change */
const char* old_pass = pPlayer->m_LastPassword.c_str();
const char* new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str());
if (strcmp(old_pass, new_pass) != 0)
{
/* If there is already an admin id assigned, this will just bail out. */
pPlayer->DoBasicAdminChecks();
pPlayer->m_LastPassword.assign(new_pass);
if (pPlayer->IsInGame() && pPlayer->IsAuthorized())
{
/* If there is already an admin id assigned, this will just bail out. */
pPlayer->DoBasicAdminChecks();
}
}
}
#if SOURCE_ENGINE >= SE_LEFT4DEAD
const char* networkid_force;
if ((networkid_force = engine->GetClientConVarValue(client, "networkid_force")) && networkid_force[0] != '\0')
{
unsigned int accountId = pPlayer->GetSteamAccountID();
logger->LogMessage("\"%s<%d><STEAM_1:%d:%d><>\" has bad networkid (id \"%s\") (ip \"%s\")",
new_name, pPlayer->GetUserId(), accountId & 1, accountId >> 1, networkid_force, pPlayer->GetIPAddress());
pPlayer->Kick("NetworkID spoofing detected.");
RETURN_META(MRES_IGNORED);
}
#endif
}
/* Notify Extensions */
List<IClientListener *>::iterator iter;
IClientListener *pListener = NULL;
@@ -1409,6 +1370,13 @@ void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
}
}
void PlayerManager::OnClientLanguageChanged(int client, unsigned int language)
{
m_cllang->PushCell(client);
m_cllang->PushCell(language);
m_cllang->Execute(NULL);
}
int PlayerManager::GetMaxClients()
{
return m_maxClients;
@@ -1428,6 +1396,11 @@ int PlayerManager::GetNumPlayers()
return m_PlayerCount;
}
int PlayerManager::GetNumClients()
{
return m_ClientCount;
}
int PlayerManager::GetClientOfUserId(int userid)
{
if (userid < 0 || userid > USHRT_MAX)
@@ -2008,7 +1981,7 @@ void CmdMaxplayersCallback()
g_Players.MaxPlayersChanged();
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue)
{
for (int i = 1; i <= m_maxClients; i++)
@@ -2016,7 +1989,10 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
if (m_Players[i].m_LanguageCookie == cookie)
{
unsigned int langid;
m_Players[i].m_LangId = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage();
unsigned int new_langid = (translator->GetLanguageByName(cvarValue, &langid)) ? langid : translator->GetServerLanguage();
m_Players[i].m_LangId = new_langid;
m_Players[i].m_OriginalLangId = new_langid;
OnClientLanguageChanged(i, new_langid);
return true;
}
@@ -2026,6 +2002,27 @@ bool PlayerManager::HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQue
}
#endif
/* IGameEventListener2::FireGameEvent */
void PlayerManager::FireGameEvent(IGameEvent *pEvent)
{
const char *name = pEvent->GetName();
if (strcmp(name, "player_connect") == 0)
{
const int client = pEvent->GetInt("index") + 1;
const int userid = pEvent->GetInt("userid");
m_ClientCount++;
}
else if (strcmp(name, "player_disconnect") == 0)
{
const int userid = pEvent->GetInt("userid");
const int client = m_UserIdLookUp[userid];
m_ClientCount--;
}
}
/*******************
*** PLAYER CODE ***
@@ -2044,6 +2041,7 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
m_pEdict = pEntity;
m_iIndex = IndexOfEdict(pEntity);
m_LangId = translator->GetServerLanguage();
m_OriginalLangId = m_LangId;
m_Serial.bits.index = m_iIndex;
m_Serial.bits.serial = g_PlayerSerialCount++;
@@ -2064,7 +2062,9 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
|| SOURCE_ENGINE == SE_HL2DM \
|| SOURCE_ENGINE == SE_BMS \
|| SOURCE_ENGINE == SE_INSURGENCY \
|| SOURCE_ENGINE == SE_DOI
|| SOURCE_ENGINE == SE_DOI \
|| SOURCE_ENGINE == SE_BLADE \
|| SOURCE_ENGINE == SE_PVKII
m_pIClient = engine->GetIServer()->GetClient(m_iIndex - 1);
#else
#if SOURCE_ENGINE == SE_SDK2013
@@ -2240,7 +2240,7 @@ void CPlayer::Disconnect()
m_bIsSourceTV = false;
m_bIsReplay = false;
m_Serial.value = -1;
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
m_LanguageCookie = InvalidQueryCvarCookie;
#endif
ClearNetchannelQueue();
@@ -2462,7 +2462,7 @@ void CPlayer::Kick(const char *str)
}
else
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
pClient->Disconnect(str);
#else
pClient->Disconnect("%s", str);
@@ -2609,9 +2609,18 @@ unsigned int CPlayer::GetLanguageId()
return m_LangId;
}
unsigned int CPlayer::GetOriginalLanguageId()
{
return m_OriginalLangId;
}
void CPlayer::SetLanguageId(unsigned int id)
{
m_LangId = id;
if(m_LangId != id)
{
m_LangId = id;
g_Players.OnClientLanguageChanged(m_iIndex, id);
}
}
int CPlayer::GetUserId()
+12 -3
View File
@@ -96,6 +96,7 @@ public:
bool IsInKickQueue();
IPlayerInfo *GetPlayerInfo();
unsigned int GetLanguageId();
unsigned int GetOriginalLanguageId();
void SetLanguageId(unsigned int id);
int GetUserId();
bool RunAdminCacheChecks();
@@ -145,13 +146,14 @@ private:
bool m_bAdminCheckSignalled = false;
int m_iIndex;
unsigned int m_LangId = SOURCEMOD_LANGUAGE_ENGLISH;
unsigned int m_OriginalLangId = SOURCEMOD_LANGUAGE_ENGLISH;
int m_UserId = -1;
bool m_bFakeClient = false;
bool m_bIsSourceTV = false;
bool m_bIsReplay = false;
serial_t m_Serial;
CSteamID m_SteamId;
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
#endif
std::deque<std::string> m_PrintfBuffer;
@@ -159,7 +161,8 @@ private:
class PlayerManager :
public SMGlobalClass,
public IPlayerManager
public IPlayerManager,
public IGameEventListener2
{
friend class CPlayer;
public:
@@ -192,6 +195,7 @@ public:
#endif
void OnClientSettingsChanged(edict_t *pEntity);
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
void OnClientLanguageChanged(int client, unsigned int language);
void OnServerHibernationUpdate(bool bHibernating);
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
void OnPrintfFrameAction(unsigned int serial);
@@ -202,6 +206,7 @@ public: //IPlayerManager
IGamePlayer *GetGamePlayer(edict_t *pEdict);
int GetMaxClients();
int GetNumPlayers();
int GetNumClients();
int GetClientOfUserId(int userid);
bool IsServerActivated();
int FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags);
@@ -212,6 +217,8 @@ public: //IPlayerManager
int GetClientFromSerial(unsigned int serial);
void ClearAdminId(AdminId id);
void RecheckAnyAdmins();
public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent);
public:
inline int MaxClients()
{
@@ -235,7 +242,7 @@ public:
{
return m_bInCCKVHook;
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
bool HandleConVarQuery(QueryCvarCookie_t cookie, int client, EQueryCvarValueStatus result, const char *cvarName, const char *cvarValue);
#endif
private:
@@ -253,6 +260,7 @@ private:
IForward *m_clcommandkv_post;
IForward *m_clinfochanged;
IForward *m_clauth;
IForward *m_cllang;
IForward *m_onActivate;
IForward *m_onActivate2;
CPlayer *m_Players;
@@ -272,6 +280,7 @@ private:
int m_SourceTVUserId;
int m_ReplayUserId;
bool m_bInCCKVHook;
int m_ClientCount;
private:
static const int NETMSG_TYPE_BITS = 5; // SVC_Print overhead for netmsg type
static const int SVC_Print_BufferSize = 2048 - 1; // -1 for terminating \0
+19 -28
View File
@@ -35,7 +35,6 @@
#include "frame_hooks.h"
#include "ConVarManager.h"
#include "logic_bridge.h"
#include <bridge/include/IProviderCallbacks.h>
#define TIMER_MIN_ACCURACY 0.1
@@ -171,8 +170,9 @@ void ITimer::Initialize(ITimedEvent *pCallbacks, float fInterval, float fToExec,
TimerSystem::TimerSystem()
{
m_pMapTimer = NULL;
m_bHasMapTickedYet = false;
m_bHasMapSimulatedYet = false;
m_fLastTickedTime = 0.0f;
OnSourceModLevelEnd();
}
TimerSystem::~TimerSystem()
@@ -213,28 +213,29 @@ void TimerSystem::OnSourceModLevelEnd()
{
m_bHasMapTickedYet = false;
m_bHasMapSimulatedYet = false;
m_bWasSimulating = false;
m_uFramesAhead = 0;
}
/* Think is called before gpGlobals is updated every frame, even if the server is hibernating */
void TimerSystem::Think(bool unused)
void TimerSystem::GameFrame(bool simulating)
{
m_uFramesAhead++;
bool simulating = m_bWasSimulating && m_uFramesAhead == 1;
if (m_bHasMapTickedYet) {
g_fUniversalTime += gpGlobals->realtime - m_fLastTickedTime;
} else {
if (simulating && m_bHasMapTickedYet)
{
g_fUniversalTime += gpGlobals->curtime - m_fLastTickedTime;
if (!m_bHasMapSimulatedYet)
{
m_bHasMapSimulatedYet = true;
MapTimeLeftChanged();
}
}
else
{
g_fUniversalTime += gpGlobals->interval_per_tick;
}
m_fLastTickedTime = gpGlobals->realtime;
m_fLastTickedTime = gpGlobals->curtime;
m_bHasMapTickedYet = true;
logicore.callbacks->OnThink(simulating);
if (g_fUniversalTime >= g_fTimerThink) {
if (g_fUniversalTime >= g_fTimerThink)
{
RunFrame();
g_fTimerThink = CalcNextThink(g_fTimerThink, TIMER_MIN_ACCURACY);
@@ -242,19 +243,9 @@ void TimerSystem::Think(bool unused)
RunFrameHooks(simulating);
m_pOnGameFrame->Execute();
}
/* GameFrame is called after gpGlobals is updated, and may not be called when the server is hibernating */
void TimerSystem::GameFrame(bool simulating)
{
m_bWasSimulating = simulating;
m_uFramesAhead = 0;
if (simulating && !m_bHasMapSimulatedYet)
if (m_pOnGameFrame->GetFunctionCount())
{
m_bHasMapSimulatedYet = true;
MapTimeLeftChanged();
m_pOnGameFrame->Execute(NULL);
}
}
-3
View File
@@ -82,7 +82,6 @@ public: //ITimerSystem
public:
void RunFrame();
void RemoveMapChangeTimers();
void Think(bool unused);
void GameFrame(bool simulating);
private:
List<ITimer *> m_SingleTimers;
@@ -93,8 +92,6 @@ private:
/* This is stuff for our manual ticking escapades. */
bool m_bHasMapTickedYet; /** Has the map ticked yet? */
bool m_bHasMapSimulatedYet; /** Has the map simulated yet? */
bool m_bWasSimulating; /** Was the last GameFrame simulating */
unsigned m_uFramesAhead; /** Number of frames Think is ahead of GameFrame */
float m_fLastTickedTime; /** Last time that the game currently gave
us while ticking.
*/
-20
View File
@@ -816,9 +816,6 @@ public:
inline bool GetColor(const char *pszFieldName, Color *out)
{
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_NOT_REPEATED();
@@ -832,14 +829,10 @@ public:
);
return true;
#endif
}
inline bool SetColor(const char *pszFieldName, const Color &value)
{
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_NOT_REPEATED();
@@ -851,14 +844,10 @@ public:
msgRGBA->set_a(value.a());
return true;
#endif
}
inline bool GetRepeatedColor(const char *pszFieldName, int index, Color *out)
{
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_REPEATED();
@@ -873,14 +862,10 @@ public:
);
return true;
#endif
}
inline bool SetRepeatedColor(const char *pszFieldName, int index, const Color &value)
{
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_REPEATED();
@@ -893,14 +878,10 @@ public:
msgRGBA->set_a(value.a());
return true;
#endif
}
inline bool AddColor(const char *pszFieldName, const Color &value)
{
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_BLADE
return false;
#else
GETCHECK_FIELD();
CHECK_FIELD_TYPE(MESSAGE);
CHECK_FIELD_REPEATED();
@@ -912,7 +893,6 @@ public:
msgRGBA->set_a(value.a());
return true;
#endif
}
inline bool GetVector2D(const char *pszFieldName, Vector2D *out)
+65 -62
View File
@@ -37,16 +37,14 @@
#include <cstrike15_usermessage_helpers.h>
#elif SOURCE_ENGINE == SE_BLADE
#include <berimbau_usermessage_helpers.h>
#elif SOURCE_ENGINE == SE_MCV
#include <vietnam_usermessage_helpers.h>
#endif
#include <amtl/am-string.h>
UserMessages g_UserMsgs;
#ifdef USE_PROTOBUF_USERMESSAGES
const protobuf::Message *GetMessagePrototype(int msg_type);
#endif
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
SH_DECL_HOOK3_void(IVEngineServer, SendUserMessage, SH_NOATTRIB, 0, IRecipientFilter &, int, const protobuf::Message &);
#else
#if SOURCE_ENGINE >= SE_LEFT4DEAD
@@ -55,14 +53,14 @@ SH_DECL_HOOK3(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRec
SH_DECL_HOOK2(IVEngineServer, UserMessageBegin, SH_NOATTRIB, 0, bf_write *, IRecipientFilter *, int);
#endif
SH_DECL_HOOK0_void(IVEngineServer, MessageEnd, SH_NOATTRIB, 0);
#endif // ==SE_CSGO || ==SE_BLADE
#endif // ==SE_CSGO || ==SE_BLADE || ==SE_MCV
UserMessages::UserMessages()
#ifndef USE_PROTOBUF_USERMESSAGES
: m_InterceptBuffer(m_pBase, 2500)
{
#else
: m_InterceptBuffer(nullptr)
: m_InterceptBuffer(NULL)
{
#endif
m_HookCount = 0;
@@ -99,7 +97,7 @@ void UserMessages::OnSourceModAllShutdown()
{
if (m_HookCount)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@@ -119,6 +117,8 @@ int UserMessages::GetMessageIndex(const char *msg)
return g_Cstrike15UsermessageHelpers.GetIndex(msg);
#elif SOURCE_ENGINE == SE_BLADE
return g_BerimbauUsermessageHelpers.GetIndex(msg);
#elif SOURCE_ENGINE == SE_MCV
return g_VietnamUsermessageHelpers.GetIndex(msg);
#else
int msgid;
@@ -158,6 +158,8 @@ bool UserMessages::GetMessageName(int msgid, char *buffer, size_t maxlength) con
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msgid);
#elif SOURCE_ENGINE == SE_BLADE
const char *pszName = g_BerimbauUsermessageHelpers.GetName(msgid);
#elif SOURCE_ENGINE == SE_MCV
const char *pszName = g_VietnamUsermessageHelpers.GetName(msgid);
#endif
if (!pszName)
return false;
@@ -237,7 +239,7 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
#ifndef USE_PROTOBUF_USERMESSAGES
return NULL;
#else
PbHandle buffer;
protobuf::Message *buffer;
if (m_InExec || m_InHook)
{
@@ -266,9 +268,8 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
// direct message creation, return buffer "from engine". keep track
m_FakeEngineBuffer =
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
buffer = m_FakeEngineBuffer.AsUnowned();
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
buffer = m_FakeEngineBuffer;
} else {
char messageName[32];
if (!GetMessageName(msg_id, messageName, sizeof(messageName)))
@@ -277,30 +278,27 @@ google::protobuf::Message *UserMessages::StartProtobufMessage(int msg_id, const
return NULL;
}
// The message returned here should always local.
auto msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
protobuf::Message *msg = OnStartMessage_Pre(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
switch (m_FakeMetaRes)
{
case MRES_IGNORED:
case MRES_HANDLED:
m_FakeEngineBuffer =
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
buffer = m_FakeEngineBuffer.AsUnowned();
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
buffer = m_FakeEngineBuffer;
break;
case MRES_OVERRIDE:
m_FakeEngineBuffer =
PbHandle(GetMessagePrototype(msg_id)->New(), PbHandle::Owned, PbHandle::Local);
m_FakeEngineBuffer = GetMessagePrototype(msg_id)->New();
// fallthrough
case MRES_SUPERCEDE:
buffer = std::move(msg);
buffer = msg;
break;
}
OnStartMessage_Post(static_cast<IRecipientFilter *>(&m_CellRecFilter), msg_id, messageName);
}
assert(!buffer.is_owned());
return buffer.GetLocalMessage();
return buffer;
#endif // USE_PROTOBUF_USERMESSAGES
}
@@ -311,13 +309,12 @@ bool UserMessages::EndMessage()
return false;
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
PbHandle localBuffer = std::move(m_FakeEngineBuffer);
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
if (m_CurFlags & USERMSG_BLOCKHOOKS)
{
PbHandle priv = localBuffer.ToPrivate(m_CurId);
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId,
*priv.GetPrivateMessage());
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
delete m_FakeEngineBuffer;
m_FakeEngineBuffer = NULL;
} else {
OnMessageEnd_Pre();
@@ -326,12 +323,10 @@ bool UserMessages::EndMessage()
case MRES_IGNORED:
case MRES_HANDLED:
case MRES_OVERRIDE:
{
PbHandle priv = localBuffer.ToPrivate(m_CurId);
engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId,
*priv.GetPrivateMessage());
engine->SendUserMessage(static_cast<IRecipientFilter &>(m_CellRecFilter), m_CurId, *m_FakeEngineBuffer);
delete m_FakeEngineBuffer;
m_FakeEngineBuffer = NULL;
break;
}
//case MRES_SUPERCEDE:
}
@@ -344,7 +339,7 @@ bool UserMessages::EndMessage()
} else {
engine->MessageEnd();
}
#endif // SE_CSGO || SE_BLADE
#endif // SE_CSGO || SE_BLADE || SE_MCV
m_InExec = false;
m_CurFlags = 0;
@@ -429,7 +424,7 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
if (!m_HookCount++)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_ADD_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@@ -451,12 +446,14 @@ bool UserMessages::InternalHook(int msg_id, IBitBufUserMessageListener *pListene
}
#ifdef USE_PROTOBUF_USERMESSAGES
const protobuf::Message *GetMessagePrototype(int msg_type)
const protobuf::Message *UserMessages::GetMessagePrototype(int msg_type)
{
#if SOURCE_ENGINE == SE_CSGO
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type);
#elif SOURCE_ENGINE == SE_BLADE
return g_BerimbauUsermessageHelpers.GetPrototype(msg_type);
#elif SOURCE_ENGINE == SE_MCV
return g_VietnamUsermessageHelpers.GetPrototype(msg_type);
#endif
}
#endif
@@ -506,7 +503,7 @@ void UserMessages::_DecRefCounter()
{
if (--m_HookCount == 0)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Pre), false);
SH_REMOVE_HOOK(IVEngineServer, SendUserMessage, engine, SH_MEMBER(this, &UserMessages::OnSendUserMessage_Post), true);
#else
@@ -518,13 +515,15 @@ void UserMessages::_DecRefCounter()
}
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg)
{
#if SOURCE_ENGINE == SE_CSGO
const char *pszName = g_Cstrike15UsermessageHelpers.GetName(msg_type);
#elif SOURCE_ENGINE == SE_BLADE
const char *pszName = g_BerimbauUsermessageHelpers.GetName(msg_type);
#elif SOURCE_ENGINE == SE_MCV
const char *pszName = g_VietnamUsermessageHelpers.GetName(msg_type);
#endif
OnStartMessage_Pre(&filter, msg_type, pszName);
@@ -538,8 +537,7 @@ void UserMessages::OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type,
}
else
{
m_FakeEngineBuffer =
PbHandle(&const_cast<protobuf::Message &>(msg), PbHandle::Unowned, PbHandle::Private);
m_FakeEngineBuffer = &const_cast<protobuf::Message &>(msg);
}
OnStartMessage_Post(&filter, msg_type, pszName);
@@ -574,8 +572,8 @@ void UserMessages::OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type
RETURN_META(res)
#endif
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
PbHandle UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
protobuf::Message *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name)
#else
@@ -589,7 +587,7 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
|| (m_InExec && (m_CurFlags & USERMSG_BLOCKHOOKS)))
{
m_InHook = false;
UM_RETURN_META_VALUE(MRES_IGNORED, nullptr);
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
}
m_CurId = msg_type;
@@ -600,20 +598,22 @@ bf_write *UserMessages::OnStartMessage_Pre(IRecipientFilter *filter, int msg_typ
if (!is_intercept_empty)
{
#ifdef USE_PROTOBUF_USERMESSAGES
m_InterceptBuffer =
PbHandle(GetMessagePrototype(msg_type)->New(), PbHandle::Owned, PbHandle::Local);
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer.AsUnowned());
if (m_InterceptBuffer)
delete m_InterceptBuffer;
m_InterceptBuffer = GetMessagePrototype(msg_type)->New();
UM_RETURN_META_VALUE(MRES_SUPERCEDE, m_InterceptBuffer);
#else
m_InterceptBuffer.Reset();
UM_RETURN_META_VALUE(MRES_SUPERCEDE, &m_InterceptBuffer);
#endif
}
UM_RETURN_META_VALUE(MRES_IGNORED, nullptr);
UM_RETURN_META_VALUE(MRES_IGNORED, NULL);
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
void* UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
protobuf::Message *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name)
#else
@@ -627,9 +627,9 @@ bf_write *UserMessages::OnStartMessage_Post(IRecipientFilter *filter, int msg_ty
#ifdef USE_PROTOBUF_USERMESSAGES
if (m_FakeMetaRes == MRES_SUPERCEDE)
m_OrigBuffer = m_InterceptBuffer.AsUnowned();
m_OrigBuffer = m_InterceptBuffer;
else
m_OrigBuffer = m_FakeEngineBuffer.AsUnowned();
m_OrigBuffer = m_FakeEngineBuffer;
#else
m_OrigBuffer = META_RESULT_ORIG_RET(bf_write *);
#endif
@@ -725,11 +725,8 @@ void UserMessages::OnMessageEnd_Pre()
{
pInfo = (*iter);
pInfo->IsHooked = true;
#ifdef USE_PROTOBUF_USERMESSAGES
PbHandle local = m_InterceptBuffer.ToLocal(m_CurId);
res = pInfo->Callback->InterceptUserMessage(m_CurId, local.GetLocalMessage(), m_CurRecFilter);
m_InterceptBuffer.CopyFrom(local);
res = pInfo->Callback->InterceptUserMessage(m_CurId, m_InterceptBuffer, m_CurRecFilter);
#else
res = pInfo->Callback->InterceptUserMessage(m_CurId, &m_InterceptBuffer, m_CurRecFilter);
#endif
@@ -780,9 +777,8 @@ void UserMessages::OnMessageEnd_Pre()
if (!handled && intercepted)
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
PbHandle priv = m_InterceptBuffer.ToPrivate(m_CurId);
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *priv.GetPrivateMessage());
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
ENGINE_CALL(SendUserMessage)(static_cast<IRecipientFilter &>(*m_CurRecFilter), m_CurId, *m_InterceptBuffer);
#else
bf_write *engine_bfw;
#if SOURCE_ENGINE >= SE_LEFT4DEAD
@@ -793,14 +789,17 @@ void UserMessages::OnMessageEnd_Pre()
m_ReadBuffer.StartReading(m_InterceptBuffer.GetBasePointer(), m_InterceptBuffer.GetNumBytesWritten());
engine_bfw->WriteBitsFromBuffer(&m_ReadBuffer, m_InterceptBuffer.GetNumBitsWritten());
ENGINE_CALL(MessageEnd)();
#endif // SE_CSGO || SE_BLADE
#endif // SE_CSGO || SE_BLADE || SE_MCV
}
{
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
PbHandle tmp_msg(GetMessagePrototype(m_CurId)->New(), PbHandle::Owned, PbHandle::Local);
tmp_msg.CopyFrom(m_OrigBuffer);
auto pTempMsg = tmp_msg.GetLocalMessage();
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
int size = m_OrigBuffer->ByteSize();
uint8 *data = (uint8 *)stackalloc(size);
m_OrigBuffer->SerializePartialToArray(data, size);
protobuf::Message *pTempMsg = GetMessagePrototype(m_CurId)->New();
pTempMsg->ParsePartialFromArray(data, size);
#else
bf_write *pTempMsg = m_OrigBuffer;
#endif
@@ -823,6 +822,10 @@ void UserMessages::OnMessageEnd_Pre()
pInfo->IsHooked = false;
iter++;
}
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
delete pTempMsg;
#endif
}
UM_RETURN_META((intercepted) ? MRES_SUPERCEDE : MRES_IGNORED);
+9 -9
View File
@@ -44,7 +44,7 @@
using namespace SourceHook;
using namespace SourceMod;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
#define USE_PROTOBUF_USERMESSAGES
#endif
@@ -52,7 +52,6 @@ using namespace SourceMod;
#include <google/protobuf/message.h>
#include <google/protobuf/descriptor.h>
#include <netmessages.pb.h>
#include "pb_handle.h"
using namespace google;
#else
@@ -103,14 +102,14 @@ public: //IUserMessages
bool intercept=false);
UserMessageType GetUserMessageType() const;
public:
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
void OnSendUserMessage_Pre(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
void OnSendUserMessage_Post(IRecipientFilter &filter, int msg_type, const protobuf::Message &msg);
#endif
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
PbHandle OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
void* OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
protobuf::Message *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
protobuf::Message *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
#elif SOURCE_ENGINE >= SE_LEFT4DEAD
bf_write *OnStartMessage_Pre(IRecipientFilter *filter, int msg_type, const char *msg_name);
bf_write *OnStartMessage_Post(IRecipientFilter *filter, int msg_type, const char *msg_name);
@@ -122,6 +121,7 @@ public:
void OnMessageEnd_Post();
private:
#ifdef USE_PROTOBUF_USERMESSAGES
const protobuf::Message *GetMessagePrototype(int msg_type);
bool InternalHook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
bool InternalUnhook(int msg_id, IProtobufUserMessageListener *pListener, bool intercept, bool isNew);
#else
@@ -141,11 +141,11 @@ private:
bf_read m_ReadBuffer;
#else
// The engine used to provide this. Now we track it.
PbHandle m_OrigBuffer;
PbHandle m_FakeEngineBuffer;
protobuf::Message *m_OrigBuffer;
protobuf::Message *m_FakeEngineBuffer;
META_RES m_FakeMetaRes;
PbHandle m_InterceptBuffer;
protobuf::Message *m_InterceptBuffer;
#endif
size_t m_HookCount;
bool m_InHook;
+2 -2
View File
@@ -36,7 +36,7 @@
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool);
#else
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
@@ -82,7 +82,7 @@ public:
#endif
}
#if SOURCE_ENGINE == SE_CSGO
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
#else
void LinkConCommandBase(ConCommandBase *pBase)
+4 -1
View File
@@ -16,7 +16,7 @@ for cxx in builder.targets:
'SM_DEFAULT_THREADER',
'SM_LOGIC'
]
if binary.compiler.target.platform == 'linux':
binary.compiler.postlink += ['-lpthread', '-lrt']
elif binary.compiler.target.platform == 'mac':
@@ -84,6 +84,9 @@ for cxx in builder.targets:
'smn_halflife.cpp',
'FrameIterator.cpp',
'DatabaseConfBuilder.cpp',
'LumpManager.cpp',
'smn_entitylump.cpp',
'NativeInvoker.cpp',
]
if binary.compiler.target.arch == 'x86_64':
+17 -21
View File
@@ -128,8 +128,8 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
{
ConfDbInfoList *list = m_Builder.GetConfigList();
ke::RefPtr<ConfDbInfo> pInfo = list->GetDatabaseConf(name);
ConfDbInfoList &list = m_Builder.GetConfigList();
ke::RefPtr<ConfDbInfo> pInfo = list.GetDatabaseConf(name);
if (!pInfo)
{
@@ -148,7 +148,7 @@ bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool
/* Try to assign a real driver pointer */
if (pInfo->info.driver[0] == '\0')
{
std::string defaultDriver = list->GetDefaultDriver();
std::string defaultDriver = list.GetDefaultDriver();
if (!m_pDefault && defaultDriver.length() > 0)
{
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
@@ -209,17 +209,14 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
}
}
ConfDbInfoList *list = m_Builder.GetConfigList();
for (size_t i = 0; i < list->size(); i++)
{
ke::RefPtr<ConfDbInfo> current = list->at(i);
if (current->realDriver == pDriver)
ConfDbInfoList &list = m_Builder.GetConfigList();
for (auto conf : list) {
if (conf->realDriver == pDriver)
{
current->realDriver = NULL;
conf->realDriver = NULL;
}
}
/* Someone unloaded the default driver? Silly.. */
if (pDriver == m_pDefault)
{
@@ -255,8 +252,8 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
IDBDriver *DBManager::GetDefaultDriver()
{
ConfDbInfoList *list = m_Builder.GetConfigList();
std::string defaultDriver = list->GetDefaultDriver();
ConfDbInfoList &list = m_Builder.GetConfigList();
std::string defaultDriver = list.GetDefaultDriver();
if (!m_pDefault && defaultDriver.length() > 0)
{
m_pDefault = FindOrLoadDriver(defaultDriver.c_str());
@@ -322,12 +319,12 @@ IDBDriver *DBManager::GetDriver(unsigned int index)
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
{
ConfDbInfoList *list = m_Builder.GetConfigList();
ke::RefPtr<ConfDbInfo> info = list->GetDatabaseConf(name);
ConfDbInfoList &list = m_Builder.GetConfigList();
ke::RefPtr<ConfDbInfo> info = list.GetDatabaseConf(name);
if (!info)
{
// couldn't find requested conf, return default if exists
info = list->GetDefaultConfiguration();
info = list.GetDefaultConfiguration();
if (!info)
{
return NULL;
@@ -337,11 +334,10 @@ const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
return &info->info;
}
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
ke::RefPtr<ConfDbInfo> DBManager::GetDatabaseConf(const char *name)
{
ConfDbInfoList *list = m_Builder.GetConfigList();
ke::RefPtr<ConfDbInfo> info(list->GetDatabaseConf(name));
return info;
ConfDbInfoList &list = m_Builder.GetConfigList();
return list.GetDatabaseConf(name);
}
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
@@ -582,8 +578,8 @@ void DBManager::OnPluginWillUnload(IPlugin *plugin)
std::string DBManager::GetDefaultDriverName()
{
ConfDbInfoList *list = m_Builder.GetConfigList();
return list->GetDefaultDriver();
ConfDbInfoList &list = m_Builder.GetConfigList();
return list.GetDefaultDriver();
}
void DBManager::AddDependency(IExtension *myself, IDBDriver *driver)
+1 -1
View File
@@ -71,7 +71,7 @@ public: //IDBManager
void AddDriver(IDBDriver *pDrivera);
void RemoveDriver(IDBDriver *pDriver);
const DatabaseInfo *FindDatabaseConf(const char *name);
ConfDbInfo *GetDatabaseConf(const char *name);
ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name);
bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength);
unsigned int GetDriverCount();
IDBDriver *GetDriver(unsigned int index);
+8 -10
View File
@@ -36,8 +36,8 @@
#define DBPARSE_LEVEL_DATABASE 2
DatabaseConfBuilder::DatabaseConfBuilder()
: m_ParseList(nullptr),
m_InfoList(new ConfDbInfoList())
: m_ParseList(),
m_InfoList()
{
}
@@ -50,7 +50,7 @@ DatabaseConfBuilder::~DatabaseConfBuilder()
{
}
ConfDbInfoList *DatabaseConfBuilder::GetConfigList()
ConfDbInfoList &DatabaseConfBuilder::GetConfigList()
{
return m_InfoList;
}
@@ -75,7 +75,7 @@ void DatabaseConfBuilder::ReadSMC_ParseStart()
m_ParseLevel = 0;
m_ParseState = DBPARSE_LEVEL_NONE;
m_ParseList = new ConfDbInfoList();
m_ParseList.clear();
}
SMCResult DatabaseConfBuilder::ReadSMC_NewSection(const SMCStates *states, const char *name)
@@ -116,7 +116,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_KeyValue(const SMCStates *states, const c
{
if (strcmp(key, "driver_default") == 0)
{
m_ParseList->SetDefaultDriver(value);
m_ParseList.SetDefaultDriver(value);
}
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
if (strcmp(key, "driver") == 0)
@@ -161,7 +161,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
/* Save it.. */
m_ParseCurrent->AddRef();
m_ParseList->push_back(m_ParseCurrent);
m_ParseList.push_back(m_ParseCurrent);
m_ParseCurrent = nullptr;
/* Go up one level */
@@ -176,9 +176,7 @@ SMCResult DatabaseConfBuilder::ReadSMC_LeavingSection(const SMCStates *states)
void DatabaseConfBuilder::ReadSMC_ParseEnd(bool halted, bool failed)
{
m_InfoList->ReleaseMembers();
delete m_InfoList;
m_InfoList.clear();
m_InfoList = m_ParseList;
m_ParseList = nullptr;
m_ParseList.clear();
}
+10 -14
View File
@@ -38,6 +38,7 @@
#include <am-vector.h>
#include <am-string.h>
#include <am-refcounting.h>
#include <am-refcounting-threadsafe.h>
class ConfDbInfo : public ke::RefcountedThreadsafe<ConfDbInfo>
@@ -56,7 +57,7 @@ public:
DatabaseInfo info;
};
class ConfDbInfoList : public std::vector<ConfDbInfo *>
class ConfDbInfoList : public std::vector<ke::RefPtr<ConfDbInfo>>
{
/* Allow internal usage of ConfDbInfoList */
friend class DBManager;
@@ -66,10 +67,10 @@ private:
return m_DefDriver;
}
ConfDbInfo *GetDatabaseConf(const char *name) {
ke::RefPtr<ConfDbInfo> GetDatabaseConf(const char *name) {
for (size_t i = 0; i < this->size(); i++)
{
ConfDbInfo *current = this->at(i);
ke::RefPtr<ConfDbInfo> current = this->at(i);
/* If we run into the default configuration, then we'll save it
* for the next call to GetDefaultConfiguration */
if (strcmp(current->name.c_str(), "default") == 0)
@@ -83,20 +84,15 @@ private:
}
return nullptr;
}
ConfDbInfo *GetDefaultConfiguration() {
ke::RefPtr<ConfDbInfo> GetDefaultConfiguration() {
return m_DefaultConfig;
}
void SetDefaultDriver(const char *input) {
m_DefDriver = std::string(input);
}
void ReleaseMembers() {
for (size_t i = 0; i < this->size(); i++) {
ConfDbInfo *current = this->at(i);
current->Release();
}
}
private:
ConfDbInfo *m_DefaultConfig;
ke::RefPtr<ConfDbInfo> m_DefaultConfig;
std::string m_DefDriver;
};
@@ -108,7 +104,7 @@ public:
~DatabaseConfBuilder();
void StartParse();
void SetPath(char* path);
ConfDbInfoList *GetConfigList();
ConfDbInfoList &GetConfigList();
public: //ITextListener_SMC
void ReadSMC_ParseStart();
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
@@ -120,10 +116,10 @@ private:
unsigned int m_ParseLevel;
unsigned int m_ParseState;
ConfDbInfo *m_ParseCurrent;
ConfDbInfoList *m_ParseList;
ConfDbInfoList m_ParseList;
private:
std::string m_Filename;
ConfDbInfoList *m_InfoList;
ConfDbInfoList m_InfoList;
};
#endif //_INCLUDE_DATABASE_CONF_BUILDER_H_
+6 -6
View File
@@ -69,13 +69,13 @@ void DebugReport::GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err,
ke::SafeVsprintf(buffer, sizeof(buffer), message, ap);
const char *plname = pluginsys->FindPluginByContext(ctx->GetContext())->GetFilename();
const char *error = g_pSourcePawn2->GetErrorString(err);
if (error)
{
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
} else {
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
if (err >= 0) {
const char *error = g_pSourcePawn2->GetErrorString(err);
if (error)
g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
else
g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
}
g_Logger.LogError("[SM] %s", buffer);
+2
View File
@@ -47,6 +47,8 @@ public: // IDebugListener
void ReportError(const IErrorReport &report, IFrameIterator &iter);
void OnDebugSpew(const char *msg, ...);
public:
// If err is -1, caller assumes the automatic reporting by SourcePawn is
// good enough, and only wants the supplemental logging provided here.
void GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...);
void GenerateErrorVA(IPluginContext *ctx, cell_t func_idx, int err, const char *message, va_list ap);
void GenerateCodeError(IPluginContext *ctx, uint32_t code_addr, int err, const char *message, ...);
+2 -5
View File
@@ -240,6 +240,8 @@ void CLocalExtension::Unload()
m_pLib->CloseLibrary();
m_pLib = NULL;
}
m_bFullyLoaded = false;
}
bool CRemoteExtension::Reload(char *error, size_t maxlength)
@@ -393,11 +395,6 @@ void CExtension::AddDependency(const IfaceInfo *pInfo)
}
}
bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
{
return (i1.iface == i2.iface) && (i1.owner == i2.owner);
}
void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
{
IfaceInfo info;
+132 -38
View File
@@ -30,6 +30,7 @@
#include "common_logic.h"
#include <string.h>
#include <stdlib.h>
#include <sstream>
#include <sh_list.h>
#include <sh_string.h>
#include "GameConfigs.h"
@@ -46,6 +47,7 @@
#include <am-string.h>
#include <bridge/include/ILogger.h>
#include <bridge/include/CoreProvider.h>
#include <bridge/include/IFileSystemBridge.h>
#if defined PLATFORM_POSIX
#include <dlfcn.h>
@@ -85,15 +87,12 @@ static const char *g_pParseEngine = NULL;
#if defined PLATFORM_WINDOWS
#define PLATFORM_NAME "windows" PLATFORM_ARCH_SUFFIX
#define PLATFORM_SERVER_BINARY "server.dll"
#elif defined PLATFORM_LINUX
#define PLATFORM_NAME "linux" PLATFORM_ARCH_SUFFIX
#define PLATFORM_COMPAT_ALT "mac" PLATFORM_ARCH_SUFFIX /* Alternate platform name if game data is missing for primary one */
#define PLATFORM_SERVER_BINARY "server_i486.so"
#elif defined PLATFORM_APPLE
#define PLATFORM_NAME "mac" PLATFORM_ARCH_SUFFIX
#define PLATFORM_COMPAT_ALT "linux" PLATFORM_ARCH_SUFFIX
#define PLATFORM_SERVER_BINARY "server.dylib"
#endif
struct TempSigInfo
@@ -106,8 +105,6 @@ struct TempSigInfo
char sig[1024];
char library[64];
} s_TempSig;
unsigned int s_ServerBinCRC;
bool s_ServerBinCRC_Ok = false;
static bool DoesGameMatch(const char *value)
{
@@ -306,35 +303,21 @@ SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *n
{
char error[255];
error[0] = '\0';
if (strcmp(name, "server") != 0)
GameBinaryInfo binInfo;
if (!g_GameConfigs.TryGetGameBinaryInfo(name, &binInfo))
{
ke::SafeSprintf(error, sizeof(error), "Unrecognized library \"%s\"", name);
}
else if (!s_ServerBinCRC_Ok)
else if (!binInfo.m_crcOK)
{
FILE *fp;
char path[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
if ((fp = fopen(path, "rb")) == NULL)
{
ke::SafeSprintf(error, sizeof(error), "Could not open binary: %s", path);
} else {
size_t size;
void *buffer;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = malloc(size);
fread(buffer, size, 1, fp);
s_ServerBinCRC = UTIL_CRC32(buffer, size);
free(buffer);
s_ServerBinCRC_Ok = true;
fclose(fp);
}
ke::SafeSprintf(error, sizeof(error), "Could not get CRC for binary: %s", name);
}
else
{
bCurrentBinCRC_Ok = binInfo.m_crcOK;
bCurrentBinCRC = binInfo.m_crc;
}
if (error[0] != '\0')
{
m_IgnoreLevel = 1;
@@ -461,12 +444,12 @@ SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key
}
} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
if (DoesPlatformMatch(key)
&& s_ServerBinCRC_Ok
&& bCurrentBinCRC_Ok
&& !bShouldBeReadingDefault)
{
unsigned int crc = 0;
sscanf(value, "%08X", &crc);
if (s_ServerBinCRC == crc)
if (bCurrentBinCRC == crc)
{
bShouldBeReadingDefault = true;
}
@@ -603,14 +586,12 @@ SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
}
void *addrInBase = NULL;
if (strcmp(s_TempSig.library, "server") == 0)
GameBinaryInfo binInfo;
if (g_GameConfigs.TryGetGameBinaryInfo(s_TempSig.library, &binInfo))
{
addrInBase = bridge->serverFactory;
} else if (strcmp(s_TempSig.library, "engine") == 0) {
addrInBase = bridge->engineFactory;
} else if (strcmp(s_TempSig.library, "matchmaking_ds") == 0) {
addrInBase = bridge->matchmakingDSFactory;
addrInBase = binInfo.m_pAddr;
}
void *final_addr = NULL;
if (addrInBase == NULL)
{
@@ -810,7 +791,10 @@ public:
(!had_game && matched_engine) ||
(matched_engine && matched_game))
{
fileList->push_back(cur_file);
if (fileList->find(cur_file) == fileList->end())
{
fileList->push_back(cur_file);
}
}
state = MSTATE_MAIN;
}
@@ -1099,6 +1083,42 @@ bool CGameConfig::GetMemSig(const char *key, void **addr)
return m_Sigs.retrieve(key, addr);
}
void GameBinPathManager::Init()
{
char search_path[PLATFORM_MAX_PATH * 8];
bridge->filesystem->GetSearchPath("GAMEBIN", false, search_path, sizeof(search_path));
char addons_folder[12];
ke::SafeSprintf(addons_folder, sizeof(addons_folder), "%caddons%c", PLATFORM_SEP_CHAR, PLATFORM_SEP_CHAR);
std::istringstream iss(search_path);
for (std::string path; std::getline(iss, path, ';');)
{
if (path.length() > 0
&& path.find(addons_folder) == std::string::npos
&& m_lookup.find(path) == m_lookup.cend()
)
{
m_lookup.insert(path);
m_ordered.push_back(path);
}
}
iss.clear();
bridge->filesystem->GetSearchPath("EXECUTABLE_PATH", false, search_path, sizeof(search_path));
iss.str(search_path);
for (std::string path; std::getline(iss, path, ';');)
{
if (m_lookup.find(path) == m_lookup.cend())
{
m_lookup.insert(path);
m_ordered.push_back(path);
}
}
}
GameConfigManager::GameConfigManager()
{
}
@@ -1109,6 +1129,8 @@ GameConfigManager::~GameConfigManager()
void GameConfigManager::OnSourceModStartup(bool late)
{
m_gameBinPathManager.Init();
LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
strncopy(g_Game, g_pSM->GetGameFolderName(), sizeof(g_Game));
@@ -1231,3 +1253,75 @@ void GameConfigManager::RemoveCachedConfig(CGameConfig *config)
{
m_Lookup.remove(config->m_File);
}
void GameConfigManager::CacheGameBinaryInfo(const char* pszName)
{
GameBinaryInfo info;
char name[64];
bridge->FormatSourceBinaryName(pszName, name, sizeof(name));
char binary_path[PLATFORM_MAX_PATH];
for (auto it = m_gameBinPathManager.Paths().begin(); it != m_gameBinPathManager.Paths().end(); ++it)
{
ke::SafeSprintf(binary_path, sizeof(binary_path), "%s%s%s", it->c_str(), it->back() == PLATFORM_SEP_CHAR ? "" : PLATFORM_SEP, name);
#if defined PLATFORM_WINDOWS
HMODULE hModule = LoadLibraryA(binary_path);
if (hModule)
{
info.m_pAddr = GetProcAddress(hModule, "CreateInterface");
FreeLibrary(hModule);
}
#else
void *pHandle = dlopen(binary_path, RTLD_NOW);
if (pHandle)
{
info.m_pAddr = dlsym(pHandle, "CreateInterface");
dlclose(pHandle);
}
#endif
if (info.m_pAddr)
break;
}
// Don't bother trying to get CRC if we couldn't find the bin loaded
if (info.m_pAddr)
{
FILE *fp;
if ((fp = fopen(binary_path, "rb")) == 0)
{
info.m_crc = 0;
}
else
{
size_t size;
void* buffer;
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = malloc(size);
fread(buffer, size, 1, fp);
info.m_crc = UTIL_CRC32(buffer, size);
free(buffer);
info.m_crcOK = true;
fclose(fp);
}
}
// But insert regardless, to cache the first lookup (even as failed)
m_gameBinInfos.insert(pszName, info);
}
bool GameConfigManager::TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest)
{
if (m_gameBinInfos.retrieve(pszName, pDest))
return pDest->m_pAddr != nullptr;
CacheGameBinaryInfo(pszName);
return m_gameBinInfos.retrieve(pszName, pDest);
}
+32
View File
@@ -38,6 +38,7 @@
#include <am-refcounting.h>
#include <sm_stringhashmap.h>
#include <sm_namehashset.h>
#include <unordered_set>
using namespace SourceMod;
@@ -91,6 +92,8 @@ private:
std::string m_offset;
std::string m_Game;
std::string m_Key;
unsigned int bCurrentBinCRC;
bool bCurrentBinCRC_Ok = false;
bool bShouldBeReadingDefault;
bool had_game;
bool matched_game;
@@ -126,6 +129,30 @@ private:
time_t m_ModTime;
};
struct GameBinaryInfo
{
void *m_pAddr = nullptr;
uint32_t m_crc = 0;
bool m_crcOK = false;
};
class GameBinPathManager
{
public:
GameBinPathManager() {}
~GameBinPathManager() {}
public:
void Init();
inline const std::vector<std::string>& Paths() const
{
return m_ordered;
}
private:
std::unordered_set<std::string> m_lookup;
std::vector<std::string> m_ordered;
};
class GameConfigManager :
public IGameConfigManager,
public SMGlobalClass
@@ -148,11 +175,16 @@ public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModAllShutdown();
public:
bool TryGetGameBinaryInfo(const char* pszName, GameBinaryInfo* pDest);
void RemoveCachedConfig(CGameConfig *config);
private:
void CacheGameBinaryInfo(const char* pszName);
private:
NameHashSet<CGameConfig *> m_Lookup;
StringHashMap<GameBinaryInfo> m_gameBinInfos;
public:
StringHashMap<ITextListener_SMC *> m_customHandlers;
GameBinPathManager m_gameBinPathManager;
};
extern GameConfigManager g_GameConfigs;
+32 -5
View File
@@ -47,6 +47,8 @@
#include "sm_invalidparamhandler.h"
#endif
using namespace std::string_literals;
HandleSystem g_HandleSys;
QHandle *ignore_handle;
@@ -299,6 +301,28 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
}
}
if (owner)
{
owner->num_handles++;
if (!owner->warned_handle_usage && owner->num_handles >= HANDLESYS_WARN_USAGE)
{
owner->warned_handle_usage = true;
std::string path = "<unknown>";
if (auto plugin = scripts->FindPluginByIdentity(owner))
{
path = "plugin "s + plugin->GetFilename();
}
else if (auto ext = g_Extensions.GetExtensionFromIdent(owner))
{
path = "extension "s + ext->GetFilename();
}
logger->LogError("[SM] Warning: %s is using more than %d handles!",
path.c_str(), HANDLESYS_WARN_USAGE);
}
}
QHandle *pHandle = &m_Handles[handle];
assert(pHandle->set == false);
@@ -320,7 +344,7 @@ HandleError HandleSystem::MakePrimHandle(HandleType_t type,
/* Create the hash value */
Handle_t hash = pHandle->serial;
hash <<= 16;
hash <<= HANDLESYS_HANDLE_BITS;
hash |= handle;
/* Add a reference count to the type */
@@ -484,7 +508,7 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
unsigned int *in_index,
bool ignoreFree)
{
unsigned int serial = (handle >> 16);
unsigned int serial = (handle >> HANDLESYS_HANDLE_BITS);
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
@@ -640,7 +664,7 @@ Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
{
#ifndef NDEBUG
unsigned int serial = (hndl >> 16);
unsigned int serial = (hndl >> HANDLESYS_HANDLE_BITS);
#endif
index = (hndl & HANDLESYS_HANDLE_MASK);
@@ -664,6 +688,9 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
QHandleType *pType = &m_Types[pHandle->type];
if (pHandle->owner && pHandle->owner->num_handles > 0)
pHandle->owner->num_handles--;
if (pHandle->clone)
{
/* If we're a clone, decrease the parent reference count */
@@ -1138,12 +1165,12 @@ void HandleSystem::Dump(const HandleReporter &fn)
continue;
}
/* Get the index */
unsigned int index = (m_Handles[i].serial << 16) | i;
unsigned int index = (m_Handles[i].serial << HANDLESYS_HANDLE_BITS) | i;
/* Determine the owner */
const char *owner = "UNKNOWN";
if (m_Handles[i].owner)
{
IdentityToken_t *pOwner = m_Handles[i].owner;
IdentityToken_t *pOwner = m_Handles[i].owner;
if (pOwner == g_pCoreIdent)
{
owner = "CORE";
+7 -4
View File
@@ -42,14 +42,17 @@
#include <sm_namehashset.h>
#include "common_logic.h"
#define HANDLESYS_MAX_HANDLES (1<<15)
#define HANDLESYS_HANDLE_BITS 20
#define HANDLESYS_MAX_HANDLES ((1 << HANDLESYS_HANDLE_BITS) - 1)
#define HANDLESYS_MAX_TYPES (1<<9)
#define HANDLESYS_MAX_SUBTYPES 0xF
#define HANDLESYS_SUBTYPE_MASK 0xF
#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
#define HANDLESYS_MAX_SERIALS 0xFFFF
#define HANDLESYS_SERIAL_MASK 0xFFFF0000
#define HANDLESYS_HANDLE_MASK 0x0000FFFF
#define HANDLESYS_SERIAL_BITS (32 - HANDLESYS_HANDLE_BITS)
#define HANDLESYS_MAX_SERIALS (1 << HANDLESYS_SERIAL_BITS)
#define HANDLESYS_SERIAL_MASK (((1 << HANDLESYS_SERIAL_BITS) - 1) << HANDLESYS_HANDLE_BITS)
#define HANDLESYS_HANDLE_MASK ((1 << HANDLESYS_HANDLE_BITS) - 1)
#define HANDLESYS_WARN_USAGE 100000
#define HANDLESYS_MEMUSAGE_MIN_VERSION 3
+131
View File
@@ -0,0 +1,131 @@
/**
* vim: set ts=4 :
* =============================================================================
* Entity Lump Manager
* Copyright (C) 2021-2022 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include "LumpManager.h"
#include <iomanip>
#include <sstream>
EntityLumpParseResult::operator bool() const {
return m_Status == Status_OK;
}
EntityLumpParseResult EntityLumpManager::Parse(const char* pMapEntities) {
m_Entities.clear();
std::istringstream mapEntities(pMapEntities);
for (;;) {
std::string token;
mapEntities >> std::ws >> token >> std::ws;
// Assert that we're at the start of a new block, otherwise we're done parsing
if (token != "{") {
if (token == "\0") {
break;
} else {
return EntityLumpParseResult {
Status_UnexpectedChar, mapEntities.tellg()
};
}
}
/**
* Parse key / value pairs until we reach a closing brace. We currently assume there
* are only quoted keys / values up to the next closing brace.
*
* The SDK suggests that there are cases that could use non-quoted symbols and nested
* braces (`shared/mapentities_shared.cpp::MapEntity_ParseToken`), but I haven't seen
* those in practice.
*/
EntityLumpEntry entry;
while (mapEntities.peek() != '}') {
std::string key, value;
if (mapEntities.peek() != '"') {
return EntityLumpParseResult {
Status_UnexpectedChar, mapEntities.tellg()
};
}
mapEntities >> quoted(key) >> std::ws;
if (mapEntities.peek() != '"') {
return EntityLumpParseResult {
Status_UnexpectedChar, mapEntities.tellg()
};
}
mapEntities >> quoted(value) >> std::ws;
entry.emplace_back(key, value);
}
mapEntities.get();
m_Entities.push_back(std::make_shared<EntityLumpEntry>(entry));
}
return EntityLumpParseResult{};
}
std::string EntityLumpManager::Dump() {
std::ostringstream stream;
for (const auto& entry : m_Entities) {
// ignore empty entries
if (entry->empty()) {
continue;
}
stream << "{\n";
for (const auto& pair : *entry) {
stream << '"' << pair.first << "\" \"" << pair.second << '"' << '\n';
}
stream << "}\n";
}
return stream.str();
}
std::weak_ptr<EntityLumpEntry> EntityLumpManager::Get(size_t index) {
return m_Entities[index];
}
void EntityLumpManager::Erase(size_t index) {
m_Entities.erase(m_Entities.begin() + index);
}
void EntityLumpManager::Insert(size_t index) {
m_Entities.emplace(m_Entities.begin() + index, std::make_shared<EntityLumpEntry>());
}
size_t EntityLumpManager::Append() {
auto it = m_Entities.emplace(m_Entities.end(), std::make_shared<EntityLumpEntry>());
return std::distance(m_Entities.begin(), it);
}
size_t EntityLumpManager::Length() {
return m_Entities.size();
}
+116
View File
@@ -0,0 +1,116 @@
/**
* vim: set ts=4 :
* =============================================================================
* Entity Lump Manager
* Copyright (C) 2021-2022 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_LUMPMANAGER_H_
#define _INCLUDE_LUMPMANAGER_H_
#include <vector>
#include <memory>
#include <string>
/**
* Entity lump manager. Provides a list that stores a list of key / value pairs and the
* functionality to (de)serialize it from / to an entity string.
* This file and its corresponding .cpp should be compilable independently of SourceMod;
* the SourceMod interop is located within smn_entitylump.
*
* @file lumpmanager.h
* @brief Class definition for object that parses lumps.
*/
/**
* @brief A container of key / value pairs.
*/
using EntityLumpEntry = std::vector<std::pair<std::string, std::string>>;
enum EntityLumpParseStatus {
Status_OK,
Status_UnexpectedChar,
};
/**
* @brief Result of parsing an entity lump. On a parse error, m_Status is not Status_OK and
* m_Position indicates the offset within the string that caused the parse error.
*/
struct EntityLumpParseResult {
EntityLumpParseStatus m_Status;
std::streamoff m_Position;
operator bool() const;
const char* Description() const;
};
/**
* @brief Manages entity lump entries.
*/
class EntityLumpManager
{
public:
/**
* @brief Parses the map entities string into an internal representation.
*/
EntityLumpParseResult Parse(const char* pMapEntities);
/**
* @brief Dumps the current internal representation out to an std::string.
*/
std::string Dump();
/**
* @brief Returns a weak reference to an EntityLumpEntry. Used for handles on the scripting side.
*/
std::weak_ptr<EntityLumpEntry> Get(size_t index);
/**
* @brief Removes an EntityLumpEntry at the given index, shifting down all entries after it by one.
*/
void Erase(size_t index);
/**
* @brief Inserts a new EntityLumpEntry at the given index, shifting up the entries previously at the index and after it up by one.
*/
void Insert(size_t index);
/**
* @brief Adds a new EntityLumpEntry to the end. Returns the index of the entry.
*/
size_t Append();
/**
* @brief Returns the number of EntityLumpEntry items in the list.
*/
size_t Length();
private:
std::vector<std::shared_ptr<EntityLumpEntry>> m_Entities;
};
#endif // _INCLUDE_LUMPMANAGER_H_
+51 -28
View File
@@ -49,6 +49,7 @@ MemoryUtils g_MemUtils;
MemoryUtils::MemoryUtils()
{
m_InfoMap.init();
#ifdef PLATFORM_APPLE
task_dyld_info_data_t dyld_info;
@@ -77,20 +78,19 @@ void MemoryUtils::OnSourceModAllInitialized()
void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t len)
{
DynLibInfo lib;
bool found;
char *ptr, *end;
const DynLibInfo* lib = nullptr;
memset(&lib, 0, sizeof(DynLibInfo));
if (!GetLibraryInfo(libPtr, lib))
if ((lib = GetLibraryInfo(libPtr)) == nullptr)
{
return NULL;
}
ptr = reinterpret_cast<char *>(lib.baseAddress);
end = ptr + lib.memorySize - len;
// Search in the original unaltered state of the binary.
char *start = lib->originalCopy.get();
char *ptr = start;
char *end = ptr + lib->memorySize - len;
bool found;
while (ptr < end)
{
found = true;
@@ -103,8 +103,9 @@ void *MemoryUtils::FindPattern(const void *libPtr, const char *pattern, size_t l
}
}
// Translate the found offset into the actual live binary memory space.
if (found)
return ptr;
return reinterpret_cast<char *>(lib->baseAddress) + (ptr - start);
ptr++;
}
@@ -116,6 +117,8 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
{
#ifdef PLATFORM_WINDOWS
/* Add this this library into the cache */
GetLibraryInfo(handle);
return GetProcAddress((HMODULE)handle, symbol);
#elif defined PLATFORM_LINUX
@@ -162,6 +165,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
}
}
/* Add this this library into the cache */
GetLibraryInfo((void *)dlmap->l_addr);
/* If we don't have a symbol table for this library, then create one */
if (table == NULL)
{
@@ -325,6 +331,9 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
/* Uh oh, we couldn't find a matching handle */
return NULL;
}
/* Add this this library into the cache */
GetLibraryInfo((void *)dlbase);
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
@@ -429,15 +438,17 @@ void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
#endif
}
bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
const DynLibInfo *MemoryUtils::GetLibraryInfo(const void *libPtr)
{
uintptr_t baseAddr;
if (libPtr == NULL)
{
return false;
return nullptr;
}
DynLibInfo lib;
#ifdef PLATFORM_WINDOWS
#ifdef PLATFORM_X86
@@ -456,7 +467,7 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION)))
{
return false;
return nullptr;
}
baseAddr = reinterpret_cast<uintptr_t>(info.AllocationBase);
@@ -470,19 +481,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
/* Check PE magic and signature */
if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != PE_NT_OPTIONAL_HDR_MAGIC)
{
return false;
return nullptr;
}
/* Check architecture */
if (file->Machine != PE_FILE_MACHINE)
{
return false;
return nullptr;
}
/* For our purposes, this must be a dynamic library */
if ((file->Characteristics & IMAGE_FILE_DLL) == 0)
{
return false;
return nullptr;
}
/* Finally, we can do this */
@@ -509,12 +520,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
if (!dladdr(libPtr, &info))
{
return false;
return nullptr;
}
if (!info.dli_fbase || !info.dli_fname)
{
return false;
return nullptr;
}
/* This is for our insane sanity checks :o */
@@ -524,31 +535,31 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
/* Check ELF magic */
if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
{
return false;
return nullptr;
}
/* Check ELF version */
if (file->e_ident[EI_VERSION] != EV_CURRENT)
{
return false;
return nullptr;
}
/* Check ELF endianness */
if (file->e_ident[EI_DATA] != ELFDATA2LSB)
{
return false;
return nullptr;
}
/* Check ELF architecture */
if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE)
{
return false;
return nullptr;
}
/* For our purposes, this must be a dynamic library/shared object */
if (file->e_type != ET_DYN)
{
return false;
return nullptr;
}
phdrCount = file->e_phnum;
@@ -598,12 +609,12 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
if (!dladdr(libPtr, &info))
{
return false;
return nullptr;
}
if (!info.dli_fbase || !info.dli_fname)
{
return false;
return nullptr;
}
/* This is for our insane sanity checks :o */
@@ -613,19 +624,19 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
/* Check Mach-O magic */
if (file->magic != MACH_MAGIC)
{
return false;
return nullptr;
}
/* Check architecture */
if (file->cputype != MACH_CPU_TYPE || file->cpusubtype != MACH_CPU_SUBTYPE)
{
return false;
return nullptr;
}
/* For our purposes, this must be a dynamic library */
if (file->filetype != MH_DYLIB)
{
return false;
return nullptr;
}
cmd_count = file->ncmds;
@@ -646,5 +657,17 @@ bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
lib.baseAddress = reinterpret_cast<void *>(baseAddr);
return true;
LibraryInfoMap::Insert i = m_InfoMap.findForAdd(lib.baseAddress);
if (i.found())
{
// We already loaded this binary before.
return &i->value;
}
// Keep a copy of the binary in its initial unpatched state for lookup.
lib.originalCopy = std::make_unique<char[]>(lib.memorySize);
memcpy(lib.originalCopy.get(), lib.baseAddress, lib.memorySize);
m_InfoMap.add(i, lib.baseAddress, std::move(lib));
return &i->value;
}
+6 -1
View File
@@ -32,6 +32,8 @@
#include "common_logic.h"
#include <IMemoryUtils.h>
#include <am-hashmap.h>
#include <memory>
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
#include <sh_vector.h>
#include "sm_symtable.h"
@@ -49,6 +51,7 @@ struct DynLibInfo
{
void *baseAddress;
size_t memorySize;
std::unique_ptr<char[]> originalCopy;
};
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
@@ -73,7 +76,7 @@ public: // IMemoryUtils
void *FindPattern(const void *libPtr, const char *pattern, size_t len);
void *ResolveSymbol(void *handle, const char *symbol);
public:
bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
const DynLibInfo *GetLibraryInfo(const void *libPtr);
#if defined PLATFORM_LINUX || defined PLATFORM_APPLE
private:
CVector<LibSymbolTable *> m_SymTables;
@@ -83,6 +86,8 @@ private:
SInt32 m_OSXMinor;
#endif
#endif
typedef ke::HashMap<void *, DynLibInfo, ke::PointerPolicy<void> > LibraryInfoMap;
LibraryInfoMap m_InfoMap;
};
extern MemoryUtils g_MemUtils;
+321
View File
@@ -0,0 +1,321 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2006-2015 AlliedModders LLC
//
// This file is part of SourcePawn. SourcePawn 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 3 of
// the License, or (at your option) any later version.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
//
#include <stdio.h>
#include <string.h>
#include "NativeInvoker.h"
/********************
* FUNCTION CALLING *
********************/
NativeInvoker::NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native)
: context_(pContext),
m_curparam(0),
m_errorstate(SP_ERROR_NONE),
native_(native)
{
}
NativeInvoker::~NativeInvoker()
{
Cancel();
}
bool
NativeInvoker::IsRunnable()
{
return true;
}
IPluginContext *
NativeInvoker::GetParentContext()
{
return context_;
}
int NativeInvoker::PushCell(cell_t cell)
{
if (m_curparam >= SP_MAX_EXEC_PARAMS)
return SetError(SP_ERROR_PARAMS_MAX);
m_info[m_curparam].marked = false;
m_params[m_curparam] = cell;
m_curparam++;
return SP_ERROR_NONE;
}
int
NativeInvoker::PushCellByRef(cell_t *cell, int flags)
{
return PushArray(cell, 1, flags);
}
int
NativeInvoker::PushFloat(float number)
{
cell_t val = sp::FloatCellUnion(number).cell;
return PushCell(val);
}
int
NativeInvoker::PushFloatByRef(float *number, int flags)
{
return PushCellByRef((cell_t *)number, flags);
}
int
NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback)
{
if (m_curparam >= SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
ParamInfo *info = &m_info[m_curparam];
info->flags = inarray ? copyback : 0;
info->marked = true;
info->size = cells;
info->str.is_sz = false;
info->orig_addr = inarray;
m_curparam++;
return SP_ERROR_NONE;
}
int
NativeInvoker::PushString(const char *string)
{
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
}
int
NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
{
return _PushString(buffer, sz_flags, cp_flags, length);
}
int
NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
{
if (m_curparam >= SP_MAX_EXEC_PARAMS)
return SetError(SP_ERROR_PARAMS_MAX);
ParamInfo *info = &m_info[m_curparam];
info->marked = true;
info->orig_addr = (cell_t *)string;
info->flags = cp_flags;
info->size = len;
info->str.sz_flags = sz_flags;
info->str.is_sz = true;
m_curparam++;
return SP_ERROR_NONE;
}
void
NativeInvoker::Cancel()
{
if (!m_curparam)
return;
m_errorstate = SP_ERROR_NONE;
m_curparam = 0;
}
int
NativeInvoker::Execute(cell_t *result, cell_t buffer, cell_t size)
{
context_->ClearLastNativeError();
// For backward compatibility, we have to clear the exception state.
// Otherwise code like this:
//
// static cell_t native(cx, params) {
// for (auto callback : callbacks) {
// callback->Execute();
// }
// }
//
// Could unintentionally leak a pending exception back to the caller,
// which wouldn't have happened before the Great Exception Refactoring.
SourcePawn::ExceptionHandler eh(context_);
eh.Debug(!size);
if (!Invoke(result)) {
if(size)
context_->StringToLocalUTF8(buffer, size, eh.Message(), NULL);
int Err = context_->GetLastNativeError();
context_->ClearLastNativeError();
return Err;
}
return SP_ERROR_NONE;
}
bool
NativeInvoker::Invoke(cell_t *result)
{
if (!IsRunnable()) {
Cancel();
context_->ReportErrorNumber(SP_ERROR_NOT_RUNNABLE);
return false;
}
if (int err = m_errorstate) {
Cancel();
context_->ReportErrorNumber(err);
return false;
}
//This is for re-entrancy!
cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
cell_t *temp_params = &_temp_params[1];
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
unsigned int numparams = m_curparam;
unsigned int i;
if (numparams)
{
//Save the info locally, then reset it for re-entrant calls.
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
}
m_curparam = 0;
/* Initialize 0th parameter */
_temp_params[0] = numparams;
/* Browse the parameters and build arrays */
bool ok = true;
for (i=0; i<numparams; i++) {
/* Is this marked as an array? */
if (temp_info[i].marked) {
if (!temp_info[i].str.is_sz) {
/* Allocate a normal/generic array */
int err = context_->HeapAlloc(
temp_info[i].size,
&(temp_info[i].local_addr),
&(temp_info[i].phys_addr));
if (err != SP_ERROR_NONE) {
context_->ReportErrorNumber(err);
ok = false;
break;
}
if (temp_info[i].orig_addr)
{
memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
}
} else {
/* Calculate cells required for the string */
size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
/* Allocate the buffer */
int err = context_->HeapAlloc(
cells,
&(temp_info[i].local_addr),
&(temp_info[i].phys_addr));
if (err != SP_ERROR_NONE) {
context_->ReportErrorNumber(err);
ok = false;
break;
}
/* Copy original string if necessary */
if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
{
/* Cut off UTF-8 properly */
if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) {
context_->StringToLocalUTF8(
temp_info[i].local_addr,
temp_info[i].size,
(const char *)temp_info[i].orig_addr,
NULL);
}
/* Copy a binary blob */
else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
{
memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
}
/* Copy ASCII characters */
else
{
context_->StringToLocal(
temp_info[i].local_addr,
temp_info[i].size,
(const char *)temp_info[i].orig_addr);
}
}
} /* End array/string calculation */
/* Update the pushed parameter with the byref local address */
temp_params[i] = temp_info[i].local_addr;
} else {
/* Just copy the value normally */
temp_params[i] = m_params[i];
}
}
/* Make the call if we can */
if (ok)
{
*result = native_->func()(context_, _temp_params);
}
/* i should be equal to the last valid parameter + 1 */
bool docopies = ok;
while (i--) {
if (!temp_info[i].marked)
continue;
if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) {
if (temp_info[i].orig_addr) {
if (temp_info[i].str.is_sz) {
memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
} else {
if (temp_info[i].size == 1) {
*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
} else {
memcpy(temp_info[i].orig_addr,
temp_info[i].phys_addr,
temp_info[i].size * sizeof(cell_t));
}
}
}
}
if (int err = context_->HeapPop(temp_info[i].local_addr))
context_->ReportErrorNumber(err);
}
return context_->GetLastNativeError() == SP_ERROR_NONE;
}
int
NativeInvoker::SetError(int err)
{
m_errorstate = err;
return err;
}
int NativeInvoker::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { return 0; }
funcid_t NativeInvoker::GetFunctionID() { return 0; }
int NativeInvoker::Execute2(IPluginContext *ctx, cell_t *result) { return 0; }
int NativeInvoker::CallFunction2(IPluginContext *ctx, const cell_t *params, unsigned int num_params, cell_t *result) { return 0; }
IPluginRuntime *NativeInvoker::GetParentRuntime() { return NULL; }
+79
View File
@@ -0,0 +1,79 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2006-2015 AlliedModders LLC
//
// This file is part of SourcePawn. SourcePawn 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 3 of
// the License, or (at your option) any later version.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
//
#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
#include <sp_vm_api.h>
#include <amtl/am-autoptr.h>
#include <amtl/am-refcounting.h>
#include "Native.h"
struct ParamInfo
{
int flags; /* Copy-back flags */
bool marked; /* Whether this is marked as being used */
cell_t local_addr; /* Local address to free */
cell_t *phys_addr; /* Physical address of our copy */
cell_t *orig_addr; /* Original address to copy back to */
ucell_t size; /* Size of array in bytes */
struct {
bool is_sz; /* is a string */
int sz_flags; /* has sz flags */
} str;
};
class NativeInvoker : public IPluginFunction
{
public:
NativeInvoker(IPluginContext *pContext, const ke::RefPtr<Native> &native);
virtual ~NativeInvoker();
public:
int PushCell(cell_t cell);
int PushCellByRef(cell_t *cell, int flags);
int PushFloat(float number);
int PushFloatByRef(float *number, int flags);
int PushArray(cell_t *inarray, unsigned int cells, int copyback);
int PushString(const char *string);
int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
int Execute(cell_t *result, cell_t buffer=0, cell_t size=0);
void Cancel();
int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result);
IPluginContext *GetParentContext();
bool Invoke(cell_t *result);
bool IsRunnable();
funcid_t GetFunctionID();
int Execute2(IPluginContext *ctx, cell_t *result);
int CallFunction2(IPluginContext *ctx,
const cell_t *params,
unsigned int num_params,
cell_t *result);
IPluginRuntime *GetParentRuntime();
const char *DebugName() {
return native_->name();
}
private:
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
int SetError(int err);
private:
IPluginContext *context_;
cell_t m_params[SP_MAX_EXEC_PARAMS];
ParamInfo m_info[SP_MAX_EXEC_PARAMS];
unsigned int m_curparam;
int m_errorstate;
ke::RefPtr<Native> native_;
};
#endif //_INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
+4 -2
View File
@@ -48,6 +48,8 @@
#include <bridge/include/IVEngineServerBridge.h>
#include <bridge/include/CoreProvider.h>
#define SOURCEMOD_PLUGINAPI_VERSION 7
CPluginManager g_PluginSys;
HandleType_t g_PluginType = 0;
IdentityType_t g_PluginIdent = 0;
@@ -309,12 +311,12 @@ bool CPlugin::ReadInfo()
base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
m_FileVersion = info->version;
if (m_FileVersion >= 4) {
if (m_FileVersion >= 5) {
base->LocalToString(info->date, (char **)&pDate);
base->LocalToString(info->time, (char **)&pTime);
ke::SafeSprintf(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
}
if (m_FileVersion > 5) {
if (m_FileVersion > SOURCEMOD_PLUGINAPI_VERSION) {
base->LocalToString(info->filevers, (char **)&pFileVers);
EvictWithError(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers);
return false;
+6 -4
View File
@@ -49,15 +49,17 @@ namespace SourceMod
{
struct IdentityToken_t
{
Handle_t ident;
void *ptr;
IdentityType_t type;
Handle_t ident = 0;
void *ptr = nullptr;
IdentityType_t type = 0;
size_t num_handles = 0;
bool warned_handle_usage = false;
};
};
struct IfaceInfo
{
bool operator ==(const IfaceInfo &info)
bool operator ==(const IfaceInfo &info) const
{
return (info.iface == iface && info.owner == owner);
}
+35
View File
@@ -56,6 +56,7 @@
#include "LibrarySys.h"
#include "RootConsoleMenu.h"
#include "CellArray.h"
#include "smn_entitylump.h"
#include <bridge/include/BridgeAPI.h>
#include <bridge/include/IProviderCallbacks.h>
@@ -89,6 +90,8 @@ CNativeOwner g_CoreNatives;
PseudoAddressManager pseudoAddr;
#endif
EntityLumpParseResult lastParseResult;
static void AddCorePhraseFile(const char *filename)
{
g_pCorePhrases->AddPhraseFile(filename);
@@ -135,6 +138,35 @@ static uint32_t ToPseudoAddress(void *addr)
#endif
}
static void SetEntityLumpWritable(bool writable)
{
g_bLumpAvailableForWriting = writable;
// write-lock causes the map entities to be serialized out to string
if (!writable)
{
g_strMapEntities = lumpmanager->Dump();
}
}
static bool ParseEntityLumpString(const char *pMapEntities, int &status, size_t &position)
{
lastParseResult = lumpmanager->Parse(pMapEntities);
status = static_cast<int>(lastParseResult.m_Status);
position = static_cast<size_t>(lastParseResult.m_Position);
return lastParseResult;
}
// returns nullptr if the original lump failed to parse
static const char* GetEntityLumpString()
{
if (!lastParseResult)
{
return nullptr;
}
return g_strMapEntities.c_str();
}
// Defined in smn_filesystem.cpp.
extern bool OnLogPrint(const char *msg);
@@ -170,6 +202,9 @@ static sm_logic_t logic =
CellArray::Free,
FromPseudoAddress,
ToPseudoAddress,
SetEntityLumpWritable,
ParseEntityLumpString,
GetEntityLumpString,
&g_PluginSys,
&g_ShareSys,
&g_Extensions,
+1 -1
View File
@@ -89,6 +89,6 @@ unsigned int UTIL_CRC32(const void *pdata, size_t data_length)
crc = CRCTable[c] ^ (crc >> 8);
}
return crc;
return ~crc;
}
+77 -7
View File
@@ -75,7 +75,11 @@ static cell_t CreateArray(IPluginContext *pContext, const cell_t *params)
if (params[2])
{
array->resize(params[2]);
if (!array->resize(params[2]))
{
delete array;
return pContext->ThrowNativeError("Failed to resize array to startsize \"%u\".", params[2]);
}
}
Handle_t hndl = handlesys->CreateHandle(htCellArray, array, pContext->GetIdentity(), g_pCoreIdent, NULL);
@@ -277,7 +281,19 @@ static cell_t GetArrayString(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
}
cell_t *blk = array->at(idx);
// the blocknumber is not guaranteed to always be passed
size_t blocknumber = 0;
if (params[0] >= 5)
{
blocknumber = (size_t)params[5];
}
if (blocknumber >= array->blocksize())
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
}
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
size_t numWritten = 0;
pContext->StringToLocalUTF8(params[3], params[4], (char *)blk, &numWritten);
@@ -303,7 +319,19 @@ static cell_t GetArrayArray(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
}
cell_t *blk = array->at(idx);
// the blocknumber is not guaranteed to always be passed
size_t blocknumber = 0;
if (params[0] >= 5)
{
blocknumber = (size_t)params[5];
}
if (blocknumber >= array->blocksize())
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
}
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
size_t indexes = array->blocksize();
if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
{
@@ -375,12 +403,30 @@ static cell_t SetArrayString(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
}
cell_t *blk = array->at(idx);
// the blocknumber is not guaranteed to always be passed
size_t blocknumber = 0;
if (params[0] >= 5)
{
blocknumber = (size_t)params[5];
}
if (blocknumber >= array->blocksize())
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
}
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
char *str;
pContext->LocalToString(params[3], &str);
return strncopy((char *)blk, str, array->blocksize() * sizeof(cell_t));
size_t maxlength = array->blocksize() * sizeof(cell_t);
if (params[0] >= 4 && params[4] != -1 && (size_t)params[4] <= array->blocksize())
{
maxlength = (size_t)params[4];
}
return strncopy((char*)blk, str, maxlength);
}
static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
@@ -401,7 +447,19 @@ static cell_t SetArrayArray(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid index %d (count: %d)", idx, array->size());
}
cell_t *blk = array->at(idx);
// the blocknumber is not guaranteed to always be passed
size_t blocknumber = 0;
if (params[0] >= 5)
{
blocknumber = (size_t)params[5];
}
if (blocknumber >= array->blocksize())
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
}
cell_t *blk = &array->base()[idx * array->blocksize() + blocknumber];
size_t indexes = array->blocksize();
if (params[4] != -1 && (size_t)params[4] <= array->blocksize())
{
@@ -529,12 +587,24 @@ static cell_t FindStringInArray(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}
// the blocknumber is not guaranteed to always be passed
size_t blocknumber = 0;
if (params[0] >= 3)
{
blocknumber = (size_t)params[3];
}
if (blocknumber >= array->blocksize())
{
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", blocknumber, array->blocksize());
}
char *str;
pContext->LocalToString(params[2], &str);
for (unsigned int i = 0; i < array->size(); i++)
{
const char *array_str = (const char *)array->at(i);
const char *array_str = (const char *)&array->base()[i * array->blocksize() + blocknumber];
if (strcmp(str, array_str) == 0)
{
return (cell_t) i;
+110 -4
View File
@@ -83,6 +83,22 @@ static cell_t CreateStack(IPluginContext *pContext, const cell_t *params)
return hndl;
}
static cell_t ClearStack(IPluginContext *pContext, const cell_t *params)
{
CellArray *array;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array)) != HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}
array->clear();
return 1;
}
static cell_t CloneStack(IPluginContext *pContext, const cell_t *params)
{
CellArray *oldArray;
@@ -224,9 +240,9 @@ static cell_t PopStackCell(IPluginContext *pContext, const cell_t *params)
}
else
{
if (idx >= array->blocksize() * 4)
if (idx >= array->blocksize() * sizeof(cell_t))
{
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
}
*buffer = (cell_t)*((char *)blk + idx);
}
@@ -340,8 +356,8 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
rval = blk[idx];
} else {
if (idx >= array->blocksize() * 4)
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * 4);
if (idx >= array->blocksize() * sizeof(cell_t))
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
rval = (cell_t)*((char *)blk + idx);
}
@@ -349,6 +365,32 @@ static cell_t ArrayStack_Pop(IPluginContext *pContext, const cell_t *params)
return rval;
}
static cell_t ArrayStack_Top(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
if (!array.Ok())
return 0;
if (array->size() == 0)
return pContext->ThrowNativeError("stack is empty");
cell_t *blk = array->at(array->size() - 1);
size_t idx = (size_t)params[2];
cell_t rval;
if (params[3] == 0) {
if (idx >= array->blocksize())
return pContext->ThrowNativeError("Invalid block %d (blocksize: %d)", idx, array->blocksize());
rval = blk[idx];
} else {
if (idx >= array->blocksize() * sizeof(cell_t))
return pContext->ThrowNativeError("Invalid byte %d (blocksize: %d bytes)", idx, array->blocksize() * sizeof(cell_t));
rval = (cell_t)*((char *)blk + idx);
}
return rval;
}
static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
@@ -371,6 +413,27 @@ static cell_t ArrayStack_PopString(IPluginContext *pContext, const cell_t *param
return 1;
}
static cell_t ArrayStack_TopString(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
if (!array.Ok())
return 0;
if (array->size() == 0)
return pContext->ThrowNativeError("stack is empty");
size_t idx = array->size() - 1;
cell_t *blk = array->at(idx);
cell_t *pWritten;
pContext->LocalToPhysAddr(params[4], &pWritten);
size_t numWritten;
pContext->StringToLocalUTF8(params[2], params[3], (char *)blk, &numWritten);
*pWritten = (cell_t)numWritten;
return 1;
}
static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
@@ -395,6 +458,29 @@ static cell_t ArrayStack_PopArray(IPluginContext *pContext, const cell_t *params
return 0;
}
static cell_t ArrayStack_TopArray(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<CellArray> array(pContext, params[1], htCellStack);
if (!array.Ok())
return 0;
if (array->size() == 0)
return pContext->ThrowNativeError("stack is empty");
cell_t *addr;
pContext->LocalToPhysAddr(params[2], &addr);
size_t idx = array->size() - 1;
cell_t *blk = array->at(idx);
size_t indexes = array->blocksize();
if (params[3] != -1 && (size_t)params[3] <= array->blocksize())
indexes = params[3];
memcpy(addr, blk, sizeof(cell_t) * indexes);
return 0;
}
static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
@@ -410,6 +496,21 @@ static cell_t GetStackBlockSize(IPluginContext *pContext, const cell_t *params)
return array->blocksize();
}
static cell_t GetStackSize(IPluginContext *pContext, const cell_t *params)
{
HandleError err;
CellArray *array;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], htCellStack, &sec, (void **)&array))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
}
return array->size();
}
REGISTER_NATIVES(cellStackNatives)
{
{"CreateStack", CreateStack},
@@ -425,15 +526,20 @@ REGISTER_NATIVES(cellStackNatives)
// Transitional syntax support.
{"ArrayStack.ArrayStack", CreateStack},
{"ArrayStack.Clear", ClearStack},
{"ArrayStack.Clone", CloneStack},
{"ArrayStack.Pop", ArrayStack_Pop},
{"ArrayStack.Top", ArrayStack_Top},
{"ArrayStack.PopString", ArrayStack_PopString},
{"ArrayStack.TopString", ArrayStack_TopString},
{"ArrayStack.PopArray", ArrayStack_PopArray},
{"ArrayStack.TopArray", ArrayStack_TopArray},
{"ArrayStack.Push", PushStackCell},
{"ArrayStack.PushString", PushStackString},
{"ArrayStack.PushArray", PushStackArray},
{"ArrayStack.Empty.get", IsStackEmpty},
{"ArrayStack.BlockSize.get", GetStackBlockSize},
{"ArrayStack.Length.get", GetStackSize},
{NULL, NULL},
};
+173 -2
View File
@@ -32,6 +32,9 @@
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <iomanip>
#include <sstream>
#include <list>
#include "common_logic.h"
#include "Logger.h"
@@ -56,6 +59,7 @@
#include <bridge/include/CoreProvider.h>
#include <bridge/include/IScriptManager.h>
#include <bridge/include/IExtensionBridge.h>
#include <sh_vector.h>
using namespace SourceMod;
using namespace SourcePawn;
@@ -114,6 +118,71 @@ public:
}
} g_CoreNativeHelpers;
/**
* @brief Nearly identical to the standard core plugin iterator
* with one key difference. Next doesn't increment the counter
* the first time it is ran. This is a hack for the methodmap..
*/
class CMMPluginIterator
: public IPluginIterator,
public IPluginsListener
{
public:
CMMPluginIterator(const CVector<SMPlugin *> *list)
: m_hasStarted(false)
{
for(auto iter = list->begin(); iter != list->end(); ++iter) {
m_list.push_back(*iter);
}
scripts->FreePluginList(list);
m_current = m_list.begin();
scripts->AddPluginsListener(this);
}
virtual ~CMMPluginIterator()
{
scripts->RemovePluginsListener(this);
}
virtual bool MorePlugins() override
{
return (m_current != m_list.end());
}
virtual IPlugin *GetPlugin() override
{
return *m_current;
}
virtual void NextPlugin() override
{
if(!m_hasStarted)
{
m_hasStarted = true;
return;
}
m_current++;
}
virtual void Release() override
{
delete this;
}
public:
virtual void OnPluginDestroyed(IPlugin *plugin) override
{
if (*m_current == plugin)
m_current = m_list.erase(m_current);
else
m_list.remove(static_cast<SMPlugin *>(plugin));
}
private:
std::list<SMPlugin *> m_list;
std::list<SMPlugin *>::iterator m_current;
bool m_hasStarted;
};
void LogAction(Handle_t hndl, int type, int client, int target, const char *message)
{
if (g_OnLogAction->GetFunctionCount())
@@ -146,7 +215,7 @@ void LogAction(Handle_t hndl, int type, int client, int target, const char *mess
g_Logger.LogMessage("[%s] %s", logtag, message);
}
static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
{
char buffer[512];
@@ -206,6 +275,49 @@ static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
return 1;
}
static int ParseTime(IPluginContext *pContext, const cell_t *params)
{
char *datetime;
char *format;
pContext->LocalToStringNULL(params[1], &datetime);
pContext->LocalToStringNULL(params[2], &format);
if (format == NULL)
{
format = const_cast<char *>(bridge->GetCvarString(g_datetime_format));
}
else if (!format[0])
{
return pContext->ThrowNativeError("Time format string cannot be empty.");
}
if (!datetime || !datetime[0])
{
return pContext->ThrowNativeError("Date/time string cannot be empty.");
}
// https://stackoverflow.com/a/33542189
std::tm t{};
std::istringstream input(datetime);
auto previousLocale = input.imbue(std::locale::classic());
input >> std::get_time(&t, format);
bool failed = input.fail();
input.imbue(previousLocale);
if (failed)
{
return pContext->ThrowNativeError("Invalid date/time string or time format.");
}
#if defined PLATFORM_WINDOWS
return _mkgmtime(&t);
#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE
return timegm(&t);
#else
return pContext->ThrowNativeError("Platform has no implemented UTC conversion for std::tm to std::time_t");
#endif
}
static cell_t GetPluginIterator(IPluginContext *pContext, const cell_t *params)
{
IPluginIterator *iter = scripts->GetPluginIterator();
@@ -264,6 +376,60 @@ static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params)
return pPlugin->GetMyHandle();
}
static cell_t PluginIterator_Create(IPluginContext *pContext, const cell_t *params)
{
IPluginIterator *iter = new CMMPluginIterator(scripts->ListPlugins());
Handle_t hndl = handlesys->CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
if (hndl == BAD_HANDLE)
{
iter->Release();
}
return hndl;
}
static cell_t PluginIterator_Next(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleSecurity sec{pContext->GetIdentity(), g_pCoreIdent};
HandleError err{};
IPluginIterator *pIter = nullptr;
if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
}
if(!pIter->MorePlugins())
return 0;
pIter->NextPlugin();
return 1;
}
static cell_t PluginIterator_Plugin_get(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = (Handle_t)params[1];
HandleSecurity sec{pContext->GetIdentity(), g_pCoreIdent};
HandleError err{};
IPluginIterator *pIter = nullptr;
if ((err=handlesys->ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
{
return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
}
IPlugin *pPlugin = pIter->GetPlugin();
if (!pPlugin)
{
return BAD_HANDLE;
}
return pPlugin->GetMyHandle();
}
IPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl)
{
if (hndl == BAD_HANDLE)
@@ -967,9 +1133,10 @@ REGISTER_NATIVES(coreNatives)
{"ThrowError", ThrowError},
{"GetTime", GetTime},
{"FormatTime", FormatTime},
{"ParseTime", ParseTime},
{"GetPluginIterator", GetPluginIterator},
{"MorePlugins", MorePlugins},
{"ReadPlugin", ReadPlugin},
{"ReadPlugin", ReadPlugin},
{"GetPluginStatus", GetPluginStatus},
{"GetPluginFilename", GetPluginFilename},
{"IsPluginDebugging", IsPluginDebugging},
@@ -1000,5 +1167,9 @@ REGISTER_NATIVES(coreNatives)
{"FrameIterator.LineNumber.get", FrameIterator_LineNumber},
{"FrameIterator.GetFunctionName", FrameIterator_GetFunctionName},
{"FrameIterator.GetFilePath", FrameIterator_GetFilePath},
{"PluginIterator.PluginIterator", PluginIterator_Create},
{"PluginIterator.Next", PluginIterator_Next},
{"PluginIterator.Plugin.get", PluginIterator_Plugin_get},
{NULL, NULL},
};
+4 -4
View File
@@ -1787,10 +1787,10 @@ static cell_t SQL_ExecuteTransaction(IPluginContext *pContext, const cell_t *par
IPluginFunction *onSuccess = NULL;
IPluginFunction *onError = NULL;
if (params[3] != -1 && ((onSuccess = pContext->GetFunctionById(params[3])) == NULL))
return pContext->ThrowNativeError("Function id %x is invalid", params[3]);
if (params[4] != -1 && ((onError = pContext->GetFunctionById(params[4])) == NULL))
return pContext->ThrowNativeError("Function id %x is invalid", params[4]);
if (!pContext->GetFunctionByIdOrNull(params[3], &onSuccess))
return 0;
if (!pContext->GetFunctionByIdOrNull(params[4], &onError))
return 0;
cell_t data = params[5];
PrioQueueLevel priority = PrioQueue_Normal;
+19 -2
View File
@@ -244,7 +244,19 @@ static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *para
pDataPack->RemoveItem();
}
pDataPack->PackFunction(params[2]);
cell_t funcid = params[2];
if (pContext->IsNullFunctionId(funcid))
{
pDataPack->PackFunction(0);
}
else if (funcid <= 0)
{
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
}
else
{
pDataPack->PackFunction(funcid);
}
return 1;
}
@@ -365,7 +377,12 @@ static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *param
return pContext->ThrowNativeError("Invalid data pack type (got %d / expected %d).", pDataPack->GetCurrentType(), CDataPackType::Function);
}
return pDataPack->ReadFunction();
cell_t funcid = pDataPack->ReadFunction();
if (!funcid)
{
return pContext->GetNullFunctionValue();
}
return funcid;
}
static cell_t smn_ReadPackCellArray(IPluginContext *pContext, const cell_t *params)
+367
View File
@@ -0,0 +1,367 @@
/**
* vim: set ts=4 :
* =============================================================================
* Entity Lump Manager
* Copyright (C) 2021-2022 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include "HandleSys.h"
#include "common_logic.h"
#include "LumpManager.h"
#include <algorithm>
HandleType_t g_EntityLumpEntryType;
std::string g_strMapEntities;
bool g_bLumpAvailableForWriting = false;
static EntityLumpManager s_LumpManager;
EntityLumpManager *lumpmanager = &s_LumpManager;
class LumpManagerNatives :
public IHandleTypeDispatch,
public SMGlobalClass
{
public: //SMGlobalClass
void OnSourceModAllInitialized()
{
g_EntityLumpEntryType = handlesys->CreateType("EntityLumpEntry", this, 0, NULL, NULL, g_pCoreIdent, NULL);
}
void OnSourceModShutdown()
{
handlesys->RemoveType(g_EntityLumpEntryType, g_pCoreIdent);
}
public: //IHandleTypeDispatch
void OnHandleDestroy(HandleType_t type, void* object)
{
if (type == g_EntityLumpEntryType)
{
delete reinterpret_cast<std::weak_ptr<EntityLumpEntry>*>(object);
}
}
};
static LumpManagerNatives s_LumpManagerNatives;
cell_t sm_LumpManagerGet(IPluginContext *pContext, const cell_t *params) {
int index = params[1];
if (index < 0 || index >= static_cast<int>(lumpmanager->Length())) {
return pContext->ThrowNativeError("Invalid index %d", index);
}
std::weak_ptr<EntityLumpEntry>* pReference = new std::weak_ptr<EntityLumpEntry>;
*pReference = lumpmanager->Get(index);
return handlesys->CreateHandle(g_EntityLumpEntryType, pReference,
pContext->GetIdentity(), g_pCoreIdent, NULL);
}
cell_t sm_LumpManagerErase(IPluginContext *pContext, const cell_t *params) {
if (!g_bLumpAvailableForWriting) {
return pContext->ThrowNativeError("Cannot use EntityLump.Erase() outside of OnMapInit");
}
int index = params[1];
if (index < 0 || index >= static_cast<int>(lumpmanager->Length())) {
return pContext->ThrowNativeError("Invalid index %d", index);
}
lumpmanager->Erase(index);
return 0;
}
cell_t sm_LumpManagerInsert(IPluginContext *pContext, const cell_t *params) {
if (!g_bLumpAvailableForWriting) {
return pContext->ThrowNativeError("Cannot use EntityLump.Insert() outside of OnMapInit");
}
int index = params[1];
if (index < 0 || index > static_cast<int>(lumpmanager->Length())) {
return pContext->ThrowNativeError("Invalid index %d", index);
}
lumpmanager->Insert(index);
return 0;
}
cell_t sm_LumpManagerAppend(IPluginContext *pContext, const cell_t *params) {
if (!g_bLumpAvailableForWriting) {
return pContext->ThrowNativeError("Cannot use EntityLump.Append() outside of OnMapInit");
}
return lumpmanager->Append();
}
cell_t sm_LumpManagerLength(IPluginContext *pContext, const cell_t *params) {
return lumpmanager->Length();
}
cell_t sm_LumpEntryGet(IPluginContext *pContext, const cell_t *params) {
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
HandleError err;
Handle_t hndl = static_cast<Handle_t>(params[1]);
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
}
if (entryref->expired()) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
}
auto entry = entryref->lock();
int index = params[2];
if (index < 0 || index >= static_cast<int>(entry->size())) {
return pContext->ThrowNativeError("Invalid index %d", index);
}
const auto& pair = (*entry)[index];
size_t nBytes;
pContext->StringToLocalUTF8(params[3], params[4], pair.first.c_str(), &nBytes);
pContext->StringToLocalUTF8(params[5], params[6], pair.second.c_str(), &nBytes);
return 0;
}
cell_t sm_LumpEntryUpdate(IPluginContext *pContext, const cell_t *params) {
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
HandleError err;
Handle_t hndl = static_cast<Handle_t>(params[1]);
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
}
if (entryref->expired()) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
}
if (!g_bLumpAvailableForWriting) {
return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Update() outside of OnMapInit");
}
auto entry = entryref->lock();
int index = params[2];
if (index < 0 || index >= static_cast<int>(entry->size())) {
return pContext->ThrowNativeError("Invalid index %d", index);
}
char *key, *value;
pContext->LocalToStringNULL(params[3], &key);
pContext->LocalToStringNULL(params[4], &value);
auto& pair = (*entry)[index];
if (key != nullptr) {
pair.first = key;
}
if (value != nullptr) {
pair.second = value;
}
return 0;
}
cell_t sm_LumpEntryInsert(IPluginContext *pContext, const cell_t *params) {
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
HandleError err;
Handle_t hndl = static_cast<Handle_t>(params[1]);
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
}
if (entryref->expired()) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
}
if (!g_bLumpAvailableForWriting) {
return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Insert() outside of OnMapInit");
}
auto entry = entryref->lock();
int index = params[2];
if (index < 0 || index > static_cast<int>(entry->size())) {
return pContext->ThrowNativeError("Invalid index %d", index);
}
char *key, *value;
pContext->LocalToString(params[3], &key);
pContext->LocalToString(params[4], &value);
entry->emplace(entry->begin() + index, key, value);
return 0;
}
cell_t sm_LumpEntryErase(IPluginContext *pContext, const cell_t *params) {
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
HandleError err;
Handle_t hndl = static_cast<Handle_t>(params[1]);
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
}
if (entryref->expired()) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
}
if (!g_bLumpAvailableForWriting) {
return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Erase() outside of OnMapInit");
}
auto entry = entryref->lock();
int index = params[2];
if (index < 0 || index >= static_cast<int>(entry->size())) {
return pContext->ThrowNativeError("Invalid index %d", index);
}
entry->erase(entry->begin() + index);
return 0;
}
cell_t sm_LumpEntryAppend(IPluginContext *pContext, const cell_t *params) {
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
HandleError err;
Handle_t hndl = static_cast<Handle_t>(params[1]);
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
}
if (entryref->expired()) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
}
if (!g_bLumpAvailableForWriting) {
return pContext->ThrowNativeError("Cannot use EntityLumpEntry.Append() outside of OnMapInit");
}
auto entry = entryref->lock();
char *key, *value;
pContext->LocalToString(params[2], &key);
pContext->LocalToString(params[3], &value);
entry->emplace_back(key, value);
return 0;
}
cell_t sm_LumpEntryFindKey(IPluginContext *pContext, const cell_t *params) {
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
HandleError err;
Handle_t hndl = static_cast<Handle_t>(params[1]);
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
}
if (entryref->expired()) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
}
// start from the index after the current one
int start = params[3] + 1;
auto entry = entryref->lock();
if (start < 0 || start >= static_cast<int>(entry->size())) {
return -1;
}
char *key;
pContext->LocalToString(params[2], &key);
auto matches_key = [&key](std::pair<std::string,std::string> pair) {
return pair.first == key;
};
auto result = std::find_if(entry->begin() + start, entry->end(), matches_key);
if (result == entry->end()) {
return -1;
}
return std::distance(entry->begin(), result);
}
cell_t sm_LumpEntryLength(IPluginContext *pContext, const cell_t *params) {
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
HandleError err;
Handle_t hndl = static_cast<Handle_t>(params[1]);
std::weak_ptr<EntityLumpEntry>* entryref = nullptr;
if ((err = handlesys->ReadHandle(hndl, g_EntityLumpEntryType, &sec, (void**) &entryref)) != HandleError_None) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (error: %d)", hndl, err);
}
if (entryref->expired()) {
return pContext->ThrowNativeError("Invalid EntityLumpEntry handle %x (reference expired)", hndl);
}
auto entry = entryref->lock();
return entry->size();
}
REGISTER_NATIVES(entityLumpNatives)
{
{ "EntityLump.Get", sm_LumpManagerGet },
{ "EntityLump.Erase", sm_LumpManagerErase },
{ "EntityLump.Insert", sm_LumpManagerInsert },
{ "EntityLump.Append", sm_LumpManagerAppend },
{ "EntityLump.Length", sm_LumpManagerLength },
{ "EntityLumpEntry.Get", sm_LumpEntryGet },
{ "EntityLumpEntry.Update", sm_LumpEntryUpdate },
{ "EntityLumpEntry.Insert", sm_LumpEntryInsert },
{ "EntityLumpEntry.Erase", sm_LumpEntryErase },
{ "EntityLumpEntry.Append", sm_LumpEntryAppend },
{ "EntityLumpEntry.FindKey", sm_LumpEntryFindKey },
{ "EntityLumpEntry.Length.get", sm_LumpEntryLength },
{NULL, NULL}
};
+44
View File
@@ -0,0 +1,44 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourceMod
* Copyright (C) 2022-2022 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_ENTITYLUMP_H_
#define _INCLUDE_SOURCEMOD_ENTITYLUMP_H_
#include <IHandleSys.h>
#include "LumpManager.h"
using namespace SourceMod;
extern std::string g_strMapEntities;
extern bool g_bLumpAvailableForWriting;
extern EntityLumpManager *lumpmanager;
#endif // _INCLUDE_SOURCEMOD_ENTITYLUMP_H_
+29 -2
View File
@@ -366,6 +366,33 @@ static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
return SP_ERROR_NONE;
}
static cell_t GetNativeFunction(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
cell_t funcid = s_curparams[param];
if (s_curcaller->IsNullFunctionId(funcid))
{
// see alliedmodders/sourcepawn#912, alliedmodders/sourcemod#2068
// convert null function to receiver's expected value so equality checks against INVALID_FUNCTION pass
return pContext->GetNullFunctionValue();
}
else if (funcid <= 0)
{
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
}
return funcid;
}
static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
@@ -414,7 +441,7 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
DetectExceptions eh(pContext);
written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
if (eh.HasException())
return 0;
return pContext->GetLastNativeError();
}
cell_t *addr;
@@ -483,7 +510,7 @@ REGISTER_NATIVES(nativeNatives)
{"GetNativeArray", GetNativeArray},
{"GetNativeCell", GetNativeCell},
{"GetNativeCellRef", GetNativeCellRef},
{"GetNativeFunction", GetNativeCell},
{"GetNativeFunction", GetNativeFunction},
{"GetNativeString", GetNativeString},
{"GetNativeStringLength", GetNativeStringLength},
{"FormatNativeString", FormatNativeString},
+78 -1
View File
@@ -73,6 +73,7 @@ class FileObject
public:
virtual ~FileObject()
{}
virtual size_t Size() = 0;
virtual size_t Read(void *pOut, int size) = 0;
virtual char *ReadLine(char *pOut, int size) = 0;
virtual size_t Write(const void *pData, int size) = 0;
@@ -119,6 +120,10 @@ public:
return true;
}
size_t Size() override {
return (size_t)bridge->filesystem->Size(handle_);
}
size_t Read(void *pOut, int size) override {
return (size_t)bridge->filesystem->Read(pOut, size, handle_);
}
@@ -183,6 +188,30 @@ public:
return unlink(path) == 0;
}
size_t Size() override {
#ifdef PLATFORM_WINDOWS
struct _stat s;
int fd = _fileno(fp_);
if (fd == -1)
return -1;
if (_fstat(fd, &s) != 0)
return -1;
if (s.st_mode & S_IFREG)
return static_cast<size_t>(s.st_size);
return -1;
#elif defined PLATFORM_POSIX
struct stat s;
int fd = fileno(fp_);
if (fd == -1)
return -1;
if (fstat(fd, &s) != 0)
return -1;
if (S_ISREG(s.st_mode))
return static_cast<size_t>(s.st_size);
return -1;
#endif
}
size_t Read(void *pOut, int size) override {
return fread(pOut, 1, size, fp_);
}
@@ -288,6 +317,10 @@ public:
}
virtual bool LogPrint(const char *msg)
{
if (!g_pLogHook) {
return false;
}
cell_t result = 0;
g_pLogHook->PushString(msg);
g_pLogHook->Execute(&result);
@@ -610,7 +643,7 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
g_pSM->BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
#ifdef PLATFORM_WINDOWS
return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
return (MoveFileExA(old_realpath, new_realpath, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) ? 1 : 0;
#elif defined PLATFORM_POSIX
return (rename(old_realpath, new_realpath)) ? 0 : 1;
#endif
@@ -722,6 +755,39 @@ static cell_t sm_SetFilePermissions(IPluginContext *pContext, const cell_t *para
#endif
}
static cell_t sm_GetFilePermissions(IPluginContext *pContext, const cell_t *params)
{
char *name;
char realpath[PLATFORM_MAX_PATH];
pContext->LocalToString(params[1], &name);
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
cell_t *mask;
pContext->LocalToPhysAddr(params[2], &mask);
#if defined PLATFORM_WINDOWS
struct _stat buffer;
cell_t valid = _stat(realpath, &buffer) == 0;
if ((buffer.st_mode & _S_IREAD) != 0) {
*mask |= (FPERM_U_READ|FPERM_G_READ|FPERM_O_READ)|(FPERM_U_EXEC|FPERM_G_EXEC|FPERM_O_EXEC);
}
if ((buffer.st_mode & _S_IWRITE) != 0) {
*mask |= (FPERM_U_WRITE|FPERM_G_WRITE|FPERM_O_WRITE);
}
return valid;
#else
struct stat buffer;
cell_t valid = stat(realpath, &buffer) == 0;
*mask = buffer.st_mode;
return valid;
#endif
}
static cell_t sm_CreateDirectory(IPluginContext *pContext, const cell_t *params)
{
char *name;
@@ -1125,6 +1191,15 @@ static cell_t sm_RemoveGameLogHook(IPluginContext *pContext, const cell_t *param
return 1;
}
static cell_t File_Size(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<FileObject> file(pContext, params[1], g_FileType);
if (!file.Ok())
return -1;
return file->Size();
}
template <typename T>
static cell_t File_ReadTyped(IPluginContext *pContext, const cell_t *params)
{
@@ -1186,6 +1261,7 @@ REGISTER_NATIVES(filesystem)
{"RemoveGameLogHook", sm_RemoveGameLogHook},
{"CreateDirectory", sm_CreateDirectory},
{"SetFilePermissions", sm_SetFilePermissions},
{"GetFilePermissions", sm_GetFilePermissions},
{"File.ReadLine", sm_ReadFileLine},
{"File.Read", sm_ReadFile},
@@ -1197,6 +1273,7 @@ REGISTER_NATIVES(filesystem)
{"File.Seek", sm_FileSeek},
{"File.Flush", sm_FlushFile},
{"File.Position.get", sm_FilePosition},
{"File.Size", File_Size},
{"File.ReadInt8", File_ReadTyped<int8_t>},
{"File.ReadUint8", File_ReadTyped<uint8_t>},
{"File.ReadInt16", File_ReadTyped<int16_t>},
+13
View File
@@ -231,6 +231,13 @@ static cell_t sm_FloatFraction(IPluginContext *pCtx, const cell_t *params)
return sp_ftoc(val);
}
static cell_t sm_FloatMod(IPluginContext* pCtx, const cell_t* params)
{
float val = fmodf(sp_ctof(params[1]), sp_ctof(params[2]));
return sp_ftoc(val);
}
static cell_t sm_Sine(IPluginContext *pCtx, const cell_t *params)
{
float val = sp_ctof(params[1]);
@@ -358,10 +365,16 @@ REGISTER_NATIVES(floatnatives)
{"FloatAdd", sm_FloatAdd},
{"FloatSub", sm_FloatSub},
{"FloatFraction", sm_FloatFraction},
{"FloatMod", sm_FloatMod},
{"RoundToZero", sm_RoundToZero},
{"RoundToCeil", sm_RoundToCeil},
{"RoundToFloor", sm_RoundToFloor},
{"RoundToNearest", sm_RoundToNearest},
{"__FLOAT_MUL__", sm_FloatMul},
{"__FLOAT_DIV__", sm_FloatDiv},
{"__FLOAT_ADD__", sm_FloatAdd},
{"__FLOAT_SUB__", sm_FloatSub},
{"__FLOAT_MOD__", sm_FloatMod},
{"__FLOAT_GT__", sm_FloatGt},
{"__FLOAT_GE__", sm_FloatGe},
{"__FLOAT_LT__", sm_FloatLt},
+88 -13
View File
@@ -8,7 +8,7 @@
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@@ -36,6 +36,9 @@
#include <IHandleSys.h>
#include <IForwardSys.h>
#include <ISourceMod.h>
#include <amtl/am-autoptr.h>
#include "ShareSys.h"
#include "NativeInvoker.h"
HandleType_t g_GlobalFwdType = 0;
HandleType_t g_PrivateFwdType = 0;
@@ -44,8 +47,9 @@ static bool s_CallStarted = false;
static ICallable *s_pCallable = NULL;
static IPluginFunction *s_pFunction = NULL;
static IForward *s_pForward = NULL;
static NativeInvoker *s_pInvoker = NULL;
class ForwardNativeHelpers :
class ForwardNativeHelpers :
public SMGlobalClass,
public IHandleTypeDispatch
{
@@ -103,6 +107,9 @@ inline void ResetCall()
s_pFunction = NULL;
s_pForward = NULL;
s_pCallable = NULL;
if(s_pInvoker)
delete s_pInvoker;
s_pInvoker = NULL;
}
static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *params)
@@ -131,7 +138,7 @@ static cell_t sm_GetFunctionByName(IPluginContext *pContext, const cell_t *param
if (pPlugin->GetBaseContext()->FindPublicByName(name, &idx) == SP_ERROR_NOT_FOUND)
{
/* Return INVALID_FUNCTION if not found */
return -1;
return pContext->GetNullFunctionValue();
}
/* Return function ID */
@@ -148,7 +155,7 @@ static cell_t sm_CreateGlobalForward(IPluginContext *pContext, const cell_t *par
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAMS_MAX, NULL);
}
pContext->LocalToString(params[1], &name);
cell_t *addr;
@@ -228,11 +235,15 @@ static cell_t sm_AddToForward(IPluginContext *pContext, const cell_t *params)
}
}
IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
cell_t funcid = params[3];
if (funcid <= 0)
{
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
}
IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(funcid);
if (!pFunction)
{
return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
}
return pForward->AddFunction(pFunction);
@@ -265,11 +276,15 @@ static cell_t sm_RemoveFromForward(IPluginContext *pContext, const cell_t *param
}
}
IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[3]);
cell_t funcid = params[3];
if (funcid <= 0)
{
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
}
IPluginFunction *pFunction = pPlugin->GetBaseContext()->GetFunctionById(funcid);
if (!pFunction)
{
return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
}
return pForward->RemoveFunction(pFunction);
@@ -327,11 +342,15 @@ static cell_t sm_CallStartFunction(IPluginContext *pContext, const cell_t *param
}
}
s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(params[2]);
cell_t funcid = params[2];
if (funcid <= 0)
{
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
}
s_pFunction = pPlugin->GetBaseContext()->GetFunctionById(funcid);
if (!s_pFunction)
{
return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
return pContext->ThrowNativeError("Invalid function id (%X)", funcid);
}
s_pCallable = static_cast<ICallable *>(s_pFunction);
@@ -367,6 +386,27 @@ static cell_t sm_CallStartForward(IPluginContext *pContext, const cell_t *params
return 1;
}
static cell_t sm_CallStartNative(IPluginContext *pContext, const cell_t *params)
{
ResetCall();
char *name;
pContext->LocalToString(params[1], &name);
ke::RefPtr<Native> pNative = g_ShareSys.FindNative(name);
if (!pNative)
return 0;//pContext->ThrowNativeError("Invalid native \"%s\"", name);
s_pInvoker = new NativeInvoker(pContext, pNative);
s_pCallable = static_cast<ICallable *>(s_pInvoker);
s_CallStarted = true;
return 1;
}
static cell_t sm_CallPushCell(IPluginContext *pContext, const cell_t *params)
{
int err;
@@ -657,6 +697,39 @@ static cell_t sm_CallFinish(IPluginContext *pContext, const cell_t *params)
IForward *pForward = s_pForward;
ResetCall();
err = pForward->Execute(result, NULL);
} else if (s_pInvoker) {
err = s_pInvoker->Execute(result);
ResetCall();
}
return err;
}
static cell_t sm_CallFinishEx(IPluginContext *pContext, const cell_t *params)
{
int err = SP_ERROR_NOT_RUNNABLE;
cell_t *result;
if (!s_CallStarted)
{
return pContext->ThrowNativeError("Cannot finish call when there is no call in progress");
}
pContext->LocalToPhysAddr(params[1], &result);
// Note: Execute() swallows exceptions, so this is okay.
if (s_pFunction)
{
IPluginFunction *pFunction = s_pFunction;
ResetCall();
err = pFunction->Execute(result, params[2], params[3]);
} else if (s_pForward) {
IForward *pForward = s_pForward;
ResetCall();
err = pForward->Execute(result, NULL);
} else if (s_pInvoker) {
err = s_pInvoker->Execute(result, params[2], params[3]);
ResetCall();
}
return err;
@@ -743,6 +816,7 @@ REGISTER_NATIVES(functionNatives)
{"RemoveAllFromForward", sm_RemoveAllFromForward},
{"Call_StartFunction", sm_CallStartFunction},
{"Call_StartForward", sm_CallStartForward},
{"Call_StartNative", sm_CallStartNative},
{"Call_PushCell", sm_CallPushCell},
{"Call_PushCellRef", sm_CallPushCellRef},
{"Call_PushFloat", sm_CallPushFloat},
@@ -754,6 +828,7 @@ REGISTER_NATIVES(functionNatives)
{"Call_PushNullVector", sm_CallPushNullVector},
{"Call_PushNullString", sm_CallPushNullString},
{"Call_Finish", sm_CallFinish},
{"Call_FinishEx", sm_CallFinishEx},
{"Call_Cancel", sm_CallCancel},
{"RequestFrame", sm_AddFrameAction},
+2
View File
@@ -119,5 +119,7 @@ REGISTER_NATIVES(handles)
{"CloseHandle", sm_CloseHandle},
{"CloneHandle", sm_CloneHandle},
{"GetMyHandle", sm_GetMyHandle},
{"Handle.Close", sm_CloseHandle},
{"Handle.~Handle", sm_CloseHandle},
{NULL, NULL},
};
+13
View File
@@ -144,6 +144,18 @@ static cell_t sm_SetClientLanguage(IPluginContext *pContext, const cell_t *param
return 1;
}
static cell_t sm_GetClientOriginalLanguage(IPluginContext *pContext, const cell_t *params)
{
IGamePlayer *player = playerhelpers->GetGamePlayer(params[1]);
if (!player || !player->IsConnected())
{
return pContext->ThrowNativeError("Invalid client index %d", params[1]);
}
return player->GetOriginalLanguageId();
}
static cell_t sm_GetLanguageByCode(IPluginContext *pContext, const cell_t *params)
{
char *code;
@@ -181,6 +193,7 @@ REGISTER_NATIVES(langNatives)
{"GetLanguageCount", sm_GetLanguageCount},
{"GetLanguageInfo", sm_GetLanguageInfo},
{"SetClientLanguage", sm_SetClientLanguage},
{"GetClientOriginalLanguage", sm_GetClientOriginalLanguage},
{"GetLanguageByCode", sm_GetLanguageByCode},
{"GetLanguageByName", sm_GetLanguageByName},
{NULL, NULL},
+4 -1
View File
@@ -592,7 +592,10 @@ private:
}
}
if (!libsys->FileTime(pMapList->path, FileTime_LastChange, &last_time)
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", pMapList->path);
if (!libsys->FileTime(realpath, FileTime_LastChange, &last_time)
|| last_time > pMapList->last_modified_time)
{
/* Reparse */
+47 -103
View File
@@ -1,5 +1,5 @@
/**
* vim: set ts=4 :
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
@@ -141,10 +141,6 @@ public:
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
unsigned int OnMenuDisplayItem(IBaseMenu *menu, int client, IMenuPanel *panel, unsigned int item, const ItemDrawInfo &dr);
bool OnSetHandlerOption(const char *option, const void *data);
#if 0
void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
#endif
private:
cell_t DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2, cell_t def_res=0);
private:
@@ -496,99 +492,51 @@ void CMenuHandler::OnMenuVoteResults(IBaseMenu *menu, const menu_vote_result_t *
unsigned int winning_votes = results->item_list[0].count;
DoAction(menu, MenuAction_VoteEnd, winning_item, (total_votes << 16) | (winning_votes & 0xFFFF));
} else {
IPluginContext *pContext = m_pVoteResults->GetParentContext();
bool no_call = false;
int err;
return;
}
/* First array */
cell_t client_array_address = -1;
cell_t *client_array_base = NULL;
cell_t client_array_size = results->num_clients + (results->num_clients * 2);
if (client_array_size)
{
if ((err = pContext->HeapAlloc(client_array_size, &client_array_address, &client_array_base))
!= SP_ERROR_NONE)
{
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for client list.", client_array_size * sizeof(cell_t));
no_call = true;
} else {
cell_t target_offs = sizeof(cell_t) * results->num_clients;
cell_t *cur_index = client_array_base;
cell_t *cur_array;
for (unsigned int i=0; i<results->num_clients; i++)
{
/* Copy the array index */
*cur_index = target_offs;
/* Get the current array address */
cur_array = (cell_t *)((char *)cur_index + target_offs);
/* Store information */
cur_array[0] = results->client_list[i].client;
cur_array[1] = results->client_list[i].item;
/* Adjust for the new target by subtracting one indirection
* and adding one array.
*/
target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
cur_index++;
}
}
IPluginContext *pContext = m_pVoteResults->GetParentContext();
AutoEnterHeapScope heap_scope(pContext);
/* First array */
cell_t client_array_address = -1;
if (cell_t client_array_size = results->num_clients * 2) {
auto init = std::make_unique<cell_t[]>(client_array_size);
for (unsigned int i = 0; i < results->num_clients; i++) {
init[i * 2] = results->client_list[i].client;
init[i * 2 + 1] = results->client_list[i].item;
}
/* Second array */
cell_t item_array_address = -1;
cell_t *item_array_base = NULL;
cell_t item_array_size = results->num_items + (results->num_items * 2);
if (item_array_size)
{
if ((err = pContext->HeapAlloc(item_array_size, &item_array_address, &item_array_base))
!= SP_ERROR_NONE)
{
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, err, "Menu callback could not allocate %d bytes for item list.", item_array_size);
no_call = true;
} else {
cell_t target_offs = sizeof(cell_t) * results->num_items;
cell_t *cur_index = item_array_base;
cell_t *cur_array;
for (unsigned int i=0; i<results->num_items; i++)
{
/* Copy the array index */
*cur_index = target_offs;
/* Get the current array address */
cur_array = (cell_t *)((char *)cur_index + target_offs);
/* Store information */
cur_array[0] = results->item_list[i].item;
cur_array[1] = results->item_list[i].count;
/* Adjust for the new target by subtracting one indirection
* and adding one array.
*/
target_offs += (sizeof(cell_t) * 2) - sizeof(cell_t);
cur_index++;
}
}
}
/* Finally, push everything */
if (!no_call)
{
m_pVoteResults->PushCell(menu->GetHandle());
m_pVoteResults->PushCell(results->num_votes);
m_pVoteResults->PushCell(results->num_clients);
m_pVoteResults->PushCell(client_array_address);
m_pVoteResults->PushCell(results->num_items);
m_pVoteResults->PushCell(item_array_address);
m_pVoteResults->Execute(NULL);
}
/* Free what we allocated, in reverse order as required */
if (item_array_address != -1)
{
pContext->HeapPop(item_array_address);
}
if (client_array_address != -1)
{
pContext->HeapPop(client_array_address);
if (!pContext->HeapAlloc2dArray(results->num_clients, 2, &client_array_address, init.get())) {
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, -1,
"Menu callback could not allocate cells for client list.");
return;
}
}
/* Second array */
cell_t item_array_address = -1;
if (cell_t item_array_size = results->num_items * 2) {
auto init = std::make_unique<cell_t[]>(item_array_size);
for (unsigned int i = 0; i < results->num_items; i++) {
init[i * 2] = results->item_list[i].item;
init[i * 2 + 1] = results->item_list[i].count;
}
if (!pContext->HeapAlloc2dArray(results->num_items, 2, &item_array_address, init.get())) {
g_DbgReporter.GenerateError(pContext, m_fnVoteResult, -1,
"Menu callback could not allocate %d cells for item list.",
item_array_size);
return;
}
}
m_pVoteResults->PushCell(menu->GetHandle());
m_pVoteResults->PushCell(results->num_votes);
m_pVoteResults->PushCell(results->num_clients);
m_pVoteResults->PushCell(client_array_address);
m_pVoteResults->PushCell(results->num_items);
m_pVoteResults->PushCell(item_array_address);
m_pVoteResults->Execute(NULL);
}
bool CMenuHandler::OnSetHandlerOption(const char *option, const void *data)
@@ -1014,7 +962,7 @@ static cell_t GetMenuExitBackButton(IPluginContext *pContext, const cell_t *para
return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
}
return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXIT) ? 1 : 0;
return ((menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK) ? 1 : 0;
}
static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
@@ -1620,15 +1568,11 @@ static cell_t InternalShowMenu(IPluginContext *pContext, const cell_t *params)
IMenuHandler *pHandler;
CPanelHandler *pActualHandler = NULL;
if (params[5] != -1)
{
IPluginFunction *pFunction = pContext->GetFunctionById(params[5]);
if (pFunction == NULL)
{
return pContext->ThrowNativeError("Invalid function index %x", params[5]);
}
pActualHandler = g_MenuHelpers.GetPanelHandler(pFunction);
}
IPluginFunction* func;
if (!pContext->GetFunctionByIdOrNull(params[5], &func))
return 0;
if (func)
pActualHandler = g_MenuHelpers.GetPanelHandler(func);
if (pActualHandler == NULL)
{
+29 -26
View File
@@ -270,18 +270,7 @@ static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params)
return playerhelpers->GetNumPlayers();
}
int maxplayers = playerhelpers->GetMaxClients();
int count = 0;
for (int i = 1; i <= maxplayers; ++i)
{
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(i);
if ((pPlayer->IsConnected()) && !(pPlayer->IsInGame()))
{
count++;
}
}
return (playerhelpers->GetNumPlayers() + count);
return playerhelpers->GetNumClients();
}
static cell_t sm_GetMaxClients(IPluginContext *pCtx, const cell_t *params)
@@ -1471,24 +1460,23 @@ static cell_t IsClientInKickQueue(IPluginContext *pContext, const cell_t *params
return pPlayer->IsInKickQueue() ? 1 : 0;
}
cmd_target_info_t g_ProcessTargetString_info;
static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params)
{
cmd_target_info_t info;
pContext->LocalToString(params[1], (char **) &info.pattern);
info.admin = params[2];
pContext->LocalToPhysAddr(params[3], &info.targets);
info.max_targets = params[4];
info.flags = params[5];
pContext->LocalToString(params[6], &info.target_name);
info.target_name_maxlength = params[7];
pContext->LocalToString(params[1], (char **) &g_ProcessTargetString_info.pattern);
g_ProcessTargetString_info.admin = params[2];
pContext->LocalToPhysAddr(params[3], &g_ProcessTargetString_info.targets);
g_ProcessTargetString_info.max_targets = params[4];
g_ProcessTargetString_info.flags = params[5];
pContext->LocalToString(params[6], &g_ProcessTargetString_info.target_name);
g_ProcessTargetString_info.target_name_maxlength = params[7];
cell_t *tn_is_ml;
pContext->LocalToPhysAddr(params[8], &tn_is_ml);
playerhelpers->ProcessCommandTarget(&info);
playerhelpers->ProcessCommandTarget(&g_ProcessTargetString_info);
if (info.target_name_style == COMMAND_TARGETNAME_ML)
if (g_ProcessTargetString_info.target_name_style == COMMAND_TARGETNAME_ML)
{
*tn_is_ml = 1;
}
@@ -1497,16 +1485,30 @@ static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params
*tn_is_ml = 0;
}
if (info.num_targets == 0)
if (g_ProcessTargetString_info.num_targets == 0)
{
return info.reason;
return g_ProcessTargetString_info.reason;
}
else
{
return info.num_targets;
return g_ProcessTargetString_info.num_targets;
}
}
static cell_t GetLastProcessTargetString(IPluginContext *pContext, const cell_t *params)
{
cell_t *admin, *flags;
pContext->StringToLocalUTF8(params[1], params[2], g_ProcessTargetString_info.pattern, NULL);
pContext->LocalToPhysAddr(params[3], &admin);
pContext->LocalToPhysAddr(params[4], &flags);
*admin = g_ProcessTargetString_info.admin;
*flags = g_ProcessTargetString_info.flags;
return 0;
}
static cell_t FormatActivitySource(IPluginContext *pContext, const cell_t *params)
{
int value;
@@ -1658,6 +1660,7 @@ REGISTER_NATIVES(playernatives)
{ "NotifyPostAdminCheck", NotifyPostAdminCheck },
{ "IsClientInKickQueue", IsClientInKickQueue },
{ "ProcessTargetString", ProcessTargetString },
{ "GetLastProcessTargetString", GetLastProcessTargetString },
{ "FormatActivitySource", FormatActivitySource },
{ "GetClientSerial", sm_GetClientSerial },
{ "GetClientFromSerial", sm_GetClientFromSerial },
+128 -15
View File
@@ -35,6 +35,7 @@
#include "common_logic.h"
#include "CellArray.h"
#include <IHandleSys.h>
#include <amtl/am-raii.h>
/***********************************
* About the double array hack *
@@ -95,7 +96,7 @@ void sort_random(cell_t *array, cell_t size)
{
int n = rand() % (i + 1);
if (array[i] != array[n])
if (array[i] != array[n])
{
array[i] ^= array[n];
array[n] ^= array[i];
@@ -125,7 +126,7 @@ static cell_t sm_SortIntegers(IPluginContext *pContext, const cell_t *params)
if (type == Sort_Ascending)
{
qsort(array, array_size, sizeof(cell_t), sort_ints_asc);
}
}
else if (type == Sort_Descending)
{
qsort(array, array_size, sizeof(cell_t), sort_ints_desc);
@@ -195,7 +196,7 @@ static cell_t sm_SortFloats(IPluginContext *pContext, const cell_t *params)
static cell_t *g_CurStringArray = NULL;
static cell_t *g_CurRebaseMap = NULL;
int sort_strings_asc(const void *blk1, const void *blk2)
int sort_strings_asc_legacy(const void *blk1, const void *blk2)
{
cell_t reloc1 = *(cell_t *)blk1;
cell_t reloc2 = *(cell_t *)blk2;
@@ -206,7 +207,7 @@ int sort_strings_asc(const void *blk1, const void *blk2)
return strcmp(str1, str2);
}
int sort_strings_desc(const void *blk1, const void *blk2)
int sort_strings_desc_legacy(const void *blk1, const void *blk2)
{
cell_t reloc1 = *(cell_t *)blk1;
cell_t reloc2 = *(cell_t *)blk2;
@@ -217,7 +218,7 @@ int sort_strings_desc(const void *blk1, const void *blk2)
return strcmp(str2, str1);
}
static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
static cell_t sm_SortStrings_Legacy(IPluginContext *pContext, const cell_t *params)
{
cell_t *array;
cell_t array_size = params[2];
@@ -245,11 +246,11 @@ static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
if (type == Sort_Ascending)
{
qsort(array, array_size, sizeof(cell_t), sort_strings_asc);
}
qsort(array, array_size, sizeof(cell_t), sort_strings_asc_legacy);
}
else if (type == Sort_Descending)
{
qsort(array, array_size, sizeof(cell_t), sort_strings_desc);
qsort(array, array_size, sizeof(cell_t), sort_strings_desc_legacy);
}
else
{
@@ -275,6 +276,69 @@ static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
return 1;
}
static IPluginContext* sSortContext = nullptr;
int sort_strings_asc(const void *blk1, const void *blk2)
{
cell_t str_addr1 = *(cell_t *)blk1;
cell_t str_addr2 = *(cell_t *)blk2;
char *str1;
char *str2;
if (sSortContext->LocalToString(str_addr1, &str1) != SP_ERROR_NONE ||
sSortContext->LocalToString(str_addr2, &str2) != SP_ERROR_NONE)
{
return 0;
}
return strcmp(str1, str2);
}
int sort_strings_desc(const void *blk1, const void *blk2)
{
cell_t str_addr1 = *(cell_t *)blk1;
cell_t str_addr2 = *(cell_t *)blk2;
char *str1;
char *str2;
if (sSortContext->LocalToString(str_addr1, &str1) != SP_ERROR_NONE ||
sSortContext->LocalToString(str_addr2, &str2) != SP_ERROR_NONE)
{
return 0;
}
return strcmp(str2, str1);
}
static cell_t sm_SortStrings(IPluginContext *pContext, const cell_t *params)
{
auto rt = pContext->GetRuntime();
if (!rt->UsesDirectArrays())
return sm_SortStrings_Legacy(pContext, params);
cell_t *array;
cell_t array_size = params[2];
cell_t type = params[3];
pContext->LocalToPhysAddr(params[1], &array);
ke::SaveAndSet<IPluginContext*> set_context(&sSortContext, pContext);
if (type == Sort_Ascending)
{
qsort(array, array_size, sizeof(cell_t), sort_strings_asc);
}
else if (type == Sort_Descending)
{
qsort(array, array_size, sizeof(cell_t), sort_strings_desc);
}
else
{
sort_random(array, array_size);
}
return 1;
}
struct sort_info
{
IPluginFunction *pFunc;
@@ -335,7 +399,7 @@ static cell_t sm_SortCustom1D(IPluginContext *pContext, const cell_t *params)
return 1;
}
int sort2d_amx_custom(const void *elem1, const void *elem2)
static int sort2d_amx_custom_legacy(const void *elem1, const void *elem2)
{
if (g_SortInfo.eh->HasException())
return 0;
@@ -361,7 +425,7 @@ int sort2d_amx_custom(const void *elem1, const void *elem2)
return result;
}
static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
static cell_t sm_SortCustom2D_Legacy(IPluginContext *pContext, const cell_t *params)
{
cell_t *array;
cell_t array_size = params[2];
@@ -401,7 +465,7 @@ static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
array[i] = i;
}
qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom);
qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom_legacy);
/** Fixup process! */
for (int i=0; i<array_size; i++)
@@ -419,6 +483,55 @@ static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
return 1;
}
static int sort2d_amx_custom(const void *elem1, const void *elem2)
{
if (g_SortInfo.eh->HasException())
return 0;
cell_t iv1 = *(cell_t *)elem1;
cell_t iv2 = *(cell_t *)elem2;
cell_t result = 0;
g_SortInfo.pFunc->PushCell(iv1);
g_SortInfo.pFunc->PushCell(iv2);
g_SortInfo.pFunc->PushCell(g_SortInfo.array_addr);
g_SortInfo.pFunc->PushCell(g_SortInfo.hndl);
g_SortInfo.pFunc->Invoke(&result);
return result;
}
static cell_t sm_SortCustom2D(IPluginContext *pContext, const cell_t *params)
{
auto rt = pContext->GetRuntime();
if (!rt->UsesDirectArrays())
return sm_SortCustom2D_Legacy(pContext, params);
cell_t *array;
cell_t array_size = params[2];
IPluginFunction *pFunction;
pContext->LocalToPhysAddr(params[1], &array);
if ((pFunction=pContext->GetFunctionById(params[3])) == NULL)
{
return pContext->ThrowNativeError("Function %x is not a valid function", params[3]);
}
sort_info oldinfo = g_SortInfo;
DetectExceptions eh(pContext);
g_SortInfo.pFunc = pFunction;
g_SortInfo.hndl = params[4];
g_SortInfo.array_addr = params[1];
g_SortInfo.eh = &eh;
qsort(array, array_size, sizeof(cell_t), sort2d_amx_custom);
g_SortInfo = oldinfo;
return 1;
}
enum SortType
{
Sort_Integer = 0,
@@ -454,7 +567,7 @@ static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
@@ -491,7 +604,7 @@ static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
{
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_asc);
}
else
else
{
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_floats_desc);
}
@@ -502,7 +615,7 @@ static cell_t sm_SortADTArray(IPluginContext *pContext, const cell_t *params)
{
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_asc);
}
else
else
{
qsort(array, arraysize, blocksize * sizeof(cell_t), sort_adtarray_strings_desc);
}
@@ -545,7 +658,7 @@ static cell_t sm_SortADTArrayCustom(IPluginContext *pContext, const cell_t *para
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
if ((err = handlesys->ReadHandle(params[1], htCellArray, &sec, (void **)&cArray))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error: %d)", params[1], err);
+1 -1
View File
@@ -170,7 +170,7 @@ static cell_t Int64ToString(IPluginContext *pCtx, const cell_t *params)
char *str;
pCtx->LocalToPhysAddr(params[1], &num);
pCtx->LocalToString(params[2], &str);
size_t res = ke::SafeSprintf(str, params[3], "%" KE_FMT_I64, (int64_t)num[1] << 32ll | (int64_t)num[0]);
size_t res = ke::SafeSprintf(str, params[3], "%" KE_FMT_I64, (uint64_t)num[1] << 32ll | (uint32_t)num[0]);
return static_cast<cell_t>(res);
}
+29
View File
@@ -29,6 +29,8 @@
* Version: $Id$
*/
#include <string.h>
#include "common_logic.h"
#include <ITextParsers.h>
#include <ISourceMod.h>
@@ -264,6 +266,32 @@ static cell_t SMC_ParseFile(IPluginContext *pContext, const cell_t *params)
return (cell_t)p_err;
}
static cell_t SMC_ParseString(IPluginContext *pContext, const cell_t *params)
{
OpenHandle<ParseInfo> parse(pContext, params[1], g_TypeSMC);
if (!parse.Ok())
return 0;
char *str;
pContext->LocalToString(params[2], &str);
SMCStates states;
SMCError p_err = textparsers->ParseSMCStream(str,
strlen(str),
parse,
&states,
NULL,
0);
cell_t *c_line, *c_col;
pContext->LocalToPhysAddr(params[3], &c_line);
pContext->LocalToPhysAddr(params[4], &c_col);
*c_line = states.line;
*c_col = states.col;
return (cell_t)p_err;
}
static cell_t SMC_GetErrorString(IPluginContext *pContext, const cell_t *params)
{
const char *str = textparsers->GetSMCErrorString((SMCError)params[1]);
@@ -334,6 +362,7 @@ REGISTER_NATIVES(textNatives)
// Transitional syntax support.
{"SMCParser.SMCParser", SMC_CreateParser},
{"SMCParser.ParseFile", SMC_ParseFile},
{"SMCParser.ParseString", SMC_ParseString},
{"SMCParser.OnStart.set", SMC_SetParseStart},
{"SMCParser.OnEnd.set", SMC_SetParseEnd},
{"SMCParser.OnEnterSection.set", SMCParser_OnEnterSection_set},
+2 -2
View File
@@ -1218,7 +1218,7 @@ reswitch:
cell_t *target;
pCtx->LocalToString(params[arg++], &key);
pCtx->LocalToPhysAddr(params[arg++], &target);
res = Translate(buf_p, llen, pCtx, key, *target, params, &arg, &error);
res = Translate(buf_p, llen + 1, pCtx, key, *target, params, &arg, &error);
if (error)
{
return 0;
@@ -1235,7 +1235,7 @@ reswitch:
size_t res;
cell_t target = bridge->GetGlobalTarget();
pCtx->LocalToString(params[arg++], &key);
res = Translate(buf_p, llen, pCtx, key, target, params, &arg, &error);
res = Translate(buf_p, llen + 1, pCtx, key, target, params, &arg, &error);
if (error)
{
return 0;
+50 -69
View File
@@ -51,9 +51,6 @@
#include <bridge/include/IVEngineServerBridge.h>
#include <bridge/include/IPlayerInfoBridge.h>
#include <bridge/include/IFileSystemBridge.h>
#if PROTOBUF_PROXY_ENABLE
# include "pb_handle.h"
#endif
sm_logic_t logicore;
@@ -105,90 +102,98 @@ public:
class VFileSystem_Logic : public IFileSystemBridge
{
public:
const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle)
const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) override
{
return filesystem->FindFirstEx(pWildCard, pPathID, pHandle);
}
const char *FindNext(FileFindHandle_t handle)
const char *FindNext(FileFindHandle_t handle) override
{
return filesystem->FindNext(handle);
}
bool FindIsDirectory(FileFindHandle_t handle)
bool FindIsDirectory(FileFindHandle_t handle) override
{
return filesystem->FindIsDirectory(handle);
}
void FindClose(FileFindHandle_t handle)
void FindClose(FileFindHandle_t handle) override
{
filesystem->FindClose(handle);
}
FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0)
FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) override
{
return filesystem->Open(pFileName, pOptions, pathID);
}
void Close(FileHandle_t file)
void Close(FileHandle_t file) override
{
filesystem->Close(file);
}
char *ReadLine(char *pOutput, int maxChars, FileHandle_t file)
char *ReadLine(char *pOutput, int maxChars, FileHandle_t file) override
{
return filesystem->ReadLine(pOutput, maxChars, file);
}
bool EndOfFile(FileHandle_t file)
bool EndOfFile(FileHandle_t file) override
{
return filesystem->EndOfFile(file);
}
bool FileExists(const char *pFileName, const char *pPathID = 0)
bool FileExists(const char *pFileName, const char *pPathID = 0) override
{
return filesystem->FileExists(pFileName, pPathID);
}
unsigned int Size(const char *pFileName, const char *pPathID = 0)
unsigned int Size(FileHandle_t file) override
{
return filesystem->Size(file);
}
unsigned int Size(const char *pFileName, const char *pPathID = 0) override
{
return filesystem->Size(pFileName, pPathID);
}
int Read(void* pOutput, int size, FileHandle_t file)
int Read(void* pOutput, int size, FileHandle_t file) override
{
return filesystem->Read(pOutput, size, file);
}
int Write(void const* pInput, int size, FileHandle_t file)
int Write(void const* pInput, int size, FileHandle_t file) override
{
return filesystem->Write(pInput, size, file);
}
void Seek(FileHandle_t file, int pos, int seekType)
void Seek(FileHandle_t file, int pos, int seekType) override
{
filesystem->Seek(file, pos, (FileSystemSeek_t) seekType);
}
unsigned int Tell(FileHandle_t file)
unsigned int Tell(FileHandle_t file) override
{
return filesystem->Tell(file);
}
int FPrint(FileHandle_t file, const char *pData)
int FPrint(FileHandle_t file, const char *pData) override
{
return filesystem->FPrintf(file, "%s", pData);
}
void Flush(FileHandle_t file)
void Flush(FileHandle_t file) override
{
filesystem->Flush(file);
}
bool IsOk(FileHandle_t file)
bool IsOk(FileHandle_t file) override
{
return filesystem->IsOk(file);
}
void RemoveFile(const char *pRelativePath, const char *pathID)
void RemoveFile(const char *pRelativePath, const char *pathID) override
{
filesystem->RemoveFile(pRelativePath, pathID);
}
void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID)
void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID) override
{
filesystem->RenameFile(pOldPath, pNewPath, pathID);
}
bool IsDirectory(const char *pFileName, const char *pathID)
bool IsDirectory(const char *pFileName, const char *pathID) override
{
return filesystem->IsDirectory(pFileName, pathID);
}
void CreateDirHierarchy(const char *path, const char *pathID)
void CreateDirHierarchy(const char *path, const char *pathID) override
{
filesystem->CreateDirHierarchy(path, pathID);
}
int GetSearchPath(const char* pathID, bool bGetPackFiles, char* pPath, int nMaxLen) override
{
return filesystem->GetSearchPath(pathID, bGetPackFiles, pPath, nMaxLen);
}
} fs_wrapper;
class VPlayerInfo_Logic : public IPlayerInfoBridge
@@ -374,6 +379,12 @@ void UTIL_ConsolePrint(const char *fmt, ...)
#define GAMEFIX "2.csgo"
#elif SOURCE_ENGINE == SE_CONTAGION
#define GAMEFIX "2.contagion"
#elif SOURCE_ENGINE == SE_PVKII
#define GAMEFIX "2.pvkii"
#elif SOURCE_ENGINE == SE_MCV
#define GAMEFIX "2.mcv"
#elif SOURCE_ENGINE == SE_MOCK
#define GAMEFIX "2.mock"
#else
#define GAMEFIX "2.ep1"
#endif
@@ -406,9 +417,6 @@ CoreProviderImpl::CoreProviderImpl()
this->GetGlobalTarget = get_global_target;
this->gamesuffix = GAMEFIX;
this->serverGlobals = &::serverGlobals;
this->serverFactory = nullptr;
this->engineFactory = nullptr;
this->matchmakingDSFactory = nullptr;
this->listeners = nullptr;
}
@@ -496,6 +504,12 @@ const char *CoreProviderImpl::GetSourceEngineName()
return "doi";
#elif SOURCE_ENGINE == SE_CSGO
return "csgo";
#elif SOURCE_ENGINE == SE_MOCK
return "mock";
#elif SOURCE_ENGINE == SE_PVKII
return "pvkii";
#elif SOURCE_ENGINE == SE_MCV
return "mcv";
#endif
}
@@ -513,7 +527,9 @@ bool CoreProviderImpl::SymbolsAreHidden()
|| (SOURCE_ENGINE == SE_INSURGENCY) \
|| (SOURCE_ENGINE == SE_DOI) \
|| (SOURCE_ENGINE == SE_BLADE) \
|| (SOURCE_ENGINE == SE_CSGO)
|| (SOURCE_ENGINE == SE_CSGO) \
|| (SOURCE_ENGINE == SE_PVKII) \
|| (SOURCE_ENGINE == SE_MCV)
return true;
#else
return false;
@@ -626,14 +642,8 @@ void CoreProviderImpl::InitializeBridge()
::serverGlobals.frametime = &gpGlobals->frametime;
::serverGlobals.interval_per_tick = &gpGlobals->interval_per_tick;
this->engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
this->serverFactory = (void *)g_SMAPI->GetServerFactory(false);
this->listeners = SMGlobalClass::head;
if (auto mmlib = ::filesystem->LoadModule("matchmaking_ds" SOURCE_BIN_SUFFIX, "GAMEBIN")) {
this->matchmakingDSFactory = (void*)Sys_GetFactory(mmlib);
}
logic_init_(this, &logicore);
// Join logic's SMGlobalClass instances.
@@ -655,41 +665,6 @@ void CoreProviderImpl::InitializeBridge()
rootmenu = logicore.rootmenu;
}
bool CoreProviderImpl::LoadProtobufProxy(char *error, size_t maxlength)
{
#if !defined(PROTOBUF_PROXY_ENABLE)
return false;
#else
char file[PLATFORM_MAX_PATH];
#if !defined(PROTOBUF_PROXY_BINARY_NAME)
# error "No engine suffix defined"
#endif
/* Now it's time to load the logic binary */
g_SMAPI->PathFormat(file,
sizeof(file),
"%s/bin/" PLATFORM_ARCH_FOLDER PROTOBUF_PROXY_BINARY_NAME PLATFORM_LIB_EXT,
g_SourceMod.GetSourceModPath());
char myerror[255];
pbproxy_ = ke::SharedLib::Open(file, myerror, sizeof(myerror));
if (!pbproxy_) {
ke::SafeSprintf(error, maxlength, "failed to load %s: %s", file, myerror);
return false;
}
auto fn = pbproxy_->get<GetProtobufProxyFn>("GetProtobufProxy");
if (!fn) {
ke::SafeStrcpy(error, maxlength, "could not find GetProtobufProxy function");
return false;
}
gProtobufProxy = fn();
return true;
#endif
}
bool CoreProviderImpl::LoadBridge(char *error, size_t maxlength)
{
char file[PLATFORM_MAX_PATH];
@@ -770,6 +745,12 @@ CoreProviderImpl::DefineCommand(const char *name, const char *help, const Comman
commands_.push_back(impl);
}
void CoreProviderImpl::FormatSourceBinaryName(const char *basename, char *buffer, size_t maxlength)
{
bool use_prefix = (!strcasecmp(basename, "tier0") || !strcasecmp(basename, "vstdlib"));
ke::SafeSprintf(buffer, maxlength, "%s%s%s%s", use_prefix ? SOURCE_BIN_PREFIX : "", basename, SOURCE_BIN_SUFFIX, SOURCE_BIN_EXT);
}
void CoreProviderImpl::InitializeHooks()
{
hooks_.Start();
-217
View File
@@ -1,217 +0,0 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2020 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$
*/
#pragma once
#if defined(PROTOBUF_ENABLE)
#include <google/protobuf/message.h>
#if defined(PROTOBUF_PROXY_ENABLE)
# include "pb_proxy.h"
extern IProtobufProxy* gProtobufProxy;
#endif
const google::protobuf::Message *GetMessagePrototype(int msg_type);
// On SDKs which use protobufs, the engine has objects compiled against a specific
// version of protobuf. Normally this is fine, we take care on Linux to use the
// same C++ ABI. On macOS however, we use libc++ to enable C++11 functionality,
// whereas the protobuf library has been compiled with libstc++. These ABIs are
// not compatible.
//
// To address the problem, we introduce PbHandle. PbHandle is a wrapper around
// protobuf::Message with two added pieces of state: whether or not the handle
// "owns" the message (and can free it in its destructor), and whether or not
// the handle was created by the engine (private) or created by SourceMod
// (local).
//
// Whenever we transfer a protobuf::Message pointer to SourceMod, we must take
// care to convert it to a Local version first. Whenever we transfer a protobuf
// pointer to the engine, we must convert it to a Private handle.
//
// For platforms with no ABI differences (almost all of them), the handle is a
// no-op. The private and local localities are compatible and no translation
// takes place.
//
// On macOS, CS:GO does require translation. SourceMod loads a tiny shim
// library that contains a copy of the protobuf sources compiled against the
// game's ABI. It then provides serialization and deserialization methods.
// SourceMod must not interact with the game's protobuf objects without first
// going through this proxy library.
//
// Note that PbHandle is not quite like unique_ptr_. It can be converted into a
// PbHandle that does not destroy the underlying object. This is mainly because
// UserMessages.cpp has rather complex state, so it is useful to track locality
// without destroying an object. An unowned PbHandle must not outlive the
// owning PbHandle.
class PbHandle
{
public:
enum Ownership {
Owned,
Unowned,
};
enum Locality {
Local,
Private,
};
PbHandle() : msg_(nullptr) {}
PbHandle(decltype(nullptr)) : msg_(nullptr) {}
PbHandle(google::protobuf::Message* msg, Ownership ownership, Locality locality)
: msg_(msg),
ownership_(ownership),
locality_(locality)
{}
PbHandle(PbHandle&& other)
: msg_(other.msg_),
ownership_(other.ownership_),
locality_(other.locality_)
{
other.msg_ = nullptr;
}
PbHandle(const PbHandle&) = delete;
~PbHandle() {
maybe_free();
}
PbHandle& operator =(PbHandle&& other) {
if (other.msg_ != msg_)
maybe_free();
msg_ = other.msg_;
ownership_ = other.ownership_;
locality_ = other.locality_;
other.msg_ = nullptr;
return *this;
}
PbHandle& operator =(const PbHandle&) = delete;
google::protobuf::Message* operator ->() const { return msg_; }
google::protobuf::Message* GetLocalMessage() {
assert(locality_ == Local);
return msg_;
}
google::protobuf::Message* GetPrivateMessage() {
assert(locality_ == Private);
return msg_;
}
PbHandle ToLocal(int msg_type) {
if (locality_ == Local)
return AsUnowned();
#if defined(PROTOBUF_PROXY_ENABLE)
PbHandle local(GetMessagePrototype(msg_type)->New(), Owned, Local);
local.CopyFromPrivate(msg_);
return local;
#else
return PbHandle(msg_, Unowned, Local);
#endif
}
PbHandle ToPrivate(int msg_type) {
if (locality_ == Private)
return AsUnowned();
#if defined(PROTOBUF_PROXY_ENABLE)
PbHandle priv(gProtobufProxy->NewPrototype(msg_type), Owned, Private);
priv.CopyFromLocal(msg_);
return priv;
#else
return PbHandle(msg_, Unowned, Private);
#endif
}
void CopyFrom(const PbHandle& other) {
if (other.msg_ == msg_) {
assert(other.locality_ == locality_);
return;
}
#if defined(PROTOBUF_PROXY_ENABLE)
if (other.locality_ == Local)
CopyFromLocal(other.msg_);
else if (other.locality_ == Private)
CopyFromPrivate(other.msg_);
#else
msg_->CopyFrom(*other.msg_);
#endif
}
PbHandle AsUnowned() {
return PbHandle(msg_, Unowned, locality_);
}
bool is_owned() const { return ownership_ == Owned; }
bool is_local() const { return locality_ == Local; }
private:
#if defined(PROTOBUF_PROXY_ENABLE)
void CopyFromPrivate(google::protobuf::Message* message) {
void* out;
size_t len;
if (!gProtobufProxy->Serialize(message, &out, &len))
return;
if (locality_ == Local)
msg_->ParsePartialFromArray(out, len);
else
gProtobufProxy->Deserialize(out, len, msg_);
gProtobufProxy->FreeBuffer(out);
}
void CopyFromLocal(google::protobuf::Message* message) {
if (locality_ == Local) {
msg_->CopyFrom(*message);
} else {
auto data = message->SerializePartialAsString();
gProtobufProxy->Deserialize(data.data(), data.size(), msg_);
}
}
#endif
void maybe_free() {
if (ownership_ != Owned)
return;
#if defined(PROTOBUF_PROXY_ENABLE)
if (locality_ == Private) {
gProtobufProxy->FreeMessage(msg_);
return;
}
#endif
delete msg_;
}
private:
google::protobuf::Message* msg_ = nullptr;
Ownership ownership_ = Unowned;
Locality locality_ = Local;
};
#endif // PROTOBUF_ENABLE
-100
View File
@@ -1,100 +0,0 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2020 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include "pb_proxy.h"
#include <stdlib.h>
#include <sm_platform.h>
#if SOURCE_ENGINE == SE_CSGO
# include <cstrike15_usermessage_helpers.h>
#else
# error "No source engine compatibility"
#endif
class ProtobufProxy : public IProtobufProxy
{
public:
bool Serialize(const google::protobuf::Message* message, void** out, size_t* len);
void FreeBuffer(void* data);
bool Deserialize(const void* buffer, size_t len, google::protobuf::Message* message);
google::protobuf::Message* NewPrototype(int msg_type);
void FreeMessage(google::protobuf::Message* message);
};
static ProtobufProxy sProtobufProxy;
PLATFORM_EXTERN_C IProtobufProxy*
GetProtobufProxy()
{
return &sProtobufProxy;
}
bool
ProtobufProxy::Serialize(const google::protobuf::Message* message, void** out, size_t* len)
{
*len = message->ByteSize();
*out = malloc(*len);
if (!*out)
return false;
if (!message->SerializePartialToArray(*out, *len)) {
free(*out);
return false;
}
return true;
}
void
ProtobufProxy::FreeBuffer(void* data)
{
free(data);
}
bool
ProtobufProxy::Deserialize(const void* buffer, size_t len, google::protobuf::Message* message)
{
return message->ParsePartialFromArray(buffer, len);
}
google::protobuf::Message*
ProtobufProxy::NewPrototype(int msg_type)
{
#if SOURCE_ENGINE == SE_CSGO
return g_Cstrike15UsermessageHelpers.GetPrototype(msg_type)->New();
#else
# error "No source engine compatibility."
#endif
}
void
ProtobufProxy::FreeMessage(google::protobuf::Message* message)
{
delete message;
}
+1 -2
View File
@@ -38,7 +38,6 @@ public:
// Local functions.
void InitializeBridge();
bool LoadProtobufProxy(char *error, size_t maxlength);
bool LoadBridge(char *error, size_t maxlength);
void ShutdownBridge();
@@ -67,6 +66,7 @@ public:
int QueryClientConVar(int client, const char *cvar) override;
bool IsClientConVarQueryingSupported() override;
void DefineCommand(const char *cmd, const char *help, const SourceMod::CommandFunc &callback) override;
void FormatSourceBinaryName(const char *basename, char *buffer, size_t maxlength) override;
ke::RefPtr<CommandHook> AddCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
ke::RefPtr<CommandHook> AddPostCommandHook(ConCommand *cmd, const CommandHook::Callback &callback);
@@ -76,7 +76,6 @@ public:
}
private:
ke::RefPtr<ke::SharedLib> pbproxy_;
ke::RefPtr<ke::SharedLib> logic_;
LogicInitFunction logic_init_;
GameHooks hooks_;
+68 -9
View File
@@ -51,7 +51,7 @@
#include <bridge/include/ILogger.h>
#include <ITranslator.h>
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
#include <netmessages.pb.h>
#endif
@@ -827,6 +827,16 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
return 1;
}
static cell_t sm_IsCommandCallback(IPluginContext *pContext, const cell_t *params)
{
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
if (!pCmd)
return 0;
return 1;
}
static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
{
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
@@ -979,11 +989,14 @@ static cell_t sm_ServerCommandEx(IPluginContext *pContext, const cell_t *params)
}
engine->ServerExecute();
g_ShouldCatchSpew = true;
engine->ServerCommand("sm_conhook_start\n");
engine->ServerCommand(buffer);
engine->ServerCommand("sm_conhook_stop\n");
if (!g_ShouldCatchSpew) {
g_ShouldCatchSpew = true;
engine->ServerCommand("sm_conhook_start\n");
engine->ServerCommand(buffer);
engine->ServerCommand("sm_conhook_stop\n");
} else {
engine->ServerCommand(buffer);
}
engine->ServerExecute();
@@ -1091,6 +1104,26 @@ static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
}
static cell_t GetPublicChatTriggers(IPluginContext *pContext, const cell_t *params)
{
size_t length;
const char *triggers = g_ChatTriggers.GetPublicChatTrigger();
pContext->StringToLocalUTF8(params[1], params[2], triggers ? triggers : "", &length);
return static_cast<cell_t>(length);
}
static cell_t GetSilentChatTriggers(IPluginContext *pContext, const cell_t *params)
{
size_t length;
const char *triggers = g_ChatTriggers.GetPrivateChatTrigger();
pContext->StringToLocalUTF8(params[1], params[2], triggers ? triggers : "", &length);
return static_cast<cell_t>(length);
}
static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
{
char *name;
@@ -1209,7 +1242,7 @@ static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
char data[256];
bf_write buffer(data, sizeof(data));
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
CNETMsg_SetConVar msg;
CMsg_CVars_CVar *cvar = msg.mutable_convars()->add_cvars();
@@ -1393,7 +1426,7 @@ static cell_t sm_CommandIteratorNext(IPluginContext *pContext, const cell_t *par
return iter->iter != cmds.end();
}
static cell_t sm_CommandIteratorFlags(IPluginContext *pContext, const cell_t *params)
static cell_t sm_CommandIteratorAdminFlags(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter;
HandleError err;
@@ -1414,6 +1447,27 @@ static cell_t sm_CommandIteratorFlags(IPluginContext *pContext, const cell_t *pa
return pInfo->eflags;
}
static cell_t sm_CommandIteratorConVarFlags(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter;
HandleError err;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid CommandIterator Handle %x", params[1]);
}
const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
if (!iter->started || iter->iter == cmds.end())
{
return pContext->ThrowNativeError("Invalid CommandIterator position");
}
ConCmdInfo *pInfo = (*(iter->iter));
return pInfo->pCmd->m_nFlags;
}
static cell_t sm_CommandIteratorGetDesc(IPluginContext *pContext, const cell_t *params)
{
GlobCmdIter *iter;
@@ -1505,6 +1559,7 @@ REGISTER_NATIVES(consoleNatives)
{"GetConVarDefault", GetConVarDefault},
{"RegServerCmd", sm_RegServerCmd},
{"RegConsoleCmd", sm_RegConsoleCmd},
{"IsCommandCallback", sm_IsCommandCallback},
{"GetCmdArgString", sm_GetCmdArgString},
{"GetCmdArgs", sm_GetCmdArgs},
{"GetCmdArg", sm_GetCmdArg},
@@ -1514,6 +1569,8 @@ REGISTER_NATIVES(consoleNatives)
{"ReadCommandIterator", ReadCommandIterator},
{"FakeClientCommandEx", FakeClientCommandEx},
{"IsChatTrigger", IsChatTrigger},
{"GetPublicChatTriggers", GetPublicChatTriggers},
{"GetSilentChatTriggers", GetSilentChatTriggers},
{"SetCommandFlags", SetCommandFlags},
{"GetCommandFlags", GetCommandFlags},
{"FindFirstConCommand", FindFirstConCommand},
@@ -1552,7 +1609,9 @@ REGISTER_NATIVES(consoleNatives)
{"CommandIterator.Next", sm_CommandIteratorNext},
{"CommandIterator.GetDescription", sm_CommandIteratorGetDesc},
{"CommandIterator.GetName", sm_CommandIteratorGetName},
{"CommandIterator.Flags.get", sm_CommandIteratorFlags},
{"CommandIterator.Flags.get", sm_CommandIteratorAdminFlags},
{"CommandIterator.AdminFlags.get", sm_CommandIteratorAdminFlags},
{"CommandIterator.ConVarFlags.get", sm_CommandIteratorConVarFlags},
{"CommandIterator.Plugin.get", sm_CommandIteratorPlugin},
{NULL, NULL}
+117 -35
View File
@@ -134,12 +134,10 @@ inline edict_t *BaseEntityToEdict(CBaseEntity *pEntity)
{
IServerUnknown *pUnk = (IServerUnknown *)pEntity;
IServerNetworkable *pNet = pUnk->GetNetworkable();
if (!pNet)
if (pNet == nullptr)
{
return NULL;
return nullptr;
}
return pNet->GetEdict();
}
@@ -285,6 +283,11 @@ static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Edict %d (%d) is not a valid edict", g_HL2.ReferenceToIndex(params[1]), params[1]);
}
if (g_HL2.ReferenceToIndex(params[1]) == 0)
{
return pContext->ThrowNativeError("Cannot remove worldspawn (edict 0)");
}
engine->RemoveEdict(pEdict);
return 1;
@@ -298,6 +301,11 @@ static cell_t RemoveEntity(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Entity %d (%d) is not a valid entity", g_HL2.ReferenceToIndex(params[1]), params[1]);
}
if (g_HL2.ReferenceToIndex(params[1]) == 0)
{
return pContext->ThrowNativeError("Cannot remove worldspawn (entity 0)");
}
// Some games have UTIL_Remove exposed on IServerTools, but for consistence, we'll
// use this method for all. Results in DeathNotice( this ) being called on parent,
// and parent being cleared (both if any parent) before UTIL_Remove is called.
@@ -353,14 +361,20 @@ static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params)
static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params)
{
edict_t *pEdict = GetEdict(params[1]);
if (!pEdict)
IServerUnknown *pUnknown = (IServerUnknown *)g_HL2.ReferenceToEntity(params[1]);
if (!pUnknown)
{
return 0;
}
return (pEdict->GetNetworkable() != NULL) ? 1 : 0;
IServerNetworkable *pNet = pUnknown->GetNetworkable();
if (!pNet)
{
return 0;
}
edict_t* edict = pNet->GetEdict();
return (edict && !edict->IsFree()) ? 1 : 0;
}
static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params)
@@ -426,14 +440,12 @@ static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params)
return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]);
}
IServerNetworkable *pNet = pUnk->GetNetworkable();
if (!pNet)
ServerClass *pClass = g_HL2.FindEntityServerClass(pEntity);
if (!pClass)
{
return 0;
}
ServerClass *pClass = pNet->GetServerClass();
pContext->StringToLocal(params[2], params[3], pClass->GetName());
return 1;
@@ -706,6 +718,36 @@ static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
return g_HL2.EntityToBCompatRef(pHandleEntity);
}
//memory addresses below 0x10000 are automatically considered invalid for dereferencing
//this is copied over from smn_core.cpp
#define VALID_MINIMUM_MEMORY_ADDRESS 0x10000
static cell_t LoadEntityFromHandleAddress(IPluginContext *pContext, const cell_t *params)
{
#ifdef PLATFORM_X86
void *addr = reinterpret_cast<void*>(params[1]);
#else
void *addr = g_SourceMod.FromPseudoAddress(params[1]);
#endif
if (addr == NULL)
{
return pContext->ThrowNativeError("Address cannot be null");
}
else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
{
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
}
CBaseHandle &hndl = *reinterpret_cast<CBaseHandle*>(addr);
CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(hndl.GetEntryIndex());
if (!pHandleEntity || hndl != reinterpret_cast<IHandleEntity *>(pHandleEntity)->GetRefEHandle())
return -1;
return g_HL2.EntityToBCompatRef(pHandleEntity);
}
/* THIS GUY IS DEPRECATED. */
static cell_t SetEntDataEnt(IPluginContext *pContext, const cell_t *params)
{
@@ -791,6 +833,44 @@ static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params)
return 1;
}
static cell_t StoreEntityToHandleAddress(IPluginContext *pContext, const cell_t *params)
{
#ifdef PLATFORM_X86
void *addr = reinterpret_cast<void*>(params[1]);
#else
void *addr = g_SourceMod.FromPseudoAddress(params[1]);
#endif
if (addr == NULL)
{
return pContext->ThrowNativeError("Address cannot be null");
}
else if (reinterpret_cast<uintptr_t>(addr) < VALID_MINIMUM_MEMORY_ADDRESS)
{
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", addr);
}
CBaseHandle &hndl = *reinterpret_cast<CBaseHandle*>(addr);
if ((unsigned)params[2] == INVALID_EHANDLE_INDEX)
{
hndl.Set(NULL);
}
else
{
CBaseEntity *pOther = GetEntity(params[2]);
if (!pOther)
{
return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[2]), params[2]);
}
IHandleEntity *pHandleEnt = (IHandleEntity *)pOther;
hndl.Set(pHandleEnt);
}
return 1;
}
static cell_t ChangeEdictState(IPluginContext *pContext, const cell_t *params)
{
edict_t *pEdict = GetEdict(params[1]);
@@ -818,6 +898,12 @@ static cell_t FindSendPropOffs(IPluginContext *pContext, const cell_t *params)
return -1;
}
// Before we added support for DPT_Array props, FindInSendTable would have given us the inner array prop itself.
// To maintain compatibility with older plugins still using us, pluck out the inner array prop ourselves.
if (pSend->GetType() == DPT_Array && pSend->GetArrayProp()) {
return pSend->GetArrayProp()->GetOffset();
}
return pSend->GetOffset();
}
@@ -825,7 +911,7 @@ static cell_t FindSendPropInfo(IPluginContext *pContext, const cell_t *params)
{
char *cls, *prop;
sm_sendprop_info_t info;
cell_t *pType, *pBits, *pLocal, *pArraySize;
cell_t *pType, *pBits, *pLocal, *pArraySize = nullptr;
pContext->LocalToString(params[1], &cls);
pContext->LocalToString(params[2], &prop);
@@ -1186,13 +1272,11 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params)
#define FIND_PROP_SEND(type, type_name) \
sm_sendprop_info_t info;\
SendProp *pProp; \
IServerUnknown *pUnk = (IServerUnknown *)pEntity; \
IServerNetworkable *pNet = pUnk->GetNetworkable(); \
if (!pNet) \
{ \
return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \
ServerClass *pServerClass = g_HL2.FindEntityServerClass(pEntity); \
if (pServerClass == nullptr) { \
pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", g_HL2.ReferenceToIndex(params[1]), params[1]); \
} \
if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) \
if (!g_HL2.FindSendPropInfo(pServerClass->GetName(), prop, &info)) \
{ \
const char *class_name = g_HL2.GetEntityClassname(pEntity); \
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \
@@ -1350,13 +1434,13 @@ static cell_t GetEntPropArraySize(IPluginContext *pContext, const cell_t *params
{
sm_sendprop_info_t info;
IServerUnknown *pUnk = (IServerUnknown *)pEntity;
IServerNetworkable *pNet = pUnk->GetNetworkable();
if (!pNet)
ServerClass *pServerClass = g_HL2.FindEntityServerClass(pEntity);
if (pServerClass == nullptr)
{
return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]);
return pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", g_HL2.ReferenceToIndex(params[1]), params[1]);
}
if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info))
if (!g_HL2.FindSendPropInfo(pServerClass->GetName(), prop, &info))
{
const char *class_name = g_HL2.GetEntityClassname(pEntity);
return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)",
@@ -1452,7 +1536,8 @@ static cell_t GetEntProp(IPluginContext *pContext, const cell_t *params)
// This isn't in CS:S yet, but will be, doesn't hurt to add now, and will save us a build later
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2 \
|| SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|| SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_PVKII \
|| SOURCE_ENGINE == SE_MCV
if (pProp->GetFlags() & SPROP_VARINT)
{
bit_count = sizeof(int) * 8;
@@ -1571,7 +1656,8 @@ static cell_t SetEntProp(IPluginContext *pContext, const cell_t *params)
// This isn't in CS:S yet, but will be, doesn't hurt to add now, and will save us a build later
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_SDK2013 || SOURCE_ENGINE == SE_TF2 \
|| SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
|| SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_PVKII \
|| SOURCE_ENGINE == SE_MCV
if (pProp->GetFlags() & SPROP_VARINT)
{
bit_count = sizeof(int) * 8;
@@ -1993,13 +2079,7 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params)
edict_t *pOtherEdict = NULL;
if (pOther)
{
IServerNetworkable *pNetworkable = ((IServerUnknown *) pOther)->GetNetworkable();
if (!pNetworkable)
{
return pContext->ThrowNativeError("Entity %d (%d) does not have a valid edict", g_HL2.ReferenceToIndex(params[4]), params[4]);
}
pOtherEdict = pNetworkable->GetEdict();
pOtherEdict = BaseEntityToEdict(pOther);
if (!pOtherEdict || pOtherEdict->IsFree())
{
return pContext->ThrowNativeError("Entity %d (%d) does not have a valid edict", g_HL2.ReferenceToIndex(params[4]), params[4]);
@@ -2502,7 +2582,7 @@ static int32_t SDKEntFlagToSMEntFlag(int flag)
case FL_FREEZING:
return ENTFLAG_FREEZING;
#elif SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
case FL_EP2V_UNKNOWN:
return ENTFLAG_EP2V_UNKNOWN1;
#endif
@@ -2581,7 +2661,7 @@ static int32_t SMEntFlagToSDKEntFlag(int32_t flag)
case ENTFLAG_FREEZING:
return FL_FREEZING;
#elif SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_SDK2013 \
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2
|| SOURCE_ENGINE == SE_BMS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_PVKII
case ENTFLAG_EP2V_UNKNOWN1:
return FL_EP2V_UNKNOWN;
#endif
@@ -2744,5 +2824,7 @@ REGISTER_NATIVES(entityNatives)
{"SetEntPropVector", SetEntPropVector},
{"GetEntityAddress", GetEntityAddress},
{"FindDataMapInfo", FindDataMapInfo},
{"LoadEntityFromHandleAddress", LoadEntityFromHandleAddress},
{"StoreEntityToHandleAddress", StoreEntityToHandleAddress},
{NULL, NULL}
};
+2
View File
@@ -505,6 +505,7 @@ static cell_t GuessSDKVersion(IPluginContext *pContext, const cell_t *params)
case SOURCE_ENGINE_TF2:
case SOURCE_ENGINE_BMS:
case SOURCE_ENGINE_SDK2013:
case SOURCE_ENGINE_PVKII:
return 35;
case SOURCE_ENGINE_LEFT4DEAD:
return 40;
@@ -518,6 +519,7 @@ static cell_t GuessSDKVersion(IPluginContext *pContext, const cell_t *params)
return 70;
case SOURCE_ENGINE_CSGO:
return 80;
// Deprecated, and not very useful. Don't bother adding new games
}
return 0;
+28 -1
View File
@@ -41,6 +41,8 @@
#include <game/shared/csgo/protobuf/cstrike15_usermessages.pb.h>
#elif SOURCE_ENGINE == SE_BLADE
#include <game/shared/berimbau/protobuf/berimbau_usermessages.pb.h>
#elif SOURCE_ENGINE == SE_MCV
#include <game/shared/vietnam/protobuf/vietnam_usermessages.pb.h>
#endif
#define MAX_HUD_CHANNELS 6
@@ -70,6 +72,7 @@ struct hud_text_parms
float holdTime;
float fxTime;
int channel;
bool isSet = false;
};
class HudMsgHelpers :
@@ -282,6 +285,7 @@ static cell_t SetHudTextParams(IPluginContext *pContext, const cell_t *params)
g_hud_params.g2 = 255;
g_hud_params.b2 = 250;
g_hud_params.a2 = 0;
g_hud_params.isSet = true;
return 1;
}
@@ -308,6 +312,7 @@ static cell_t SetHudTextParamsEx(IPluginContext *pContext, const cell_t *params)
g_hud_params.g2 = static_cast<byte>(color2[1]);
g_hud_params.b2 = static_cast<byte>(color2[2]);
g_hud_params.a2 = static_cast<byte>(color2[3]);
g_hud_params.isSet = true;
return 1;
}
@@ -318,8 +323,12 @@ void UTIL_SendHudText(int client, const hud_text_parms &textparms, const char *p
players[0] = client;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
CCSUsrMsg_HudMsg *msg = (CCSUsrMsg_HudMsg *)g_UserMsgs.StartProtobufMessage(g_HudMsgNum, players, 1, 0);
if (!msg)
{
return;
}
msg->set_channel(textparms.channel & 0xFF);
CMsgVector2D *pos = msg->mutable_pos();
@@ -373,13 +382,22 @@ static cell_t ShowSyncHudText(IPluginContext *pContext, const cell_t *params)
Handle_t err;
CPlayer *pPlayer;
hud_syncobj_t *obj;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
char message_buffer[512];
#else
char message_buffer[255-36];
#endif
if (!s_HudMsgHelpers.IsSupported())
{
return -1;
}
if (!g_hud_params.isSet)
{
return pContext->ThrowNativeError("ShowSyncHudText first requires a call to SetHudTextParams or SetHudTextParamsEx");
}
if ((err = s_HudMsgHelpers.ReadHudSyncObj(params[2], pContext->GetIdentity(), &obj)) != HandleError_None)
{
return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[2], err);
@@ -453,13 +471,22 @@ static cell_t ShowHudText(IPluginContext *pContext, const cell_t *params)
{
int client;
CPlayer *pPlayer;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_BLADE || SOURCE_ENGINE == SE_MCV
char message_buffer[512];
#else
char message_buffer[255-36];
#endif
if (!s_HudMsgHelpers.IsSupported())
{
return -1;
}
if (!g_hud_params.isSet)
{
return pContext->ThrowNativeError("ShowHudText first requires a call to SetHudTextParams or SetHudTextParamsEx");
}
client = params[1];
if ((pPlayer = g_Players.GetPlayerByIndex(client)) == NULL)
{
+14 -2
View File
@@ -669,9 +669,21 @@ static cell_t smn_KvRewind(IPluginContext *pCtx, const cell_t *params)
return pCtx->ThrowNativeError("Invalid key value handle %x (error %d)", hndl, herr);
}
while (pStk->pCurRoot.size() > 1)
// Older plugins do not have the clearHistory param
if (params[0] < 2 || params[2])
{
pStk->pCurRoot.pop();
while (pStk->pCurRoot.size() > 1)
{
pStk->pCurRoot.pop();
}
}
else
{
auto root = pStk->pCurRoot.begin();
if (root != pStk->pCurRoot.end())
{
pStk->pCurRoot.push(*root);
}
}
return 1;
+22
View File
@@ -356,6 +356,27 @@ static cell_t GetAvgPackets(IPluginContext *pContext, const cell_t *params)
return sp_ftoc(value);
}
static cell_t sm_GetClientIClient(IPluginContext *pContext, const cell_t *params)
{
int client = params[1];
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer)
{
return pContext->ThrowNativeError("Client index %d is invalid", client);
}
else if (!pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client %d is not connected", client);
}
else if (pPlayer->IsFakeClient())
{
return pContext->ThrowNativeError("Client %d is a bot", client);
}
return (cell_t)pPlayer->GetIClient();
}
static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params)
{
int client = params[1];
@@ -392,6 +413,7 @@ REGISTER_NATIVES(playernatives)
{"GetClientAvgChoke", GetAvgChoke},
{"GetClientAvgData", GetAvgData},
{"GetClientAvgPackets", GetAvgPackets},
{"GetClientIClient", sm_GetClientIClient },
{"RunAdminCacheChecks", RunAdminCacheChecks},
{NULL, NULL}
};
+1 -1
View File
@@ -70,7 +70,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen
PLUGIN_SAVEVARS();
GET_V_IFACE_ANY(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_SDK2013
#if SOURCE_ENGINE == SE_SDK2013
// Shim to avoid hooking shims
engine = (IVEngineServer *)ismm->GetEngineFactory()("VEngineServer023", nullptr);
if (!engine)
+30 -3
View File
@@ -46,6 +46,7 @@
#include <amtl/os/am-path.h>
#include <bridge/include/IExtensionBridge.h>
#include <bridge/include/IScriptManager.h>
#include <bridge/include/IProviderCallbacks.h>
#include <bridge/include/ILogger.h>
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
@@ -53,6 +54,7 @@ SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool);
SH_DECL_HOOK1_void(IServerGameDLL, Think, SH_NOATTRIB, false, bool);
SH_DECL_HOOK1_void(IVEngineServer, ServerCommand, SH_NOATTRIB, false, const char *);
SH_DECL_HOOK0(IVEngineServer, GetMapEntitiesString, SH_NOATTRIB, 0, const char *);
SourceModBase g_SourceMod;
@@ -277,6 +279,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
/* Hook this now so we can detect startup without calling StartSourceMod() */
SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
SH_ADD_HOOK(IVEngineServer, GetMapEntitiesString, engine, SH_MEMBER(this, &SourceModBase::GetMapEntitiesString), false);
/* Only load if we're not late */
if (!late)
@@ -290,7 +293,6 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
void SourceModBase::StartSourceMod(bool late)
{
SH_ADD_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false);
SH_ADD_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::Think), false);
SH_ADD_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
enginePatch = SH_GET_CALLCLASS(engine);
@@ -362,6 +364,8 @@ void SourceModBase::StartSourceMod(bool late)
{
g_pSourcePawn2->InstallWatchdogTimer(atoi(timeout) * 1000);
}
SH_ADD_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(logicore.callbacks, &IProviderCallbacks::OnThink), false);
}
static bool g_LevelEndBarrier = false;
@@ -414,10 +418,32 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch
g_LevelEndBarrier = true;
int parseError;
size_t position;
bool success = logicore.ParseEntityLumpString(pMapEntities, parseError, position);
logicore.SetEntityLumpWritable(true);
g_pOnMapInit->PushString(pMapName);
g_pOnMapInit->Execute();
logicore.SetEntityLumpWritable(false);
RETURN_META_VALUE(MRES_IGNORED, true);
if (!success)
{
logger->LogError("Map entity lump parsing for %s failed with error code %d on position %d", pMapName, parseError, position);
RETURN_META_VALUE(MRES_IGNORED, true);
}
RETURN_META_VALUE_NEWPARAMS(MRES_HANDLED, true, &IServerGameDLL::LevelInit, (pMapName, logicore.GetEntityLumpString(), pOldLevel, pLandmarkName, loadGame, background));
}
const char *SourceModBase::GetMapEntitiesString()
{
const char *pNewMapEntities = logicore.GetEntityLumpString();
if (pNewMapEntities != nullptr)
{
RETURN_META_VALUE(MRES_SUPERCEDE, pNewMapEntities);
}
RETURN_META_VALUE(MRES_IGNORED, NULL);
}
void SourceModBase::LevelShutdown()
@@ -532,6 +558,7 @@ void SourceModBase::CloseSourceMod()
return;
SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(this, &SourceModBase::LevelInit), false);
SH_REMOVE_HOOK(IVEngineServer, GetMapEntitiesString, engine, SH_MEMBER(this, &SourceModBase::GetMapEntitiesString), false);
if (g_Loaded)
{
@@ -596,8 +623,8 @@ void SourceModBase::ShutdownServices()
}
SH_REMOVE_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SourceModBase::LevelShutdown), false);
SH_REMOVE_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::Think), false);
SH_REMOVE_HOOK(IServerGameDLL, GameFrame, gamedll, SH_MEMBER(&g_Timers, &TimerSystem::GameFrame), false);
SH_REMOVE_HOOK(IServerGameDLL, Think, gamedll, SH_MEMBER(logicore.callbacks, &IProviderCallbacks::OnThink), false);
}
void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...)
+1
View File
@@ -140,6 +140,7 @@ public: // ISourceMod
private:
void ShutdownServices();
private:
const char* GetMapEntitiesString();
char m_SMBaseDir[PLATFORM_MAX_PATH];
char m_SMRelDir[PLATFORM_MAX_PATH];
char m_ModDir[32];
File diff suppressed because one or more lines are too long
+9 -2
View File
@@ -80,8 +80,15 @@ CallWrapper::CallWrapper(const SourceHook::ProtoInfo *protoInfo) : m_FnFlags(0)
CallWrapper::CallWrapper(const SourceHook::ProtoInfo *protoInfo, const PassInfo *retInfo,
const PassInfo paramInfo[], unsigned int fnFlags) : CallWrapper(protoInfo)
{
m_RetParam->fields = retInfo->fields;
m_RetParam->numFields = retInfo->numFields;
if (retInfo)
{
m_RetParam->fields = retInfo->fields;
m_RetParam->numFields = retInfo->numFields;
}
else
{
m_RetParam = nullptr;
}
unsigned int argnum = protoInfo->numOfParams;
for (unsigned int i = 0; i < argnum; i++)
+10 -2
View File
@@ -725,7 +725,7 @@ inline void Write_PushObject(JitWriter *jit, const SourceHook::PassInfo *info, u
ObjectClass classes[MAX_CLASSES];
int numWords = ClassifyObject(smInfo, classes);
if (classes[0] == ObjectClass::Pointer)
if (classes[0] == ObjectClass::Pointer || classes[0] == ObjectClass::Memory)
goto push_byref;
int neededIntRegs = 0;
@@ -787,7 +787,7 @@ inline void Write_PushObject(JitWriter *jit, const SourceHook::PassInfo *info, u
return;
#elif defined PLATFORM_WINDOWS
if (info->size < 64 && (info->size & (info->size - 1)) == 0)
if (info->size > 8 || (info->size & (info->size - 1)) != 0)
goto push_byref;
else {
SourceHook::PassInfo podInfo;
@@ -1055,7 +1055,11 @@ void *JIT_CallCompile(CallWrapper *pWrapper, FuncAddrMethod method)
int numWords;
#endif
#ifdef PLATFORM_POSIX
g_StackUsage = 0;
#elif defined PLATFORM_WINDOWS
g_StackUsage = 32; // Shadow space
#endif
writer.outbase = NULL;
writer.outptr = NULL;
@@ -1155,8 +1159,12 @@ skip_retbuffer:
#endif
/* Clean up the calling stack */
#ifdef PLATFORM_POSIX
if (hasParams && g_StackUsage)
#endif
{
Write_RectifyStack(jit, g_StackAlign);
}
/* Copy the return type to the return buffer if the function is not void */
if (pRet && !Needs_Retbuf)
+1 -1
View File
@@ -398,7 +398,7 @@ cell_t AddSettingsPrefabMenuItem(IPluginContext *pContext, const cell_t *params)
/* User passed a function id for a callback */
if (params[4] != -1)
if (!pContext->IsNullFunctionId(params[4]))
{
pItem->forward = forwards->CreateForwardEx(NULL, ET_Ignore, 5, NULL, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell);
pItem->forward->AddFunction(pContext, static_cast<funcid_t>(params[4]));
+11 -17
View File
@@ -9,15 +9,7 @@ project.sources += [
'timeleft.cpp',
'forwards.cpp',
'util_cstrike.cpp',
'../../public/smsdk_ext.cpp',
'../../public/CDetour/detours.cpp',
'../../public/asm/asm.c',
'../../public/libudis86/decode.c',
'../../public/libudis86/itab.c',
'../../public/libudis86/syn-att.c',
'../../public/libudis86/syn-intel.c',
'../../public/libudis86/syn.c',
'../../public/libudis86/udis86.c',
'../../public/smsdk_ext.cpp'
]
for sdk_name in ['css', 'csgo']:
@@ -29,31 +21,33 @@ for sdk_name in ['css', 'csgo']:
project.sources += ['rulesfix.cpp']
for cxx in builder.targets:
if not cxx.target.arch in sdk.platformSpec[cxx.target.platform]:
if not cxx.target.arch in sdk['platforms'][cxx.target.platform]:
continue
cxx.defines += ['HAVE_STRING_H']
binary = SM.HL2ExtConfig(project, builder, cxx, 'game.cstrike.ext.' + sdk.ext, sdk)
binary = SM.HL2ExtConfig(project, builder, cxx, 'game.cstrike.ext.' + sdk['extension'], sdk)
SM.AddCDetour(binary)
if sdk_name == 'csgo':
compiler = binary.compiler
compiler.cxxincludes += [os.path.join(sdk.path, 'public', 'steam')]
compiler.cxxincludes += [os.path.join(sdk['path'], 'public', 'steam')]
compiler.defines += ['VERSION_SAFE_STEAM_API_INTERFACES']
library_name = ''
if cxx.target.platform == 'windows':
compiler.linkflags += [os.path.join(sdk.path, 'lib', 'public', 'steam_api.lib')]
compiler.linkflags += [os.path.join(sdk['path'], 'lib', 'public', 'steam_api.lib')]
elif cxx.target.platform == 'linux':
library_name = 'libsteam_api.so'
if cxx.target.arch == 'x86_64':
source_path = os.path.join(sdk.path, 'lib', 'linux64')
source_path = os.path.join(sdk['path'], 'lib', 'linux64')
else:
source_path = os.path.join(sdk.path, 'lib', 'linux')
source_path = os.path.join(sdk['path'], 'lib', 'linux')
elif cxx.target.platform == 'mac':
library_name = 'libsteam_api.dylib'
if cxx.target.arch == 'x86_64':
source_path = os.path.join(sdk.path, 'lib', 'osx64')
source_path = os.path.join(sdk['path'], 'lib', 'osx64')
else:
source_path = os.path.join(sdk.path, 'lib', 'mac')
source_path = os.path.join(sdk['path'], 'lib', 'mac')
if library_name:
source_path = os.path.join(source_path, library_name)
+1 -1
View File
@@ -100,7 +100,7 @@ bool CStrike::SDK_OnLoad(char *error, size_t maxlength, bool late)
g_pHandleBuyForward = forwards->CreateForward("CS_OnBuyCommand", ET_Event, 2, NULL, Param_Cell, Param_String);
g_pPriceForward = forwards->CreateForward("CS_OnGetWeaponPrice", ET_Event, 3, NULL, Param_Cell, Param_String, Param_CellByRef);
g_pTerminateRoundForward = forwards->CreateForward("CS_OnTerminateRound", ET_Event, 2, NULL, Param_FloatByRef, Param_CellByRef);
g_pCSWeaponDropForward = forwards->CreateForward("CS_OnCSWeaponDrop", ET_Event, 2, NULL, Param_Cell, Param_Cell);
g_pCSWeaponDropForward = forwards->CreateForward("CS_OnCSWeaponDrop", ET_Event, 3, NULL, Param_Cell, Param_Cell, Param_Cell);
m_TerminateRoundDetourEnabled = false;

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