Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
66442b7
fix: Ensure CPlayer vtable validity before virtual calls
ELDment Nov 15, 2025
66083b8
fix: Ensure options are properly locked for thread safety
ELDment Nov 15, 2025
6ca89fc
fix: Add null check for CPlayer pointer before vtable validation
ELDment Nov 15, 2025
a9d0bc9
Merge pull request #100 from ELDment/beta-2
skuzzis Nov 15, 2025
412f6d3
fix: Resolve crash issue caused by duplicate CPlayer initialization
ELDment Nov 16, 2025
aff0b5a
fix: Add null check for invalid player in CheckTransmitHook
ELDment Nov 16, 2025
500ab40
chore: Add async submenu loading test code
ELDment Nov 16, 2025
380d2ea
fix(managed): Fix DropWeapon
samyycX Nov 16, 2025
0b38fe1
feat(managed): More math methods
samyycX Nov 16, 2025
6b61ed9
fix: Resolve menu cycling issue caused by failure to distinguish clos…
ELDment Nov 16, 2025
dc2ecf6
feat(steamworks): Add ToSteamIdOnline
samyycX Nov 16, 2025
8b5d64a
fix: Fix TerminateRound
ELDment Nov 16, 2025
e5b1f5c
fix: Resolve platform differences for TerminateRound
ELDment Nov 16, 2025
eb9ba0d
chore: Avoid unnecessary overhead
ELDment Nov 16, 2025
802a1fb
feat(managed): Add RunCommand event
samyycX Nov 16, 2025
ff21db8
fix(managed): fix build
samyycX Nov 16, 2025
9c74ddf
fix(managed): Move steamid online to proper place
samyycX Nov 16, 2025
66c1e80
fix(generator): Clean unused method
samyycX Nov 16, 2025
2d0acb7
feat(managed): Expose soundevent guid
samyycX Nov 16, 2025
f4e753f
chore: Add defensive programming checks across all player methods
ELDment Nov 16, 2025
2a17c90
fix: Prevent race condition in player lifecycle management
ELDment Nov 16, 2025
947d1bd
feat(API): OnWorldUpdate + NextWorldUpdate
skuzzis Nov 16, 2025
b414052
Merge branch 'beta' of https://github.com/swiftly-solution/swiftlys2 …
skuzzis Nov 16, 2025
8f34016
fix(events): OnWorldUpdate register
skuzzis Nov 16, 2025
f983a10
feat(BasePlugin): OnSharedInterfaceInjected
skuzzis Nov 16, 2025
ec5c4af
feat(BasePlugin): OnAllPluginsLoaded
skuzzis Nov 16, 2025
fad2892
perf(netmessages): Send player mask
skuzzis Nov 16, 2025
893d3f4
update(SetClientConvar): Use MessageID
skuzzis Nov 16, 2025
12f5c1b
update(template): update target framework to .NET 10
m3ntorsky Nov 16, 2025
74d5577
refactor: Implement more reasonable plugin management
ELDment Nov 16, 2025
23b6b31
Merge upstream/beta into beta-5
ELDment Nov 16, 2025
c35ae56
[skip ci] Merge pull request #103 from m3ntorsky/master
skuzzis Nov 16, 2025
20bbfb7
fix(status): Map Name
skuzzis Nov 16, 2025
abcc059
revert(natives): String changes
skuzzis Nov 17, 2025
1ffe8fa
Merge remote-tracking branch 'upstream/beta' into beta-3
ELDment Nov 17, 2025
32b73cf
Merge remote-tracking branch 'upstream/beta' into beta-5
ELDment Nov 17, 2025
816dd56
perf(native): PostEventAbstract calls
skuzzis Nov 17, 2025
6a4be71
refactor: Eliminate redundancy and improve code organization in Plugi…
ELDment Nov 17, 2025
794eb5e
fix: Properly close menus
ELDment Nov 17, 2025
50d858e
refactor: Eliminate redundancy and improve code organization in Plugi…
ELDment Nov 17, 2025
cf886a3
refactor: Eliminate redundancy and improve code organization in Plugi…
ELDment Nov 17, 2025
60e258f
feat(API/Engine): WorkshopId
skuzzis Nov 17, 2025
eb58730
refactor: Improve CoreCommandService readability and code quality
ELDment Nov 18, 2025
a417b2b
fix: Improve plugin status handling
ELDment Nov 18, 2025
4224b92
refactor: Enhanced plugin management system with better adaptability
ELDment Nov 18, 2025
5def8b7
fix: Auto hot reload logic issues
ELDment Nov 18, 2025
f4b8827
refactor: Improve command usage clarity
ELDment Nov 18, 2025
55128cb
Merge pull request #102 from ELDment/beta-3
skuzzis Nov 18, 2025
e875b38
fix(GetWorkshopId): Another method
skuzzis Nov 18, 2025
53a6c0a
Merge branch 'beta' of https://github.com/swiftly-solution/swiftlys2 …
skuzzis Nov 18, 2025
a07c907
fix(WorkshopId): Reset on map change
skuzzis Nov 18, 2025
d6160a4
fix: Typo
ELDment Nov 18, 2025
dc82068
fix: Wait for DLL file lock release before hot reload
ELDment Nov 18, 2025
66a9e60
chore: Clean up code
ELDment Nov 18, 2025
0b79890
Merge pull request #104 from ELDment/beta-5
skuzzis Nov 18, 2025
20a6bec
refactor: Thoroughly format code and follow naming conventions
ELDment Nov 18, 2025
a3f3271
feat: Implement OnPlayerPawnPostThinkHook event
ELDment Nov 18, 2025
4882c5a
chore: Clean up code
ELDment Nov 18, 2025
2bedf55
Merge pull request #109 from ELDment/beta-3
skuzzis Nov 18, 2025
55ebebe
feat: Add AddTerroristWins and AddCTWins interfaces
ELDment Nov 19, 2025
eab8686
feat: Add overloads for AddTerroristWins and AddCTWins
ELDment Nov 19, 2025
1ed8697
fix: Correct TerminateRound function definition
ELDment Nov 19, 2025
a122fb9
chore: Add Linux support for AddTerroristWins and AddCTWins
ELDment Nov 19, 2025
b5f6067
feat: Add CMoveData, CMoveDataBase, SubtickMove and TouchListT struct…
ELDment Nov 19, 2025
4ca702b
[skip ci]Add ClearPermission method to IPermissionManager
himenekocn Nov 19, 2025
b41f01a
Add ClearPermission method to PermissionManager
himenekocn Nov 19, 2025
6c7c369
Merge pull request #111 from himenekocn/beta
skuzzis Nov 19, 2025
dde6e1d
chore: Clean up code
ELDment Nov 19, 2025
ba87838
chore: Follow coding standards
ELDment Nov 19, 2025
2bb3c5d
fix: TerminateRound definition on Linux
ELDment Nov 19, 2025
833123c
fix: Correct SubtickMove memory padding alignment
ELDment Nov 19, 2025
e4c9940
Merge pull request #112 from ELDment/beta-5
skuzzis Nov 19, 2025
633a570
feat(API/PlayerManager): Helpers (suggestion from @zakriamansoor47)
skuzzis Nov 19, 2025
934ed2d
feat(managed): Add GamePhase enum
samyycX Nov 19, 2025
62ecb87
feat(managed): Add Team
samyycX Nov 19, 2025
072d37d
feat(managed): Fix some types
samyycX Nov 19, 2025
b0d7c8d
feat(managed): Add gamephase enum
samyycX Nov 19, 2025
41af18c
Merge pull request #113 from swiftly-solution/feat/few_schema_update
skuzzis Nov 19, 2025
87fa8d8
chore: Merge upstream beta
ELDment Nov 19, 2025
67d8e8b
feat: Implement CCSMatch structure and GameService
ELDment Nov 19, 2025
7dea468
feat: Complete implementation of CCSMatch
ELDment Nov 19, 2025
b968ee5
refactor: Improve interface and struct design
ELDment Nov 19, 2025
87797bb
chore: Clean up
ELDment Nov 19, 2025
1bb0a37
chore: Clean up code
ELDment Nov 19, 2025
821b422
Merge pull request #110 from ELDment/beta-3
skuzzis Nov 19, 2025
a94586a
perf(managed): Create Entity using template
skuzzis Nov 19, 2025
5e55409
feat(managed): Allocator, few change in CCSMatch
samyycX Nov 20, 2025
1b01558
feat(managed): Support nested 2 vtable
samyycX Nov 20, 2025
28e6e92
feat(managed): Add helper to get schema size
samyycX Nov 20, 2025
e2a5bcc
feat(API): Projectile EmitGrenade
skuzzis Nov 20, 2025
d75241d
Merge branch 'beta' of https://github.com/swiftly-solution/swiftlys2 …
skuzzis Nov 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 18 additions & 0 deletions ACKNOWLEDGEMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ CS2Fixes is and will always be a great repository for RE stuff in CS2.
*/
```

## CS2KZ-Metamod

We've taken CMoveData structure and it's stuff used in that.

```
/*
* CS2KZ-Metamod 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.
*
* CS2KZ-Metamod 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.
*/
```

## CounterStrikeSharp

We've inspired the feature VoiceManager with the one from CounterStrikeSharp.
Expand Down
162 changes: 75 additions & 87 deletions generator/native_generator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self):

def add_line(self, text: str = ""):
if text.strip():
self.lines.append(" " * self.indent_level + text)
self.lines.append(" " * self.indent_level + text)
else:
self.lines.append("")

Expand All @@ -62,15 +62,14 @@ def dedent(self):
self.indent_level = max(0, self.indent_level - 1)

def add_block(self, header: str, content_func):
self.add_line(header)
self.add_line("{")
self.add_line(header + " {")
self.indent()
content_func()
self.dedent()
self.add_line("}")

def get_code(self) -> str:
return "\r\n".join(self.lines)
return "\n".join(self.lines)


def split_by_last_dot(value: str):
Expand All @@ -95,6 +94,7 @@ def parse_native(lines: list[str]):
writer.add_line("#pragma warning disable CS0649")
writer.add_line("#pragma warning disable CS0169")
writer.add_line()
writer.add_line("using System.Buffers;")
writer.add_line("using System.Text;")
writer.add_line("using System.Threading;")
writer.add_line("using SwiftlyS2.Shared.Natives;")
Expand Down Expand Up @@ -158,68 +158,24 @@ def write_method_content():
if is_marked_sync:
writer.add_block("if (Thread.CurrentThread.ManagedThreadId != _MainThreadID)", lambda: writer.add_line('throw new InvalidOperationException("This method can only be called from the main thread.");'))

string_params = [n for t, n in param_signatures if t == "string"]
bytes_params = [n for t, n in param_signatures if t == "byte[]"]

for param in bytes_params:
writer.add_line(f"var {param}Length = {param}.Length;")

if not string_params:
fixed_blocks = []
for param in bytes_params:
fixed_blocks.append(f"fixed (byte* {param}BufferPtr = {param})")

def write_simple_call():
call_args = []
for t, n in param_signatures:
if t == "byte[]":
call_args.extend([f"{n}BufferPtr", f"{n}Length"])
elif t == "bool":
call_args.append(f"{n} ? (byte)1 : (byte)0")
else:
call_args.append(n)

if is_buffer_return(return_type):
first_call_args = ["null"] + call_args
writer.add_line(f"var ret = _{function_name}({', '.join(first_call_args)});")
if return_type == "string":
writer.add_line("var retBuffer = new byte[ret + 1];")
else:
writer.add_line("var retBuffer = new byte[ret];")

def write_ret_fixed():
second_call_args = ["retBufferPtr"] + call_args
writer.add_line(f"ret = _{function_name}({', '.join(second_call_args)});")
if return_type == "string":
writer.add_line("return Encoding.UTF8.GetString(retBufferPtr, ret);")
else:
writer.add_line("var retBytes = new byte[ret];")
writer.add_line("for (int i = 0; i < ret; i++) retBytes[i] = retBufferPtr[i];")
writer.add_line("return retBytes;")

writer.add_block("fixed (byte* retBufferPtr = retBuffer)", write_ret_fixed)
else:
if return_type == "void":
writer.add_line(f"_{function_name}({', '.join(call_args)});")
else:
writer.add_line(f"var ret = _{function_name}({', '.join(call_args)});")
writer.add_line("return ret == 1;" if return_type == "bool" else "return ret;")

def write_with_fixed_blocks(blocks, index=0):
if index < len(blocks):
writer.add_block(blocks[index], lambda: write_with_fixed_blocks(blocks, index + 1))
else:
write_simple_call()

if fixed_blocks:
write_with_fixed_blocks(fixed_blocks)
else:
write_simple_call()
return

for param in string_params:
writer.add_line(f"byte[] {param}Buffer = Encoding.UTF8.GetBytes({param} + \"\\0\");")
string_params = []
bytes_params = []
pool_declared = False

for t, n in param_signatures:
if t == "string":
if not pool_declared:
writer.add_line("var pool = ArrayPool<byte>.Shared;")
pool_declared = True
writer.add_line(f"var {n}Length = Encoding.UTF8.GetByteCount({n});")
writer.add_line(f"var {n}Buffer = pool.Rent({n}Length + 1);")
writer.add_line(f"Encoding.UTF8.GetBytes({n}, {n}Buffer);")
writer.add_line(f"{n}Buffer[{n}Length] = 0;")
string_params.append(n)
elif t == "byte[]":
writer.add_line(f"var {n}Length = {n}.Length;")
bytes_params.append(n)

fixed_blocks = []
for param in string_params:
fixed_blocks.append(f"fixed (byte* {param}BufferPtr = {param}Buffer)")
Expand All @@ -228,42 +184,77 @@ def write_with_fixed_blocks(blocks, index=0):

def write_native_call():
call_args = []
for t, n in param_signatures:
if t == "string":
call_args.append(f"{n}BufferPtr")
elif t == "byte[]":
call_args.extend([f"{n}BufferPtr", f"{n}Length"])
elif t == "bool":
call_args.append(f"{n} ? (byte)1 : (byte)0")
else:
call_args.append(n)

if is_buffer_return(return_type):
first_call_args = ["null"] + call_args
first_call_args = ["null"]
for t, n in param_signatures:
if t == "string":
first_call_args.append(f"{n}BufferPtr")
elif t == "byte[]":
first_call_args.extend([f"{n}BufferPtr", f"{n}Length"])
elif t == "bool":
first_call_args.append(f"{n} ? (byte)1 : (byte)0")
else:
first_call_args.append(n)

writer.add_line(f"var ret = _{function_name}({', '.join(first_call_args)});")
if return_type == "string":
writer.add_line("var retBuffer = new byte[ret + 1];")
else:
writer.add_line("var retBuffer = new byte[ret];")

if not pool_declared:
writer.add_line("var pool = ArrayPool<byte>.Shared;")
writer.add_line("var retBuffer = pool.Rent(ret + 1);")

def write_ret_fixed():
second_call_args = ["retBufferPtr"] + call_args
second_call_args = ["retBufferPtr"]
for t, n in param_signatures:
if t == "string":
second_call_args.append(f"{n}BufferPtr")
elif t == "byte[]":
second_call_args.extend([f"{n}BufferPtr", f"{n}Length"])
elif t == "bool":
second_call_args.append(f"{n} ? (byte)1 : (byte)0")
else:
second_call_args.append(n)

writer.add_line(f"ret = _{function_name}({', '.join(second_call_args)});")

if return_type == "string":
writer.add_line("return Encoding.UTF8.GetString(retBufferPtr, ret);")
writer.add_line("var retString = Encoding.UTF8.GetString(retBufferPtr, ret);")
writer.add_line("pool.Return(retBuffer);")
for param in string_params:
writer.add_line(f"pool.Return({param}Buffer);")
writer.add_line("return retString;")
else:
writer.add_line("var retBytes = new byte[ret];")
writer.add_line("for (int i = 0; i < ret; i++) retBytes[i] = retBufferPtr[i];")
writer.add_line("pool.Return(retBuffer);")
for param in string_params:
writer.add_line(f"pool.Return({param}Buffer);")
writer.add_line("return retBytes;")

writer.add_block("fixed (byte* retBufferPtr = retBuffer)", write_ret_fixed)

else:
for t, n in param_signatures:
if t == "string":
call_args.append(f"{n}BufferPtr")
elif t == "byte[]":
call_args.extend([f"{n}BufferPtr", f"{n}Length"])
elif t == "bool":
call_args.append(f"{n} ? (byte)1 : (byte)0")
else:
call_args.append(n)

if return_type == "void":
writer.add_line(f"_{function_name}({', '.join(call_args)});")
else:
writer.add_line(f"var ret = _{function_name}({', '.join(call_args)});")
writer.add_line("return ret == 1;" if return_type == "bool" else "return ret;")


for param in string_params:
writer.add_line(f"pool.Return({param}Buffer);")

if return_type != "void":
writer.add_line("return ret == 1;" if return_type == "bool" else f"return ret;")

def write_with_fixed_blocks(blocks, index=0):
if index < len(blocks):
writer.add_block(blocks[index], lambda: write_with_fixed_blocks(blocks, index + 1))
Expand All @@ -276,10 +267,7 @@ def write_with_fixed_blocks(blocks, index=0):
write_native_call()

writer.add_block(f"public unsafe static {RETURN_TYPE_MAP[return_type]} {function_name}({method_signature})", write_method_content)

# Benchmark class should be public for external access
access_modifier = "public" if class_name == "Benchmark" else "internal"
writer.add_block(f"{access_modifier} static class Native{class_name}", write_class_content)
writer.add_block(f"internal static class Native{class_name}", write_class_content)

with open(out_path, "w", encoding="utf-8", newline="") as f:
f.write(writer.get_code())
Expand Down
Loading
Loading