├── .clang-format ├── .dockerignore ├── .editorconfig ├── .github └── workflows │ ├── linux.yml │ └── windows.yml ├── .gitignore ├── .gitmodules ├── .idea └── .gitignore ├── .vscode ├── c_cpp_properties.json └── launch.json ├── BuildInfo.h.in ├── CyberpunkMP.code-workspace ├── Dockerfile ├── LICENSE.md ├── MakeVSLatestProjects.cmd ├── README.md ├── code ├── assets │ ├── Archives │ │ ├── .gitignore │ │ ├── CyberpunkMP.cpmodproj │ │ ├── layout.xml │ │ ├── packed │ │ │ └── archive │ │ │ │ └── pc │ │ │ │ └── mod │ │ │ │ └── CyberpunkMP.archive │ │ ├── source │ │ │ └── archive │ │ │ │ ├── base │ │ │ │ └── gameplay │ │ │ │ │ └── gui │ │ │ │ │ └── prototype_hud.inkhud │ │ │ │ ├── mods │ │ │ │ └── cyberpunkmp │ │ │ │ │ ├── default_male.ccstate │ │ │ │ │ ├── minimap_mappin.inkwidget │ │ │ │ │ ├── minimap_mappin_player.inkwidget │ │ │ │ │ ├── multiplayer_ui.inkanim │ │ │ │ │ ├── multiplayer_ui.inkwidget │ │ │ │ │ ├── muppet.ent │ │ │ │ │ ├── player_ma_fpp.ent │ │ │ │ │ ├── player_ma_tpp.ent │ │ │ │ │ ├── player_ma_tpp_cutscene.ent │ │ │ │ │ ├── player_wa_fpp.ent │ │ │ │ │ ├── player_wa_tpp_cutscene.ent │ │ │ │ │ ├── workspot_anim.ent │ │ │ │ │ └── workspot_base.workspot │ │ │ │ └── multi │ │ │ │ └── gameplay │ │ │ │ └── gui │ │ │ │ └── widgets │ │ │ │ └── minimap │ │ │ │ └── minimap_pingsystem_mapping.inkwidget │ │ └── xmake.lua │ ├── CET │ │ └── init.lua │ ├── Inputs │ │ ├── CyberpunkMP.xml │ │ └── xmake.lua │ ├── Tweaks │ │ ├── CyberpunkMP.tweak │ │ └── xmake.lua │ ├── redscript │ │ ├── Common.reds │ │ ├── CyberpunkMP.reds │ │ ├── DeathMenu.reds │ │ ├── Ink │ │ │ ├── ChatController.reds │ │ │ ├── ChatHotkeyController.reds │ │ │ ├── ChatMessageController.reds │ │ │ ├── DeliveryListController.reds │ │ │ ├── DeliveryListItemController.reds │ │ │ ├── EmoteSelector.reds │ │ │ ├── EmoteSelectorItem.reds │ │ │ ├── JobListController.reds │ │ │ ├── JobListItemController.reds │ │ │ ├── MultiplayerGameController.reds │ │ │ ├── ServerListController.reds │ │ │ └── ServerListItemController.reds │ │ ├── PhoneHotkeyController.reds │ │ ├── Plugins │ │ │ ├── Delivery.reds │ │ │ ├── Emotes.reds │ │ │ ├── Jobs.reds │ │ │ ├── Mappins.reds │ │ │ └── Taxi.reds │ │ ├── Rpc.reds │ │ ├── World │ │ │ ├── AppearanceSystem.reds │ │ │ ├── ChatSystem.reds │ │ │ ├── InterpolationSystem.reds │ │ │ ├── NetworkWorldSystem.reds │ │ │ └── VehicleSystem.reds │ │ ├── helpers.reds │ │ └── xmake.lua │ └── xmake.lua ├── client │ ├── App │ │ ├── Application.cpp │ │ ├── Application.h │ │ ├── ChatMessageEvent.cpp │ │ ├── ChatMessageEvent.h │ │ ├── Components │ │ │ ├── AttachedComponent.h │ │ │ ├── EntityComponent.h │ │ │ ├── InterpolationComponent.h │ │ │ ├── PlayerComponent.h │ │ │ └── SpawningComponent.h │ │ ├── Debugging │ │ │ ├── DebugService.cpp │ │ │ └── DebugService.h │ │ ├── Extensions │ │ │ └── inkTextInputWidget.cpp │ │ ├── Network │ │ │ ├── NetworkService.cpp │ │ │ ├── NetworkService.h │ │ │ └── Rpc │ │ │ │ ├── RpcCsharp.cpp │ │ │ │ ├── RpcCsharp.h │ │ │ │ ├── RpcGenerator.cpp │ │ │ │ ├── RpcGenerator.h │ │ │ │ ├── RpcPack.cpp │ │ │ │ ├── RpcPack.h │ │ │ │ ├── RpcService.cpp │ │ │ │ ├── RpcService.h │ │ │ │ ├── RpcValidator.cpp │ │ │ │ └── RpcValidator.h │ │ ├── Rendering │ │ │ ├── ImGuiService.cpp │ │ │ ├── ImGuiService.h │ │ │ ├── dx12.cpp │ │ │ ├── dx12.h │ │ │ ├── imgui_user_config.cpp │ │ │ ├── imgui_user_config.h │ │ │ ├── win32.cpp │ │ │ └── win32.h │ │ ├── Settings.cpp │ │ ├── Settings.h │ │ ├── Threading │ │ │ ├── ThreadService.cpp │ │ │ └── ThreadService.h │ │ └── World │ │ │ ├── AppearanceSystem.cpp │ │ │ ├── AppearanceSystem.h │ │ │ ├── ChatSystem.cpp │ │ │ ├── ChatSystem.h │ │ │ ├── InterpolationSystem.cpp │ │ │ ├── InterpolationSystem.h │ │ │ ├── NetworkWorldSystem.cpp │ │ │ ├── NetworkWorldSystem.h │ │ │ ├── RpcDefinition.cpp │ │ │ ├── RpcDefinition.h │ │ │ ├── VehicleSystem.cpp │ │ │ └── VehicleSystem.h │ ├── Core │ │ ├── Container │ │ │ ├── Container.hpp │ │ │ └── Registry.hpp │ │ ├── Facades │ │ │ ├── Container.hpp │ │ │ ├── Hook.hpp │ │ │ ├── Log.hpp │ │ │ ├── Runtime.cpp │ │ │ └── Runtime.hpp │ │ ├── Foundation │ │ │ ├── Application.cpp │ │ │ ├── Application.hpp │ │ │ ├── Feature.hpp │ │ │ ├── LocaleProvider.hpp │ │ │ ├── RuntimeProvider.cpp │ │ │ └── RuntimeProvider.hpp │ │ ├── Hooking │ │ │ ├── Detail.hpp │ │ │ ├── HookingAgent.cpp │ │ │ ├── HookingAgent.hpp │ │ │ ├── HookingDriver.cpp │ │ │ └── HookingDriver.hpp │ │ ├── Logging │ │ │ ├── LoggingAgent.cpp │ │ │ ├── LoggingAgent.hpp │ │ │ ├── LoggingDriver.cpp │ │ │ └── LoggingDriver.hpp │ │ ├── Raw.hpp │ │ ├── Rendering │ │ │ ├── RenderingAgent.cpp │ │ │ ├── RenderingAgent.hpp │ │ │ ├── RenderingDriver.cpp │ │ │ └── RenderingDriver.hpp │ │ ├── Runtime │ │ │ ├── HostImage.cpp │ │ │ ├── HostImage.hpp │ │ │ ├── ModuleImage.cpp │ │ │ ├── ModuleImage.hpp │ │ │ ├── OwnerMutex.cpp │ │ │ └── OwnerMutex.hpp │ │ ├── Stl.hpp │ │ └── Win.hpp │ ├── Game │ │ ├── Animation │ │ │ ├── AnimationData.h │ │ │ ├── AnimationDriver.cpp │ │ │ ├── AnimationDriver.h │ │ │ ├── Base.h │ │ │ ├── MultiMovementController.cpp │ │ │ ├── MultiMovementController.h │ │ │ └── States │ │ │ │ ├── Base.cpp │ │ │ │ ├── Base.h │ │ │ │ ├── Idling.cpp │ │ │ │ ├── Idling.h │ │ │ │ ├── Spawning.cpp │ │ │ │ ├── Spawning.h │ │ │ │ ├── Sprinting.cpp │ │ │ │ ├── Sprinting.h │ │ │ │ ├── Walking.cpp │ │ │ │ └── Walking.h │ │ ├── CharacterCustomizationSystem.h │ │ ├── DelaySystem.h │ │ ├── Entity.h │ │ ├── MappinSystem.h │ │ ├── MorphTargetManagerComponent.h │ │ ├── Movement.h │ │ ├── PlayerSystem.h │ │ ├── Puppet.h │ │ ├── Rendering.h │ │ ├── ScriptValidation.cpp │ │ ├── ScriptValidation.h │ │ ├── Utils.cpp │ │ └── Utils.h │ ├── Main.cpp │ ├── Red │ │ ├── Alias.hpp │ │ ├── Engine.hpp │ │ ├── Engine │ │ │ ├── Framework.hpp │ │ │ ├── LogChannel.hpp │ │ │ ├── Macros │ │ │ │ └── Framework.hpp │ │ │ └── Mappings.hpp │ │ ├── Specializations.hpp │ │ ├── TypeInfo.hpp │ │ ├── TypeInfo │ │ │ ├── Common.hpp │ │ │ ├── Construction.hpp │ │ │ ├── Definition.hpp │ │ │ ├── Invocation.hpp │ │ │ ├── Macros │ │ │ │ ├── Definition.hpp │ │ │ │ └── Resolving.hpp │ │ │ ├── Mappings.hpp │ │ │ ├── Parameters.hpp │ │ │ ├── Registrar.hpp │ │ │ └── Resolving.hpp │ │ ├── Utils.hpp │ │ └── Utils │ │ │ ├── Handles.hpp │ │ │ ├── JobQueues.hpp │ │ │ └── Resources.hpp │ ├── Support │ │ ├── MinHook │ │ │ ├── MinHookProvider.cpp │ │ │ └── MinHookProvider.hpp │ │ ├── RED4ext │ │ │ ├── RED4extProvider.cpp │ │ │ └── RED4extProvider.hpp │ │ ├── RedLib │ │ │ ├── RedLibProvider.cpp │ │ │ └── RedLibProvider.hpp │ │ ├── Renderer │ │ │ ├── RenderingProvider.cpp │ │ │ └── RenderingProvider.hpp │ │ └── Spdlog │ │ │ ├── SpdlogProvider.cpp │ │ │ └── SpdlogProvider.hpp │ ├── stdafx.h │ └── xmake.lua ├── common │ ├── CommonPCH.h │ ├── Core │ │ ├── Allocator.cpp │ │ ├── Allocator.h │ │ ├── AllocatorSymbolOverride.h │ │ ├── BoundedAllocator.cpp │ │ ├── BoundedAllocator.h │ │ ├── Buffer.cpp │ │ ├── Buffer.h │ │ ├── Filesystem.cpp │ │ ├── Filesystem.h │ │ ├── Hash.cpp │ │ ├── Hash.h │ │ ├── Initializer.h │ │ ├── Lockable.h │ │ ├── Locked.h │ │ ├── Memory.h │ │ ├── Meta.h │ │ ├── MimallocAllocator.cpp │ │ ├── MimallocAllocator.h │ │ ├── Outcome.h │ │ ├── Platform.h │ │ ├── ScratchAllocator.cpp │ │ ├── ScratchAllocator.h │ │ ├── Serialization.cpp │ │ ├── Serialization.h │ │ ├── Signal.h │ │ ├── StackAllocator.h │ │ ├── StandardAllocator.cpp │ │ ├── StandardAllocator.h │ │ ├── Stl.h │ │ ├── StlAllocator.h │ │ ├── TaskQueue.cpp │ │ ├── TaskQueue.h │ │ ├── TrackAllocator.h │ │ ├── ViewBuffer.cpp │ │ └── ViewBuffer.h │ ├── Math │ │ ├── Hash.h │ │ ├── Math.cpp │ │ ├── Math.h │ │ ├── Spline.h │ │ ├── Vector2.h │ │ └── Vector3.h │ ├── Network │ │ ├── Client.cpp │ │ ├── Client.h │ │ ├── Packet.cpp │ │ ├── Packet.h │ │ ├── Server.cpp │ │ ├── Server.h │ │ ├── SteamInterface.cpp │ │ ├── SteamInterface.h │ │ ├── SynchronizedClock.cpp │ │ └── SynchronizedClock.h │ ├── Reverse │ │ ├── App.cpp │ │ ├── App.h │ │ ├── AutoPtr.cpp │ │ ├── AutoPtr.h │ │ ├── AutoPtrManager.cpp │ │ ├── AutoPtrManager.h │ │ ├── Debug.cpp │ │ ├── Debug.h │ │ ├── Entry.cpp │ │ ├── Entry.h │ │ ├── FunctionHook.cpp │ │ ├── FunctionHook.h │ │ ├── JitAssembly.h │ │ ├── Memory.h │ │ ├── MemoryVP.h │ │ ├── Memory_Win.inl │ │ ├── Pattern.cpp │ │ ├── Pattern.h │ │ └── ThisCall.h │ ├── System │ │ ├── Log.cpp │ │ ├── Log.h │ │ ├── Path.cpp │ │ └── Path.h │ ├── Tests │ │ └── main.cpp │ └── xmake.lua ├── launcher │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── electron │ │ ├── .gitignore │ │ ├── app.js │ │ ├── package.json │ │ ├── pnpm-lock.yaml │ │ └── preload.mjs │ ├── index.html │ ├── package.json │ ├── pnpm-lock.yaml │ ├── postcss.config.cjs │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.tsx │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ ├── ModDownloadPanel.tsx │ │ │ ├── Owadview.tsx │ │ │ ├── WindowFrame.tsx │ │ │ ├── dialogs │ │ │ │ └── AddServerDialog.tsx │ │ │ └── servers │ │ │ │ ├── HeadRow.tsx │ │ │ │ ├── ServerList.tsx │ │ │ │ └── ServerRow.tsx │ │ ├── data │ │ │ ├── ModData.ts │ │ │ └── ServerData.ts │ │ ├── index.css │ │ ├── main.tsx │ │ ├── react-app-env.d.ts │ │ └── vite-env.d.ts │ ├── tailwind.config.cjs │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── vite.config.mjs │ └── xmake.lua ├── loader │ └── xmake.lua ├── netpack │ ├── ErrorHandler.cpp │ ├── ErrorHandler.h │ ├── Indent.cpp │ ├── Indent.h │ ├── NetPackPCH.h │ ├── cpp │ │ ├── helpers.cc │ │ ├── helpers.h │ │ ├── names.h │ │ └── options.h │ ├── main.cpp │ └── xmake.lua ├── protocol │ ├── Protocol.cpp │ ├── ProtocolPCH.h │ ├── client.proto │ ├── common.proto │ ├── server.proto │ └── xmake.lua └── server │ ├── admin │ ├── .gitignore │ ├── README.md │ ├── eslint.config.js │ ├── globals.d.ts │ ├── index.html │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ │ ├── App.tsx │ │ ├── Clients │ │ │ └── WebApiClient.ts │ │ ├── Components │ │ │ ├── Drawer │ │ │ │ ├── Drawer.tsx │ │ │ │ └── DrawerItem.tsx │ │ │ ├── Toast │ │ │ │ └── ToastProvider.tsx │ │ │ └── Toolbar │ │ │ │ ├── ThemeSwitch.tsx │ │ │ │ └── Toolbar.tsx │ │ ├── Data │ │ │ ├── PluginData.ts │ │ │ └── ToastData.ts │ │ ├── Pages │ │ │ ├── About │ │ │ │ └── About.tsx │ │ │ ├── Dashboard │ │ │ │ ├── Dashboard.tsx │ │ │ │ └── WidgetGrid.tsx │ │ │ ├── Plugins │ │ │ │ └── Plugins.tsx │ │ │ └── Settings │ │ │ │ └── Settings.tsx │ │ ├── Stores │ │ │ ├── AppStore.ts │ │ │ ├── PluginStore.ts │ │ │ ├── StorageStore.ts │ │ │ └── ToastStore.ts │ │ ├── Theme.ts │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── vite.config.ts │ ├── watcher.js │ └── xmake.lua │ ├── loader │ ├── .gitignore │ ├── EnvironmentHelper.cs │ ├── Extensions │ │ └── EmbedIO.cs │ ├── FileSystemHelper.cs │ ├── Game │ │ ├── PlayerManager.cs │ │ ├── Timer.cs │ │ └── World.cs │ ├── Program.cs │ ├── Server.Loader.csproj │ ├── Server.cs │ ├── Systems │ │ ├── Plugins.cs │ │ ├── Rpc.cs │ │ ├── Statistics.cs │ │ └── WebApi.cs │ └── xmake.lua │ ├── native │ ├── Components │ │ ├── AppearanceComponent.h │ │ ├── AttachmentComponent.cpp │ │ ├── AttachmentComponent.h │ │ ├── CellComponent.h │ │ ├── CharacterComponent.h │ │ ├── InterpolationComponent.h │ │ ├── LevelTag.h │ │ ├── MovementComponent.cpp │ │ ├── MovementComponent.h │ │ ├── PlayerComponent.cpp │ │ ├── PlayerComponent.h │ │ ├── VehicleComponent.cpp │ │ └── VehicleComponent.h │ ├── Config.cpp │ ├── Config.h │ ├── Game │ │ ├── GridCell.cpp │ │ ├── GridCell.h │ │ ├── Level.cpp │ │ ├── Level.h │ │ ├── World.cpp │ │ └── World.h │ ├── GameServer.cpp │ ├── GameServer.h │ ├── PlayerManager.cpp │ ├── PlayerManager.h │ ├── Scripting │ │ ├── AttachmentComponentScriptInstance.cpp │ │ ├── AttachmentComponentScriptInstance.h │ │ ├── BufferScriptInstance.cpp │ │ ├── BufferScriptInstance.h │ │ ├── ConfigScriptInstance.cpp │ │ ├── IAttachmentComponent.h │ │ ├── IBuffer.h │ │ ├── IConfig.h │ │ ├── ILogger.h │ │ ├── IMovementComponent.h │ │ ├── IPlayer.h │ │ ├── IPlayerManager.h │ │ ├── IRpc.h │ │ ├── IWorld.h │ │ ├── LoggerScriptInstance.cpp │ │ ├── LoggerScriptInstance.h │ │ ├── MovementComponentScriptInstance.cpp │ │ ├── MovementComponentScriptInstance.h │ │ ├── PlayerManagerScriptInstance.cpp │ │ ├── PlayerManagerScriptInstance.h │ │ ├── PlayerScriptInstance.cpp │ │ ├── PlayerScriptInstance.h │ │ ├── RpcScriptInstance.cpp │ │ ├── RpcScriptInstance.h │ │ ├── ScriptingBase.h │ │ ├── ServerAPI.cpp │ │ ├── ServerAPI.h │ │ ├── WorldScriptInstance.cpp │ │ └── WorldScriptInstance.h │ ├── ServerPCH.h │ ├── Systems │ │ ├── ChatSystem.cpp │ │ ├── ChatSystem.h │ │ ├── ServerListSystem.cpp │ │ └── ServerListSystem.h │ └── xmake.lua │ ├── scripting │ ├── CyberpunkSdk │ │ ├── .gitignore │ │ ├── AssemblyInfo.cs │ │ ├── CyberpunkSdk.csproj │ │ ├── Game │ │ │ ├── Components │ │ │ │ ├── AttachmentComponent.cs │ │ │ │ └── MovementComponent.cs │ │ │ ├── Player.cs │ │ │ ├── PlayerManager.cs │ │ │ ├── Timer.cs │ │ │ └── World.cs │ │ ├── Server.cs │ │ ├── Systems │ │ │ ├── Logger.cs │ │ │ └── Rpc.cs │ │ ├── Types │ │ │ ├── CName.cs │ │ │ ├── GameTime.cs │ │ │ └── TweakDBID.cs │ │ ├── Utils │ │ │ └── CRC32.cs │ │ └── WebApi.cs │ ├── EmoteSystem │ │ ├── .gitignore │ │ ├── Admin │ │ │ ├── .gitignore │ │ │ ├── index.ts │ │ │ ├── package.json │ │ │ ├── pnpm-lock.yaml │ │ │ ├── src │ │ │ │ └── widget.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.js │ │ ├── Client │ │ │ └── Plugins.EmoteClient.cs │ │ ├── EmoteSystem.csproj │ │ ├── Plugin.cs │ │ ├── RedTypes.cs │ │ ├── Server │ │ │ └── Plugins.EmoteServer.cs │ │ ├── ServerImpl.cs │ │ └── WebApi.cs │ ├── JobSystem │ │ ├── .gitignore │ │ ├── Client │ │ │ ├── Plugins.DeliveryClient.cs │ │ │ ├── Plugins.JobsClient.cs │ │ │ ├── Plugins.TaxiDriverClient.cs │ │ │ └── Plugins.TaxiRiderClient.cs │ │ ├── DeliveryDriver.cs │ │ ├── Job.cs │ │ ├── JobManager.cs │ │ ├── JobSystem.csproj │ │ ├── JobSystem.csproj.user │ │ ├── Plugin.cs │ │ ├── Police.cs │ │ ├── Properties │ │ │ └── PublishProfiles │ │ │ │ └── FolderProfile.pubxml │ │ ├── RedTypes.cs │ │ ├── Server │ │ │ ├── Plugins.DeliveryServer.cs │ │ │ ├── Plugins.JobsServer.cs │ │ │ └── Plugins.TaxiServer.cs │ │ └── Taxi.cs │ ├── SdkGenerator │ │ ├── .gitignore │ │ ├── Program.cs │ │ └── SdkGenerator.csproj │ ├── VehicleSystem │ │ ├── .gitignore │ │ ├── Plugin.cs │ │ ├── Server │ │ │ └── Plugins.EmoteServer.cs │ │ ├── ServerImpl.cs │ │ └── VehicleSystem.csproj │ ├── scripting.sln │ └── xmake.lua │ └── xmake.lua ├── log.reds ├── tools ├── InkWidgetCustomClass.1sc ├── VftableCounter.py ├── codegen │ └── xmake.lua └── csharp │ └── xmake.lua ├── vendor ├── httplib.h └── xmake.lua ├── xmake-requires.lock └── xmake.lua /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: AlwaysBreak 5 | AlignEscapedNewlines: Left 6 | AlignOperands: true 7 | AllowShortCaseLabelsOnASingleLine: true 8 | AllowShortFunctionsOnASingleLine: InlineOnly 9 | AllowShortLambdasOnASingleLine: Inline 10 | BraceWrapping: 11 | AfterCaseLabel: true 12 | IndentBraces: true 13 | BreakBeforeBraces: Allman 14 | BreakConstructorInitializers: BeforeComma 15 | ColumnLimit: 180 16 | IndentWidth: 4 17 | PenaltyBreakFirstLessLess: 180 18 | PointerAlignment: Left 19 | SortIncludes: Never 20 | SpaceBeforeParensOptions: 21 | AfterControlStatements: false -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | .vscode/ 3 | .xmake/ 4 | build/ 5 | bin/ 6 | obj/ 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{cpp,hpp}] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_size = 4 8 | indent_style = space 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Tools / IDEs 2 | vs20*/ 3 | vsxmake*/ 4 | .vs/ 5 | .idea 6 | compile_commands.json 7 | code/scripting/CyberpunkSdk/CyberpunkSdk.csproj.user 8 | code/scripting/JobSystem/Properties/PublishProfiles/FolderProfile.pubxml.user 9 | 10 | # Dependencies 11 | .xmake/* 12 | package/* 13 | .cache/* 14 | node_modules 15 | 16 | # Generated 17 | **.netpack.gen.cpp 18 | **.netpack.gen.h 19 | 20 | # Builds 21 | build/* 22 | out/* 23 | dist 24 | distrib/* 25 | 26 | # Miscellaneous 27 | code/client/Archives/CyberpunkMP.zip 28 | Cyberpunk2077.exe* 29 | imgui.ini -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/RED4ext.SDK"] 2 | path = vendor/RED4ext.SDK 3 | url = https://github.com/tiltedphoques/RED4ext.SDK.git 4 | [submodule "vendor/ArchiveXL"] 5 | path = vendor/ArchiveXL 6 | url = https://github.com/psiberx/cp2077-archive-xl.git 7 | [submodule "vendor/TweakXL"] 8 | path = vendor/TweakXL 9 | url = https://github.com/psiberx/cp2077-tweak-xl.git 10 | [submodule "vendor/Codeware"] 11 | path = vendor/Codeware 12 | url = https://github.com/psiberx/cp2077-codeware.git 13 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Rider ignored files 5 | /modules.xml 6 | /.idea.CyberpunkMP.iml 7 | /contentModel.xml 8 | /projectSettingsUpdater.xml 9 | # Editor-based HTTP Client requests 10 | /httpRequests/ 11 | # Datasource local storage ignored files 12 | /dataSources/ 13 | /dataSources.local.xml 14 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "myIncludePath": [ 4 | "${workspaceFolder}/code", 5 | "${workspaceFolder}/vendor" 6 | ] 7 | }, 8 | "configurations": [ 9 | { 10 | "name": "Win32", 11 | "compilerPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.38.33130\\bin\\HostX64\\x64\\cl.exe", 12 | "intelliSenseMode": "windows-msvc-x64", 13 | "compileCommands": ".vscode/compile_commands.json", 14 | "includePath": [ 15 | "${myIncludePath}" 16 | ], 17 | "defines": [ 18 | "_WINDOWS" 19 | ], 20 | "cStandard": "c17", 21 | "cppStandard": "c++20", 22 | "browse": { 23 | "path": [ 24 | "${myIncludePath}", 25 | "${workspaceFolder}" 26 | ] 27 | } 28 | } 29 | ], 30 | "version": 4 31 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "XMake Debug", 5 | "type": "xmake", 6 | "request": "launch", 7 | "target": "Client" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /BuildInfo.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | // This file was autogenerated by xmake 3 | #define BUILD_BRANCH "${GIT_BRANCH}" 4 | #define BUILD_COMMIT "${GIT_COMMIT}" -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:8.0.404-bookworm-slim-amd64 AS build 2 | WORKDIR /app 3 | ENV XMAKE_ROOT y 4 | 5 | RUN echo 'deb http://deb.debian.org/debian bookworm-backports main' >> /etc/apt/sources.list 6 | RUN apt update \ 7 | && apt install -y xmake g++ \ 8 | && apt clean 9 | 10 | COPY . . 11 | 12 | RUN --mount=type=cache,target=/root/.xmake xmake -y 13 | 14 | # RELEASE STAGE 15 | FROM mcr.microsoft.com/dotnet/runtime:8.0.11-bookworm-slim-amd64 AS release 16 | WORKDIR /app 17 | 18 | COPY --from=build /app/build/linux/x86_64/release/ /app/ 19 | 20 | 21 | EXPOSE 11778 22 | CMD [ "/app/Server.Loader" ] 23 | -------------------------------------------------------------------------------- /MakeVSLatestProjects.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | xmake project -k vsxmake -------------------------------------------------------------------------------- /code/assets/Archives/.gitignore: -------------------------------------------------------------------------------- 1 | *.zip -------------------------------------------------------------------------------- /code/assets/Archives/CyberpunkMP.cpmodproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | CyberpunkMP 4 | CyberpunkMP 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /code/assets/Archives/packed/archive/pc/mod/CyberpunkMP.archive: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/packed/archive/pc/mod/CyberpunkMP.archive -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/base/gameplay/gui/prototype_hud.inkhud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/base/gameplay/gui/prototype_hud.inkhud -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/default_male.ccstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/default_male.ccstate -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/minimap_mappin.inkwidget: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/minimap_mappin.inkwidget -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/minimap_mappin_player.inkwidget: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/minimap_mappin_player.inkwidget -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/multiplayer_ui.inkanim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/multiplayer_ui.inkanim -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/multiplayer_ui.inkwidget: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/multiplayer_ui.inkwidget -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/muppet.ent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/muppet.ent -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/player_ma_fpp.ent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/player_ma_fpp.ent -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/player_ma_tpp.ent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/player_ma_tpp.ent -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/player_ma_tpp_cutscene.ent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/player_ma_tpp_cutscene.ent -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/player_wa_fpp.ent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/player_wa_fpp.ent -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/player_wa_tpp_cutscene.ent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/player_wa_tpp_cutscene.ent -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/workspot_anim.ent: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/workspot_anim.ent -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/mods/cyberpunkmp/workspot_base.workspot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/mods/cyberpunkmp/workspot_base.workspot -------------------------------------------------------------------------------- /code/assets/Archives/source/archive/multi/gameplay/gui/widgets/minimap/minimap_pingsystem_mapping.inkwidget: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/assets/Archives/source/archive/multi/gameplay/gui/widgets/minimap/minimap_pingsystem_mapping.inkwidget -------------------------------------------------------------------------------- /code/assets/Archives/xmake.lua: -------------------------------------------------------------------------------- 1 | rule("archive") 2 | set_extensions(".archive") 3 | -- on_build_file(function (target, sourcefile, opt) 4 | -- os.cp(sourcefile, path.join(target:targetdir(), path.basename(sourcefile) .. ".archive")) 5 | -- end) 6 | on_install(function (target) 7 | print("on_install") 8 | for _, sourcebatch in pairs(target:sourcebatches()) do 9 | local sourcekind = sourcebatch.rulename 10 | if sourcekind == "archive" then 11 | for _, sourcefile in ipairs(sourcebatch.sourcefiles) do 12 | os.cp(sourcefile, path.join(target:installdir("launcher"), "mod", "assets", "Archives", path.basename(sourcefile) .. ".archive")) 13 | end 14 | end 15 | end 16 | end) 17 | 18 | target("Archives") 19 | if is_mode("debug") then 20 | add_defines("TP_ARCHIVES_LOCATION=\"../../../../code/assets/Archives/packed/archive/pc/mod/\"", {public = true}) 21 | else 22 | add_defines("TP_ARCHIVES_LOCATION=\"assets/Archives\"", {public = true}) 23 | end 24 | set_kind("headeronly") 25 | set_group("Assets") 26 | add_rules("archive") 27 | add_files("packed/archive/pc/mod/CyberpunkMP.archive") -------------------------------------------------------------------------------- /code/assets/Inputs/xmake.lua: -------------------------------------------------------------------------------- 1 | rule("input") 2 | set_extensions(".xml") 3 | on_install(function (target) 4 | for _, sourcebatch in pairs(target:sourcebatches()) do 5 | local sourcekind = sourcebatch.rulename 6 | if sourcekind == "input" then 7 | for _, sourcefile in ipairs(sourcebatch.sourcefiles) do 8 | os.cp(sourcefile, path.join(target:installdir("launcher"), "mod", "assets", "Inputs", path.basename(sourcefile) .. ".xml")) 9 | end 10 | end 11 | end 12 | end) 13 | 14 | target("Inputs") 15 | if is_mode("debug") then 16 | add_defines("TP_INPUTS_LOCATION=\"../../../../code/assets/Inputs/CyberpunkMP.xml\"", {public = true}) 17 | else 18 | add_defines("TP_INPUTS_LOCATION=\"assets/Inputs/CyberpunkMP.xml\"", {public = true}) 19 | end 20 | set_kind("headeronly") 21 | set_group("Assets") 22 | add_rules("input") 23 | add_files("CyberpunkMP.xml") -------------------------------------------------------------------------------- /code/assets/Tweaks/xmake.lua: -------------------------------------------------------------------------------- 1 | rule("tweak") 2 | set_extensions(".tweak") 3 | 4 | on_install(function (target) 5 | for _, sourcebatch in pairs(target:sourcebatches()) do 6 | local sourcekind = sourcebatch.rulename 7 | if sourcekind == "tweak" then 8 | for _, sourcefile in ipairs(sourcebatch.sourcefiles) do 9 | os.cp(sourcefile, path.join(target:installdir("launcher"), "mod", "assets", "Tweaks", path.basename(sourcefile) .. ".tweak")) 10 | end 11 | end 12 | end 13 | end) 14 | 15 | target("Tweaks") 16 | if is_mode("debug") then 17 | add_defines("TP_TWEAKS_LOCATION=\"../../../../code/assets/Tweaks/\"", {public = true}) 18 | else 19 | add_defines("TP_TWEAKS_LOCATION=\"assets/Tweaks/\"", {public = true}) 20 | end 21 | set_kind("headeronly") 22 | set_group("Assets") 23 | add_rules("tweak") 24 | add_files("**.tweak") -------------------------------------------------------------------------------- /code/assets/redscript/DeathMenu.reds: -------------------------------------------------------------------------------- 1 | // @wrapMethod(DeathMenuGameController) 2 | // protected cb func OnInitialize() -> Bool { 3 | // wrappedMethod(); 4 | // this.SpawnFromExternal(this.GetRootCompoundWidget(), r"mods\\cyberpunkmp\\multiplayer_ui.inkwidget", n"chat"); 5 | // } 6 | 7 | @wrapMethod(DeathMenuGameController) 8 | protected cb func OnInitialize() -> Bool { 9 | wrappedMethod(); 10 | this.AsyncSpawnFromExternal(inkWidgetRef.Get(this.m_buttonHintsManagerRef), r"mods\\cyberpunkmp\\multiplayer_ui.inkwidget", n"chat", this, n"OnChatSpawn"); 11 | } 12 | 13 | @addMethod(DeathMenuGameController) 14 | protected cb func OnChatSpawn(widget: ref, userData: ref) -> Bool { 15 | widget.SetAnchorPoint(1.0, 1.0); 16 | // this.GetRootCompoundWidget().ReorderChild(widget, 0); 17 | } -------------------------------------------------------------------------------- /code/assets/redscript/PhoneHotkeyController.reds: -------------------------------------------------------------------------------- 1 | @addField(PhoneHotkeyController) 2 | private let m_isMultiplayerUIOpenBBId: ref; 3 | 4 | @wrapMethod(PhoneHotkeyController) 5 | protected func Initialize() -> Bool { 6 | let og = wrappedMethod(); 7 | this.m_isMultiplayerUIOpenBBId = this.GetUIBlackboard().RegisterListenerBool(GetAllBlackboardDefs().UIGameData.UIMultiplayerContextRequest, this, n"OnUIMultiplayerIsShown"); 8 | return og; 9 | } 10 | 11 | @wrapMethod(PhoneHotkeyController) 12 | protected func Uninitialize() -> Void { 13 | wrappedMethod(); 14 | this.GetUIBlackboard().UnregisterListenerBool(GetAllBlackboardDefs().UIGameData.UIMultiplayerContextRequest, this.m_isMultiplayerUIOpenBBId); 15 | } 16 | 17 | @addMethod(PhoneHotkeyController) 18 | private final func OnUIMultiplayerIsShown(value: Bool) -> Void { 19 | this.ToggleVisibility(!value, false); 20 | } -------------------------------------------------------------------------------- /code/assets/redscript/Plugins/Emotes.reds: -------------------------------------------------------------------------------- 1 | module CyberpunkMP.Plugins 2 | 3 | import CyberpunkMP.* 4 | import CyberpunkMP.World.* 5 | 6 | public native class EmoteServer extends ServerRpc { 7 | public static native func TriggerEmote(name: String) -> Void; 8 | } 9 | 10 | public class EmoteClient extends ClientRpc { 11 | public func TriggerEmote(serverId: Uint64, name: String) -> Void{ 12 | let entityId = GameInstance.GetNetworkWorldSystem().GetEntityIdByServerId(serverId); 13 | GameInstance.GetNetworkWorldSystem().GetAppearanceSystem().HandleEmote(entityId, name); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /code/assets/redscript/Plugins/Jobs.reds: -------------------------------------------------------------------------------- 1 | module CyberpunkMP.Plugins 2 | 3 | import CyberpunkMP.* 4 | import CyberpunkMP.World.* 5 | 6 | public class JobEntry { 7 | let id: Uint32; 8 | let name: String; 9 | let description: String; 10 | let reward: Uint32; 11 | } 12 | 13 | public struct JobInfo { 14 | let id: Uint32; 15 | let name: String; 16 | let description: String; 17 | let reward: Uint32; 18 | } 19 | 20 | public native class JobsServer extends ServerRpc { 21 | public static native func SelectJob(job: CName) -> Void; 22 | public static native func QuitJob() -> Void; 23 | } 24 | 25 | public class JobsClient extends ClientRpc { 26 | 27 | public func SetActiveJob(job: CName) -> Void { 28 | LogChannel(n"DEBUG", s"[JobsClient] SetActiveJob"); 29 | 30 | // Set the current active job of the player 31 | if (Equals(job, n"Delivery Driver")) { 32 | // Enable the delivery UI 33 | DeliveryServer.LoadDeliveries(); 34 | } else if (Equals(job, n"Taxi Driver")) { 35 | TaxiServer.LoadJobs(); 36 | } 37 | // Handle "None" here 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/assets/redscript/Rpc.reds: -------------------------------------------------------------------------------- 1 | module CyberpunkMP 2 | 3 | public native class ClientRpc extends IScriptable { 4 | } 5 | 6 | public native class ServerRpc extends IScriptable { 7 | } 8 | -------------------------------------------------------------------------------- /code/assets/redscript/World/ChatSystem.reds: -------------------------------------------------------------------------------- 1 | module CyberpunkMP.World 2 | 3 | import Codeware.* 4 | import CyberpunkMP.* 5 | 6 | public native class ChatSystem extends IScriptable { 7 | public native func Send(message: String); 8 | public native func GetUsername() -> String; 9 | 10 | public func HandleChatMessage(author: String, message: String) { 11 | let evt: ref; 12 | evt.author = author; 13 | evt.message = message; 14 | 15 | LogChannel(n"DEBUG", s"[ChatSystem] HandleChatMessage: " + message); 16 | let uiSystem = GameInstance.GetUISystem(GetGameInstance()); 17 | uiSystem.QueueEvent(evt); 18 | } 19 | // private final func OnConnectToServer(request: ref) -> Void { 20 | // this.m_Blackboard.SetBool(GetAllBlackboardDefs().UI_ComDevice.ContactsActive, open, true); 21 | // } 22 | } 23 | -------------------------------------------------------------------------------- /code/assets/redscript/World/InterpolationSystem.reds: -------------------------------------------------------------------------------- 1 | module CyberpunkMP.World 2 | 3 | public native class InterpolationSystem extends IScriptable { 4 | 5 | } -------------------------------------------------------------------------------- /code/assets/redscript/helpers.reds: -------------------------------------------------------------------------------- 1 | native func Log(const text: script_ref) -> Void 2 | native func LogWarning(const text: script_ref) -> Void 3 | native func LogError(const text: script_ref) -> Void 4 | 5 | // output goes to CET window 6 | native func LogChannel(channel: CName, const text: script_ref) 7 | native func LogChannelWarning(channel: CName, const text: script_ref) -> Void 8 | native func LogChannelError(channel: CName, const text: script_ref) -> Void 9 | 10 | native func FTLog(const value: script_ref) -> Void 11 | native func FTLogWarning(const value: script_ref) -> Void 12 | native func FTLogError(const value: script_ref) -> Void 13 | 14 | native func Trace() -> Void 15 | native func TraceToString() -> String -------------------------------------------------------------------------------- /code/assets/redscript/xmake.lua: -------------------------------------------------------------------------------- 1 | rule("redscript") 2 | set_extensions(".reds") 3 | -- on_build_file(function (target, sourcefile, opt) 4 | -- -- not sure how to not hard-code the relative directory 5 | -- os.cp(sourcefile, path.join(target:targetdir() .. "/redscript", path.relative(sourcefile, "code/redscript"))) 6 | -- end) 7 | on_install(function (target) 8 | for _, sourcebatch in pairs(target:sourcebatches()) do 9 | local sourcekind = sourcebatch.rulename 10 | if sourcekind == "redscript" then 11 | for _, sourcefile in ipairs(sourcebatch.sourcefiles) do 12 | os.cp(sourcefile, path.join(target:installdir("launcher"), "mod", "assets", "redscript", path.relative(sourcefile, "code/redscript/assets"))) 13 | end 14 | end 15 | end 16 | end) 17 | 18 | target("redscript") 19 | if is_mode("debug") then 20 | add_defines("TP_REDSCRIPT_LOCATION=\"../../../../code/assets/redscript\"", {public = true}) 21 | else 22 | add_defines("TP_REDSCRIPT_LOCATION=\"assets/redscript\"", {public = true}) 23 | end 24 | set_kind("headeronly") 25 | set_group("Assets") 26 | add_rules("redscript") 27 | add_files("**.reds") -------------------------------------------------------------------------------- /code/assets/xmake.lua: -------------------------------------------------------------------------------- 1 | includes("Archives", "Inputs", "Tweaks", "redscript") -------------------------------------------------------------------------------- /code/client/App/Application.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Foundation/Application.hpp" 4 | #include 5 | 6 | 7 | namespace App 8 | { 9 | struct Application : Core::Application 10 | { 11 | explicit Application(RED4ext::PluginHandle aPlugin, const RED4ext::Sdk* aSdk = nullptr); 12 | 13 | protected: 14 | 15 | void OnStarted() override; 16 | void OnStopped() override; 17 | }; 18 | 19 | extern UniquePtr GApplication; 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /code/client/App/ChatMessageEvent.cpp: -------------------------------------------------------------------------------- 1 | #include "ChatMessageEvent.h" -------------------------------------------------------------------------------- /code/client/App/ChatMessageEvent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "Red/TypeInfo/Macros/Definition.hpp" 6 | 7 | struct ChatMessageUIEvent : RED4ext::red::Event 8 | { 9 | RED4ext::CString author; 10 | RED4ext::CString message; 11 | 12 | RTTI_IMPL_TYPEINFO(ChatMessageUIEvent); 13 | RTTI_IMPL_ALLOCATOR(); 14 | }; 15 | 16 | RTTI_DEFINE_CLASS(ChatMessageUIEvent, { 17 | RTTI_PARENT(RED4ext::red::Event); 18 | // auto pType = Red::GetClass("String"); 19 | // type->props.PushBack(Red::CProperty::Create(pType, "author", nullptr, static_cast(0x40))); 20 | // type->props.PushBack(Red::CProperty::Create(pType, "message", nullptr, static_cast(0x60))); 21 | RTTI_PROPERTY(author); 22 | RTTI_PROPERTY(message); 23 | }); -------------------------------------------------------------------------------- /code/client/App/Components/AttachedComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct AttachedComponent 4 | { 5 | //flecs::entity Parent; 6 | }; -------------------------------------------------------------------------------- /code/client/App/Components/EntityComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Game/Animation/MultiMovementController.h" 3 | 4 | struct EntityComponent 5 | { 6 | Red::EntityID Id; 7 | bool IsVehicle{false}; 8 | MultiMovementController* Controller{nullptr}; 9 | }; 10 | -------------------------------------------------------------------------------- /code/client/App/Components/InterpolationComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct InterpolationComponent 4 | { 5 | struct Timepoint 6 | { 7 | glm::vec3 Position{}; 8 | glm::vec3 Rotation{}; 9 | float Velocity{0.f}; 10 | uint64_t Tick{0}; 11 | }; 12 | 13 | List TimePoints{}; 14 | Timepoint PreviousFrame{}; 15 | }; -------------------------------------------------------------------------------- /code/client/App/Components/PlayerComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct PlayerComponent 4 | { 5 | }; -------------------------------------------------------------------------------- /code/client/App/Components/SpawningComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct MultiMovementController; 4 | struct SpawningComponent 5 | { 6 | Red::EntityID Id; 7 | MultiMovementController* Controller{nullptr}; 8 | }; -------------------------------------------------------------------------------- /code/client/App/Debugging/DebugService.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "DebugService.h" 3 | #include 4 | 5 | namespace App 6 | { 7 | DebugService::DebugService() 8 | { 9 | } 10 | 11 | DebugService::~DebugService() 12 | { 13 | } 14 | 15 | void DebugService::OnBootstrap() 16 | { 17 | } 18 | 19 | void DebugService::Draw() 20 | { 21 | if (ImGui::BeginMainMenuBar()) 22 | { 23 | if (ImGui::BeginMenu("Test")) 24 | { 25 | if (ImGui::Button("Connect")) 26 | { 27 | Core::Container::Get()->Connect("127.0.0.1:11778"); 28 | 29 | /*auto handle = Red::GetGameSystem(); 30 | Red::EntityID id; 31 | Red::ScriptGameInstance game; 32 | Red::CallVirtual(handle, "CreatePuppet", id, game);*/ 33 | } 34 | ImGui::EndMenu(); 35 | } 36 | ImGui::EndMainMenuBar(); 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /code/client/App/Debugging/DebugService.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Foundation/Feature.hpp" 4 | #include "Core/Logging/LoggingAgent.hpp" 5 | 6 | namespace App 7 | { 8 | struct DebugService : Core::Feature, Core::LoggingAgent 9 | { 10 | DebugService(); 11 | ~DebugService() override; 12 | 13 | void OnBootstrap() override; 14 | 15 | void Draw(); 16 | }; 17 | } // namespace App 18 | -------------------------------------------------------------------------------- /code/client/App/Extensions/inkTextInputWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "Core/Stl.hpp" 2 | #include 3 | 4 | struct TextInputExtension : RED4ext::ink::TextInputWidget 5 | { 6 | void MoveCaret(int32_t position) { this->caretPosition = position; } 7 | }; 8 | 9 | RTTI_EXPAND_CLASS(RED4ext::ink::TextInputWidget, { RTTI_METHOD_FQN(TextInputExtension::MoveCaret); }); -------------------------------------------------------------------------------- /code/client/App/Network/Rpc/RpcCsharp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /code/client/App/Network/Rpc/RpcGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct BaseArgumentPack; 4 | 5 | namespace Game 6 | { 7 | struct ScriptFunction; 8 | struct ScriptClass; 9 | } 10 | 11 | struct RpcMock 12 | { 13 | }; 14 | 15 | struct RpcContext 16 | { 17 | struct Arg 18 | { 19 | UniquePtr pack; 20 | }; 21 | 22 | Vector args; 23 | Red::CName klass; 24 | Red::CName function; 25 | }; 26 | 27 | struct RpcHandler 28 | { 29 | RpcContext context; 30 | Red::CClassFunction* function; 31 | }; 32 | 33 | struct RpcGenerator 34 | { 35 | using Descriptor = Red::ClassDescriptorDefaultImpl; 36 | 37 | static void GenerateHandlers(); 38 | static void DumpCsharp(); 39 | static void CreateFunction(Descriptor* desc, const Game::ScriptClass* klass, Game::ScriptFunction* func); 40 | static const Vector& GetFunctions() { return s_functions; } 41 | static RpcHandler* GetRpcHandler(uint64_t klass, uint64_t func); 42 | 43 | private: 44 | 45 | static inline Vector s_functions; 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /code/client/App/Network/Rpc/RpcPack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct BaseArgumentPack 4 | { 5 | BaseArgumentPack(Red::CBaseRTTIType* type) 6 | : m_pRtti(type) 7 | { 8 | } 9 | 10 | virtual ~BaseArgumentPack() {} 11 | 12 | virtual void Read(void* pDest, Buffer::Reader& aReader) = 0; 13 | virtual void Write(void* pSrc, Buffer::Writer& aWriter) = 0; 14 | 15 | Red::CBaseRTTIType* m_pRtti; 16 | }; 17 | 18 | UniquePtr MakePack(Red::CBaseRTTIType* type); -------------------------------------------------------------------------------- /code/client/App/Network/Rpc/RpcService.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Core/Foundation/Feature.hpp" 3 | #include "Core/Hooking/HookingAgent.hpp" 4 | 5 | struct RpcId 6 | { 7 | uint64_t Klass; 8 | uint64_t Function; 9 | 10 | bool operator==(const RpcId& acRhs) const { return Klass == acRhs.Klass && Function == acRhs.Function; } 11 | }; 12 | 13 | struct RpcHandler; 14 | struct CachedRpcHandler 15 | { 16 | RpcId Id; 17 | RpcHandler* Handler; 18 | }; 19 | 20 | template <> struct std::hash 21 | { 22 | std::size_t operator()(const RpcId& s) const noexcept { return s.Klass ^ (s.Function << 1); } 23 | }; 24 | 25 | struct RpcService : Core::Feature, Core::HookingAgent 26 | { 27 | RpcService(RED4ext::PluginHandle aPlugin, const RED4ext::Sdk* aSdk); 28 | ~RpcService() override; 29 | 30 | void OnInitialize() override; 31 | void OnShutdown() override; 32 | 33 | std::optional GetRpcId(uint64_t aKlass, uint64_t aFunction) const; 34 | 35 | protected: 36 | 37 | static bool PrepareRpc(RED4ext::CGameApplication* aApp); 38 | 39 | void HandleRpc(const PacketEvent& aMessage); 40 | void HandleRpcDefinitions(const PacketEvent& aMessage); 41 | bool Call(const server::RpcCall& aMessage) const; 42 | 43 | private: 44 | 45 | Map m_serverRpcs; 46 | Vector m_clientRpcs; 47 | }; 48 | -------------------------------------------------------------------------------- /code/client/App/Network/Rpc/RpcValidator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Core/Hooking/HookingAgent.hpp" 3 | 4 | struct RpcValidator : Core::HookingAgent 5 | { 6 | static void InternalValidate(); 7 | 8 | static void Attach(); 9 | }; 10 | -------------------------------------------------------------------------------- /code/client/App/Rendering/imgui_user_config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Core/Facades/Log.hpp" 4 | 5 | // NOTE: imgui_user_config.h is included by imgui.h which is included with precompiled header, so no need to include it 6 | // here once more 7 | 8 | // global definition "Enable ImGui Assertions Logging" 9 | bool g_ImGuiAssertionsEnabled{false}; 10 | 11 | #ifdef NDEBUG 12 | // inline _wassert decl for NDEBUG as it is not emitted inside assert.h header in this case 13 | extern "C" _ACRTIMP void __cdecl _wassert(char const* _Message, char const* _File, unsigned _Line); 14 | #endif 15 | 16 | // runtime assertions which can be enabled/disabled inside CET options, always logged into main log file when they 17 | // happen 18 | void ImGuiAssert(char const* acpMessage, char const* acpFile, unsigned aLine) 19 | { 20 | // TODO - make this log to log of the one who caused assertion instead of default log! 21 | Core::Log::Error("ImGui assertion failed in file \"{}\" at line {}! Expression ({}) evaluates to false!", acpFile, aLine, acpMessage); 22 | } 23 | -------------------------------------------------------------------------------- /code/client/App/Rendering/imgui_user_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // global declaration "Enable ImGui Assertions" 4 | extern bool g_ImGuiAssertionsEnabled; 5 | 6 | // runtime assertions which can be enabled/disabled inside CET options 7 | void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine); 8 | 9 | // custom assertion function macro for ImGui 10 | #define IM_ASSERT(expression) (void)((g_ImGuiAssertionsEnabled && ((!!(expression)) || (ImGuiAssert(#expression, __FILE__, (unsigned)(__LINE__)), 0)))) -------------------------------------------------------------------------------- /code/client/App/Settings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fs = std::filesystem; 4 | 5 | struct Settings 6 | { 7 | static Settings& Get() 8 | { 9 | static Settings instance; 10 | return instance; 11 | } 12 | static bool IsDisabled() 13 | { 14 | return !Get().enabled; 15 | } 16 | static void Load(); 17 | 18 | fs::path exePath{}; 19 | fs::path gamePath{}; 20 | String Version{}; 21 | String ip = "127.0.0.1"; 22 | uint16_t port = 11778; 23 | Vector mods = {}; 24 | bool enabled = false; 25 | bool RpcOnly = false; 26 | fs::path RpcPath{}; 27 | 28 | private: 29 | Settings() = default; 30 | }; -------------------------------------------------------------------------------- /code/client/App/Threading/ThreadService.cpp: -------------------------------------------------------------------------------- 1 | #include "ThreadService.h" 2 | 3 | void ThreadService::RunInMainThread(std::function aFunc) 4 | { 5 | auto pService = Core::Container::Get(); 6 | pService->m_queue.Add(aFunc); 7 | } 8 | 9 | void ThreadService::OnGameUpdate(RED4ext::CGameApplication* apApp) 10 | { 11 | m_queue.Drain(); 12 | } 13 | -------------------------------------------------------------------------------- /code/client/App/Threading/ThreadService.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Foundation/Feature.hpp" 4 | #include 5 | 6 | struct ThreadService final 7 | : Core::Feature 8 | { 9 | static void RunInMainThread(std::function aFunc); 10 | 11 | protected: 12 | 13 | void OnGameUpdate(RED4ext::CGameApplication* apApp) override; 14 | 15 | private: 16 | 17 | TaskQueue m_queue; 18 | }; 19 | -------------------------------------------------------------------------------- /code/client/App/World/AppearanceSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Stl.hpp" 4 | #include "Core/Hooking/HookingAgent.hpp" 5 | #include "RED4ext/Scripting/Natives/Generated/Vector4.hpp" 6 | #include "RED4ext/Scripting/Natives/Generated/Quaternion.hpp" 7 | #include "Network/Client.h" 8 | 9 | 10 | struct AppearanceSystem : RED4ext::IScriptable 11 | { 12 | RTTI_IMPL_TYPEINFO(AppearanceSystem); 13 | RTTI_IMPL_ALLOCATOR(); 14 | 15 | AppearanceSystem(); 16 | 17 | void OnInitialize(const RED4ext::JobHandle& aJob); 18 | 19 | Red::DynArray GetEntityItems(Red::EntityID &); 20 | void AddEntity(const Red::EntityID entityID, const Red::DynArray& items, const Vector ccstate); 21 | Vector GetPlayerItems(Red::Handle player); 22 | bool ApplyAppearance(Red::Handle object); 23 | 24 | void OnWorldAttached(RED4ext::world::RuntimeScene* aScene); 25 | void OnBeforeWorldDetach(RED4ext::world::RuntimeScene* aScene); 26 | 27 | private: 28 | Core::Map> m_playerEquipment; 29 | Core::Map> m_playerCcstate; 30 | }; 31 | 32 | RTTI_DEFINE_CLASS(AppearanceSystem, { 33 | RTTI_ALIAS("CyberpunkMP.World.AppearanceSystem"); 34 | RTTI_METHOD(GetEntityItems); 35 | RTTI_METHOD(ApplyAppearance); 36 | }); -------------------------------------------------------------------------------- /code/client/App/World/ChatSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Stl.hpp" 4 | 5 | struct ChatSystem : RED4ext::IScriptable 6 | { 7 | RTTI_IMPL_TYPEINFO(ChatSystem); 8 | RTTI_IMPL_ALLOCATOR(); 9 | 10 | void Update(uint64_t aTick); 11 | 12 | void OnInitialize(const RED4ext::JobHandle& aJob); 13 | void OnWorldAttached(RED4ext::world::RuntimeScene* aScene); 14 | void OnAfterWorldDetach(); 15 | 16 | void Send(const Red::CString& aMessage); 17 | RED4ext::CString GetUsername(); 18 | 19 | protected: 20 | 21 | 22 | void HandleChatMessage(const PacketEvent& aMessage); 23 | 24 | private: 25 | bool m_ready{false}; 26 | Vector m_messages; 27 | }; 28 | 29 | RTTI_DEFINE_CLASS(ChatSystem, { 30 | RTTI_ALIAS("CyberpunkMP.World.ChatSystem"); 31 | RTTI_METHOD(Send); 32 | RTTI_METHOD(GetUsername); 33 | }); -------------------------------------------------------------------------------- /code/client/App/World/InterpolationSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Hooking/HookingAgent.hpp" 4 | #include "RED4ext/Scripting/Natives/gameIEntityStubSystem.hpp" 5 | 6 | 7 | struct InterpolationSystem : RED4ext::IScriptable, Core::HookingAgent 8 | { 9 | RTTI_IMPL_TYPEINFO(InterpolationSystem) 10 | RTTI_IMPL_ALLOCATOR(); 11 | 12 | void OnInitialize(const RED4ext::JobHandle& aJob); 13 | void OnWorldAttached(RED4ext::world::RuntimeScene* aScene); 14 | void OnAfterWorldDetach(); 15 | 16 | void OnConnected(); 17 | void OnDisconnected(); 18 | 19 | protected: 20 | 21 | void HandleNotifyEntityMove(const PacketEvent& aMessage); 22 | 23 | private: 24 | bool m_ready{false}; 25 | flecs::system m_interpolator; 26 | flecs::observer m_entityObserver; 27 | }; 28 | 29 | RTTI_DEFINE_CLASS(InterpolationSystem, { 30 | RTTI_ALIAS("CyberpunkMP.World.InterpolationSystem"); 31 | }); -------------------------------------------------------------------------------- /code/client/App/World/RpcDefinition.cpp: -------------------------------------------------------------------------------- 1 | #include "RpcDefinition.h" 2 | -------------------------------------------------------------------------------- /code/client/App/World/RpcDefinition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct ClientRpc : RED4ext::IScriptable 4 | { 5 | RTTI_IMPL_TYPEINFO(ClientRpc); 6 | RTTI_IMPL_ALLOCATOR(); 7 | }; 8 | 9 | struct ServerRpc : RED4ext::IScriptable 10 | { 11 | RTTI_IMPL_TYPEINFO(ServerRpc); 12 | RTTI_IMPL_ALLOCATOR(); 13 | }; 14 | 15 | RTTI_DEFINE_CLASS(ClientRpc, { RTTI_ALIAS("CyberpunkMP.ClientRpc"); }); 16 | RTTI_DEFINE_CLASS(ServerRpc, { RTTI_ALIAS("CyberpunkMP.ServerRpc"); }); -------------------------------------------------------------------------------- /code/client/Core/Container/Container.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Stl.hpp" 4 | 5 | namespace Core 6 | { 7 | class Container 8 | { 9 | public: 10 | template 11 | inline static void Set(const Core::SharedPtr& aInstance) 12 | { 13 | Resolver::Assign(aInstance); 14 | } 15 | 16 | template 17 | inline static Core::SharedPtr Get() 18 | { 19 | return Resolver::Retrieve().lock(); 20 | } 21 | 22 | template 23 | inline static bool Has() 24 | { 25 | return !Resolver::Retrieve().expired(); 26 | } 27 | 28 | template 29 | inline static void Reset() 30 | { 31 | Resolver::Reset(); 32 | } 33 | 34 | private: 35 | template 36 | struct Resolver 37 | { 38 | inline static void Assign(const Core::SharedPtr& aInstance) 39 | { 40 | s_instance = aInstance; 41 | } 42 | 43 | inline static Core::WeakPtr& Retrieve() 44 | { 45 | return s_instance; 46 | } 47 | 48 | inline static void Reset() 49 | { 50 | s_instance = {}; 51 | } 52 | 53 | inline static Core::WeakPtr s_instance; 54 | }; 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /code/client/Core/Facades/Container.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Container/Container.hpp" 4 | 5 | namespace Core 6 | { 7 | template 8 | inline Core::SharedPtr Resolve() 9 | { 10 | return Container::Get(); 11 | } 12 | 13 | template 14 | inline bool Resolvable() 15 | { 16 | return Container::Get(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /code/client/Core/Facades/Runtime.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Runtime/HostImage.hpp" 4 | #include "Core/Runtime/ModuleImage.hpp" 5 | 6 | namespace Core::Runtime 7 | { 8 | void Initialize(const Core::HostImage& aHost, const Core::ModuleImage& aModule); 9 | 10 | [[nodiscard]] uintptr_t GetImageBase(); 11 | [[nodiscard]] std::filesystem::path GetImagePath(); 12 | [[nodiscard]] std::filesystem::path GetRootDir(); 13 | [[nodiscard]] std::filesystem::path GetModulePath(); 14 | [[nodiscard]] std::filesystem::path GetModuleDir(); 15 | [[nodiscard]] std::string GetModuleName(); 16 | [[nodiscard]] bool IsASI(); 17 | [[nodiscard]] bool IsASI(HMODULE aHandle); 18 | [[nodiscard]] bool IsEXE(std::wstring_view aName); 19 | } 20 | -------------------------------------------------------------------------------- /code/client/Core/Foundation/LocaleProvider.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Foundation/Feature.hpp" 4 | 5 | namespace Core 6 | { 7 | class LocaleProvider : public Feature 8 | { 9 | public: 10 | LocaleProvider(const char* aLocale = "en_US.UTF-8") 11 | { 12 | std::setlocale(LC_ALL, aLocale); 13 | } 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /code/client/Core/Foundation/RuntimeProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "RuntimeProvider.hpp" 2 | #include "Core/Facades/Runtime.hpp" 3 | 4 | Core::RuntimeProvider::RuntimeProvider(HMODULE aHandle) noexcept 5 | : m_handle(aHandle) 6 | , m_basePathDepth(0) 7 | { 8 | } 9 | 10 | void Core::RuntimeProvider::OnInitialize() 11 | { 12 | Runtime::Initialize(HostImage(m_basePathDepth), ModuleImage(m_handle)); 13 | } 14 | -------------------------------------------------------------------------------- /code/client/Core/Foundation/RuntimeProvider.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Foundation/Feature.hpp" 4 | #include "Core/Win.hpp" 5 | 6 | namespace Core 7 | { 8 | class RuntimeProvider : public Feature 9 | { 10 | public: 11 | explicit RuntimeProvider(HMODULE aHandle) noexcept; 12 | 13 | auto SetBaseImagePathDepth(int aDepth) noexcept 14 | { 15 | m_basePathDepth = aDepth; 16 | return Defer(this); 17 | } 18 | 19 | protected: 20 | void OnInitialize() override; 21 | 22 | HMODULE m_handle; 23 | int m_basePathDepth; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /code/client/Core/Hooking/HookingAgent.cpp: -------------------------------------------------------------------------------- 1 | #include "HookingAgent.hpp" 2 | 3 | #include 4 | 5 | namespace 6 | { 7 | Core::HookingDriver* s_driver; 8 | } 9 | 10 | void Core::HookingAgent::SetHookingDriver(Core::HookingDriver& aDriver) 11 | { 12 | s_driver = &aDriver; 13 | } 14 | 15 | Core::HookingDriver& Core::HookingAgent::GetHookingDriver() 16 | { 17 | assert(s_driver); 18 | return *s_driver; 19 | } 20 | -------------------------------------------------------------------------------- /code/client/Core/Hooking/HookingDriver.cpp: -------------------------------------------------------------------------------- 1 | #include "HookingDriver.hpp" 2 | #include "HookingAgent.hpp" 3 | 4 | #include 5 | 6 | namespace 7 | { 8 | Core::HookingDriver* s_default; 9 | } 10 | 11 | void Core::HookingDriver::SetDefault(Core::HookingDriver& aDriver) 12 | { 13 | s_default = &aDriver; 14 | 15 | HookingAgent::SetHookingDriver(aDriver); 16 | } 17 | 18 | Core::HookingDriver& Core::HookingDriver::GetDefault() 19 | { 20 | assert(s_default); 21 | return *s_default; 22 | } 23 | -------------------------------------------------------------------------------- /code/client/Core/Hooking/HookingDriver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Core 4 | { 5 | class HookingDriver 6 | { 7 | public: 8 | virtual bool HookAttach(uintptr_t aAddress, void* aCallback) = 0; 9 | virtual bool HookAttach(uintptr_t aAddress, void* aCallback, void** aOriginal) = 0; 10 | virtual bool HookDetach(uintptr_t aAddress) = 0; 11 | virtual void Enqueue(std::function aFunc) = 0; 12 | 13 | static void SetDefault(HookingDriver& aDriver); 14 | static HookingDriver& GetDefault(); 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /code/client/Core/Logging/LoggingAgent.cpp: -------------------------------------------------------------------------------- 1 | #include "LoggingAgent.hpp" 2 | 3 | #include 4 | 5 | namespace 6 | { 7 | Core::LoggingDriver* s_driver; 8 | } 9 | 10 | void Core::LoggingAgent::SetDriver(Core::LoggingDriver& aDriver) 11 | { 12 | s_driver = &aDriver; 13 | } 14 | 15 | Core::LoggingDriver& Core::LoggingAgent::GetLoggingDriver() 16 | { 17 | assert(s_driver); 18 | return *s_driver; 19 | } 20 | 21 | void Core::LoggingAgent::LogFlush() 22 | { 23 | s_driver->LogFlush(); 24 | } 25 | -------------------------------------------------------------------------------- /code/client/Core/Logging/LoggingDriver.cpp: -------------------------------------------------------------------------------- 1 | #include "LoggingDriver.hpp" 2 | #include "LoggingAgent.hpp" 3 | 4 | #include 5 | 6 | namespace 7 | { 8 | Core::LoggingDriver* s_default; 9 | } 10 | 11 | void Core::LoggingDriver::SetDefault(LoggingDriver& aDriver) 12 | { 13 | s_default = &aDriver; 14 | 15 | LoggingAgent::SetDriver(aDriver); 16 | } 17 | 18 | Core::LoggingDriver& Core::LoggingDriver::GetDefault() 19 | { 20 | assert(s_default); 21 | return *s_default; 22 | } 23 | -------------------------------------------------------------------------------- /code/client/Core/Rendering/RenderingAgent.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderingAgent.hpp" 2 | 3 | #include 4 | 5 | namespace 6 | { 7 | Core::RenderingDriver* s_driver; 8 | } 9 | 10 | Microsoft::WRL::ComPtr Core::RenderingAgent::GetSwapChain() 11 | { 12 | return GetRenderingDriver().GetSwapChain(); 13 | } 14 | 15 | Microsoft::WRL::ComPtr Core::RenderingAgent::GetCommandQueue() 16 | { 17 | return GetRenderingDriver().GetCommandQueue(); 18 | } 19 | 20 | HWND Core::RenderingAgent::GetWindow() 21 | { 22 | return GetRenderingDriver().GetWindow(); 23 | } 24 | 25 | void Core::RenderingAgent::SetDriver(RenderingDriver& aDriver) 26 | { 27 | s_driver = &aDriver; 28 | } 29 | 30 | Core::RenderingDriver& Core::RenderingAgent::GetRenderingDriver() 31 | { 32 | assert(s_driver); 33 | return *s_driver; 34 | } 35 | 36 | Core::RenderingAgent::RenderingAgent() 37 | { 38 | GetRenderingDriver().Register(this); 39 | } 40 | 41 | Core::RenderingAgent::~RenderingAgent() 42 | { 43 | GetRenderingDriver().UnRegister(this); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /code/client/Core/Rendering/RenderingAgent.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RenderingDriver.hpp" 4 | 5 | namespace Core 6 | { 7 | class RenderingAgent 8 | { 9 | protected: 10 | static RenderingDriver& GetRenderingDriver(); 11 | 12 | RenderingAgent(); 13 | virtual ~RenderingAgent(); 14 | 15 | TP_NOCOPYMOVE(RenderingAgent); 16 | 17 | virtual void OnRenderInit() = 0; 18 | virtual void OnPresent() = 0; 19 | virtual void OnReset(bool aCompleteReset) = 0; 20 | virtual bool OnWindowProc(HWND ahWnd, UINT auMsg, WPARAM awParam, LPARAM alParam) { return false; } 21 | 22 | static Microsoft::WRL::ComPtr GetSwapChain(); 23 | static Microsoft::WRL::ComPtr GetCommandQueue(); 24 | static HWND GetWindow(); 25 | 26 | friend RenderingDriver; 27 | 28 | private: 29 | friend RenderingDriver; 30 | 31 | static void SetDriver(RenderingDriver& aDriver); 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /code/client/Core/Rendering/RenderingDriver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Core 4 | { 5 | class RenderingAgent; 6 | 7 | class RenderingDriver 8 | { 9 | public: 10 | 11 | static void SetDefault(RenderingDriver& aDriver); 12 | static RenderingDriver& GetDefault(); 13 | 14 | Microsoft::WRL::ComPtr GetSwapChain() const; 15 | Microsoft::WRL::ComPtr GetCommandQueue() const; 16 | Microsoft::WRL::ComPtr GetCommandList() const; 17 | HWND GetWindow() const; 18 | 19 | void Register(RenderingAgent* aAgent); 20 | void UnRegister(RenderingAgent* aAgent); 21 | 22 | protected: 23 | 24 | void TriggerPresent() const; 25 | void TriggerReset(bool aCompleteReset = false) const; 26 | void TriggerRenderInit() const; 27 | bool TriggerWindowProc(HWND, UINT, WPARAM, LPARAM); 28 | 29 | Microsoft::WRL::ComPtr m_pdxgiSwapChain{}; 30 | Microsoft::WRL::ComPtr m_pCommandQueue{}; 31 | Microsoft::WRL::ComPtr m_pCommandList{}; 32 | HWND m_window{nullptr}; 33 | 34 | private: 35 | 36 | Vector m_agents; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /code/client/Core/Runtime/HostImage.cpp: -------------------------------------------------------------------------------- 1 | #include "HostImage.hpp" 2 | #include "Core/Win.hpp" 3 | 4 | Core::HostImage::HostImage(int aExePathDepth) 5 | { 6 | const auto handle = GetModuleHandleW(nullptr); 7 | 8 | m_base = reinterpret_cast(handle); 9 | 10 | std::wstring filePath(MAX_PATH, '\0'); 11 | filePath.resize(::GetModuleFileNameW(handle, filePath.data(), MAX_PATH)); 12 | 13 | m_exe = filePath; 14 | m_root = m_exe.parent_path(); 15 | 16 | while (--aExePathDepth >= 0) 17 | m_root = m_root.parent_path(); 18 | } 19 | 20 | uintptr_t Core::HostImage::GetBase() const 21 | { 22 | return m_base; 23 | } 24 | 25 | std::filesystem::path Core::HostImage::GetPath() const 26 | { 27 | return m_exe; 28 | } 29 | 30 | std::string Core::HostImage::GetName() const 31 | { 32 | return m_exe.stem().string(); 33 | } 34 | 35 | std::filesystem::path Core::HostImage::GetRootDir() const 36 | { 37 | return m_root; 38 | } 39 | -------------------------------------------------------------------------------- /code/client/Core/Runtime/HostImage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Core 4 | { 5 | class HostImage 6 | { 7 | public: 8 | explicit HostImage(int32_t aExePathDepth = 0); 9 | ~HostImage() = default; 10 | 11 | [[nodiscard]] uintptr_t GetBase() const; 12 | [[nodiscard]] std::filesystem::path GetPath() const; 13 | [[nodiscard]] std::string GetName() const; 14 | [[nodiscard]] std::filesystem::path GetRootDir() const; 15 | 16 | private: 17 | uintptr_t m_base; 18 | std::filesystem::path m_exe; 19 | std::filesystem::path m_root; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /code/client/Core/Runtime/ModuleImage.cpp: -------------------------------------------------------------------------------- 1 | #include "ModuleImage.hpp" 2 | 3 | Core::ModuleImage::ModuleImage(HMODULE aHandle) 4 | { 5 | std::wstring filePath(MAX_PATH, '\0'); 6 | filePath.resize(::GetModuleFileNameW(aHandle, filePath.data(), MAX_PATH)); 7 | 8 | m_path = filePath; 9 | } 10 | 11 | std::filesystem::path Core::ModuleImage::GetPath() const 12 | { 13 | return m_path; 14 | } 15 | 16 | std::filesystem::path Core::ModuleImage::GetDir() const 17 | { 18 | return m_path.parent_path(); 19 | } 20 | 21 | std::string Core::ModuleImage::GetName() const 22 | { 23 | return m_path.stem().string(); 24 | } 25 | 26 | bool Core::ModuleImage::IsASI() const 27 | { 28 | return m_path.extension() == L".asi"; 29 | } 30 | -------------------------------------------------------------------------------- /code/client/Core/Runtime/ModuleImage.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Win.hpp" 4 | 5 | namespace Core 6 | { 7 | class ModuleImage 8 | { 9 | public: 10 | explicit ModuleImage(HMODULE aHandle); 11 | ~ModuleImage() = default; 12 | 13 | [[nodiscard]] std::filesystem::path GetPath() const; 14 | [[nodiscard]] std::filesystem::path GetDir() const; 15 | [[nodiscard]] std::string GetName() const; 16 | [[nodiscard]] bool IsASI() const; 17 | 18 | private: 19 | std::filesystem::path m_path; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /code/client/Core/Runtime/OwnerMutex.cpp: -------------------------------------------------------------------------------- 1 | #include "OwnerMutex.hpp" 2 | 3 | Core::OwnerMutex::OwnerMutex(std::string_view aName) 4 | : m_aname(aName) 5 | , m_mutex(nullptr) 6 | { 7 | } 8 | 9 | Core::OwnerMutex::OwnerMutex(std::wstring_view aName) 10 | : m_wname(aName) 11 | , m_mutex(nullptr) 12 | { 13 | } 14 | 15 | Core::OwnerMutex::~OwnerMutex() 16 | { 17 | Release(); 18 | } 19 | 20 | bool Core::OwnerMutex::Obtain() 21 | { 22 | const auto mutex = !m_wname.empty() 23 | ? CreateMutexW(NULL, TRUE, m_wname.data()) 24 | : CreateMutexA(NULL, TRUE, m_aname.data()); 25 | 26 | if (!mutex) 27 | return false; 28 | 29 | if (GetLastError() == ERROR_ALREADY_EXISTS) 30 | { 31 | ReleaseMutex(mutex); 32 | return false; 33 | } 34 | 35 | m_mutex = mutex; 36 | 37 | return true; 38 | } 39 | 40 | bool Core::OwnerMutex::Release() 41 | { 42 | if (!m_mutex) 43 | return false; 44 | 45 | ReleaseMutex(m_mutex); 46 | m_mutex = nullptr; 47 | 48 | return true; 49 | } 50 | 51 | bool Core::OwnerMutex::IsOwner() 52 | { 53 | return m_mutex; 54 | } 55 | -------------------------------------------------------------------------------- /code/client/Core/Runtime/OwnerMutex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Win.hpp" 4 | 5 | namespace Core 6 | { 7 | class OwnerMutex 8 | { 9 | public: 10 | explicit OwnerMutex(std::string_view aName); 11 | explicit OwnerMutex(std::wstring_view aName); 12 | ~OwnerMutex(); 13 | 14 | bool Obtain(); 15 | bool Release(); 16 | bool IsOwner(); 17 | 18 | private: 19 | std::string_view m_aname; 20 | std::wstring_view m_wname; 21 | HANDLE m_mutex; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /code/client/Core/Win.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef WIN32_LEAN_AND_MEAN 4 | #define WIN32_LEAN_AND_MEAN 5 | #endif 6 | #ifndef NOMINMAX 7 | #define NOMINMAX 8 | #endif 9 | 10 | #include 11 | #include 12 | -------------------------------------------------------------------------------- /code/client/Game/Animation/AnimationData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Base.h" 4 | 5 | struct AnimationData 6 | { 7 | Red::CName controller; 8 | bool debug = false; 9 | Locomotion_Style style{LS_Idle}; 10 | MotionTableAction action{MTA_None}; 11 | float path = 0.f; 12 | float slope = 0.f; 13 | float delta = 0.f; 14 | bool stairs = false; 15 | float ground = 0.f; 16 | float time = 0.f; 17 | float footScale = 1.f; 18 | float startAngle = 0.f; 19 | bool unk = false; 20 | float speed = 0.f; 21 | }; 22 | -------------------------------------------------------------------------------- /code/client/Game/Animation/AnimationDriver.cpp: -------------------------------------------------------------------------------- 1 | #include "AnimationDriver.h" 2 | 3 | 4 | AnimationDriver::~AnimationDriver() 5 | { 6 | Detach(); 7 | } 8 | 9 | void AnimationDriver::Attach(Red::Entity* parent) 10 | { 11 | static Core::RawFunc<2624656810UL, decltype(&AnimationDriver::Attach)> attach; 12 | attach(this, parent); 13 | } 14 | 15 | void AnimationDriver::Detach() 16 | { 17 | static Core::RawFunc<2385973466UL, decltype(&AnimationDriver::Detach)> detach; 18 | detach(this); 19 | } 20 | 21 | void AnimationDriver::SendParameters(AnimationData& data) 22 | { 23 | static Core::RawFunc<2132808949UL, decltype(&AnimationDriver::SendParameters)> send; 24 | send(this, data); 25 | } 26 | 27 | float AnimationDriver::GetAnimLength(Red::CName name) const 28 | { 29 | static Core::RawFunc<3750304414UL, float (*)(Red::AnimationControllerComponent*, Red::CName)> get; 30 | if (const auto pComp = component.Lock()) 31 | return get(pComp.GetPtr(), name); 32 | return 0.f; 33 | } 34 | -------------------------------------------------------------------------------- /code/client/Game/Animation/AnimationDriver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RED4ext/Scripting/Natives/Generated/anim/AnimFeature_CrowdLocomotion.hpp" 4 | #include "RED4ext/Scripting/Natives/Generated/anim/AnimFeature_Locomotion.hpp" 5 | #include "RED4ext/Scripting/Natives/Generated/ent/AnimationControllerComponent.hpp" 6 | 7 | struct AnimationData; 8 | 9 | struct AnimationDriver 10 | { 11 | ~AnimationDriver(); 12 | 13 | void Attach(Red::Entity* parent); 14 | void Detach(); 15 | 16 | void SendParameters(AnimationData& data); 17 | 18 | float GetAnimLength(Red::CName name) const; 19 | 20 | Red::Handle locomotion; 21 | Red::Handle crowd; 22 | Red::WeakHandle component; 23 | }; 24 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Base.cpp: -------------------------------------------------------------------------------- 1 | #include "Base.h" 2 | 3 | #include "Game/Animation/AnimationData.h" 4 | 5 | namespace States 6 | { 7 | void Base::GetAnimationData(AnimationData& aData) const 8 | { 9 | aData.action = MTA_None; 10 | aData.style = LS_Idle; 11 | } 12 | 13 | std::optional Base::Process(const Update& acEvent) noexcept 14 | { 15 | return std::nullopt; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Idling.cpp: -------------------------------------------------------------------------------- 1 | #include "Idling.h" 2 | 3 | #include "Sprinting.h" 4 | #include "Walking.h" 5 | 6 | namespace States 7 | { 8 | void Idling::Enter() noexcept 9 | { 10 | } 11 | 12 | std::optional Idling::Process(const Update& acEvent) noexcept 13 | { 14 | if (acEvent.Speed >= kRunSpeed) 15 | return Transit(); 16 | if (acEvent.Speed >= kWalkSpeed) 17 | return Transit(); 18 | 19 | return std::nullopt; 20 | } 21 | } // namespace States 22 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Idling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Base.h" 4 | 5 | namespace States 6 | { 7 | struct Idling : Base 8 | { 9 | Idling(MultiMovementController& aParent) 10 | : Base(aParent) 11 | { 12 | } 13 | 14 | ~Idling() override{} 15 | void Enter() noexcept override; 16 | 17 | std::optional Process(const Update& acEvent) noexcept override; 18 | }; 19 | } // namespace States 20 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Spawning.cpp: -------------------------------------------------------------------------------- 1 | #include "Spawning.h" 2 | #include "Idling.h" 3 | #include "Sprinting.h" 4 | #include "Walking.h" 5 | 6 | namespace States 7 | { 8 | void Spawning::Enter() noexcept 9 | { 10 | } 11 | 12 | std::optional Spawning::Process(const Update& acEvent) noexcept 13 | { 14 | if (acEvent.Speed >= kRunSpeed) 15 | return Transit(); 16 | if (acEvent.Speed >= kWalkSpeed) 17 | return Transit(); 18 | 19 | return Transit(); 20 | } 21 | } // namespace States 22 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Spawning.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Base.h" 4 | 5 | namespace States 6 | { 7 | struct Spawning : Base 8 | { 9 | Spawning(MultiMovementController& aParent) 10 | : Base(aParent) 11 | { 12 | } 13 | 14 | ~Spawning() override{} 15 | void Enter() noexcept override; 16 | 17 | std::optional Process(const Update& acEvent) noexcept override; 18 | }; 19 | } // namespace States 20 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Sprinting.cpp: -------------------------------------------------------------------------------- 1 | #include "Sprinting.h" 2 | 3 | #include "Idling.h" 4 | #include "Walking.h" 5 | 6 | #include "Game/Animation/AnimationData.h" 7 | #include "Game/Animation/MultiMovementController.h" 8 | 9 | namespace States 10 | { 11 | void Sprinting::Enter() noexcept 12 | { 13 | m_timer = 0.f; 14 | m_duration = m_parent.GetAnimLength("sprint_0"); 15 | } 16 | 17 | void Sprinting::GetAnimationData(AnimationData& aData) const 18 | { 19 | aData.action = MTA_Move; 20 | aData.style = LS_Sprint; 21 | aData.time = m_timer; 22 | } 23 | 24 | std::optional Sprinting::Process(const Update& acEvent) noexcept 25 | { 26 | if (acEvent.Speed < kRunSpeed) 27 | { 28 | if (acEvent.Speed >= kWalkSpeed) 29 | return Transit(); 30 | return Transit(); 31 | } 32 | 33 | m_timer += acEvent.Delta; 34 | m_timer = std::fmodf(m_timer, m_duration); 35 | 36 | return std::nullopt; 37 | } 38 | } // namespace States 39 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Sprinting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Base.h" 4 | 5 | namespace States 6 | { 7 | struct Sprinting : Base 8 | { 9 | Sprinting(MultiMovementController& aParent) 10 | : Base(aParent) 11 | { 12 | } 13 | 14 | ~Sprinting() override{} 15 | void Enter() noexcept override; 16 | 17 | void GetAnimationData(AnimationData& aData) const override; 18 | 19 | std::optional Process(const Update& acEvent) noexcept override; 20 | 21 | private: 22 | 23 | float m_timer = 0.f; 24 | float m_duration = 0.f; 25 | }; 26 | } // namespace States 27 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Walking.cpp: -------------------------------------------------------------------------------- 1 | #include "Walking.h" 2 | 3 | #include "Idling.h" 4 | #include "Sprinting.h" 5 | 6 | #include "Game/Animation/AnimationData.h" 7 | #include "Game/Animation/MultiMovementController.h" 8 | 9 | namespace States 10 | { 11 | void Walking::Enter() noexcept 12 | { 13 | m_timer = 0.f; 14 | m_duration = m_parent.GetAnimLength("walk_0"); 15 | } 16 | 17 | void Walking::GetAnimationData(AnimationData& aData) const 18 | { 19 | aData.action = MTA_Move; 20 | aData.style = LS_Walk; 21 | aData.time = m_timer; 22 | } 23 | 24 | std::optional Walking::Process(const Update& acEvent) noexcept 25 | { 26 | if (acEvent.Speed >= kRunSpeed) 27 | return Transit(); 28 | if (acEvent.Speed < kWalkSpeed) 29 | return Transit(); 30 | 31 | m_timer += acEvent.Delta; 32 | m_timer = std::fmodf(m_timer, m_duration); 33 | 34 | return std::nullopt; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/client/Game/Animation/States/Walking.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Base.h" 4 | 5 | namespace States 6 | { 7 | struct Walking : Base 8 | { 9 | Walking(MultiMovementController& aParent) 10 | : Base(aParent) 11 | { 12 | } 13 | 14 | ~Walking() override {} 15 | void Enter() noexcept override; 16 | void GetAnimationData(AnimationData& aData) const override; 17 | 18 | std::optional Process(const Update& acEvent) noexcept override; 19 | 20 | private: 21 | 22 | float m_timer = 0.f; 23 | float m_duration = 0.f; 24 | }; 25 | } // namespace States 26 | -------------------------------------------------------------------------------- /code/client/Game/DelaySystem.h: -------------------------------------------------------------------------------- 1 | #include "RED4ext/Scripting/Natives/Generated/game/IDelaySystem.hpp" 2 | 3 | namespace Game 4 | { 5 | struct ExDelaySystem : Red::game::IDelaySystem 6 | { 7 | enum DelayFlag : uint32_t 8 | { 9 | NoFlag = 0, 10 | Flag1 = 1 << 0, 11 | Flag2 = 1 << 1, 12 | Flag3 = 1 << 2, 13 | Flag4 = 1 << 3 14 | }; 15 | 16 | virtual void sub_1B0(); 17 | virtual void sub_1B8(); 18 | virtual void sub_1C0(); 19 | virtual void AddFunction(const std::function& func, float delay, DelayFlag flag, int one, Red::CName name1, Red::CName name2); 20 | 21 | }; 22 | } -------------------------------------------------------------------------------- /code/client/Game/Entity.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct AnimationData; 6 | 7 | namespace Game 8 | { 9 | using EntityID = Core::OffsetPtr<0x48, Red::EntityID>; 10 | using EntityPtr = Core::OffsetPtr<0x90, Red::Entity*>; 11 | 12 | struct Controller 13 | { 14 | virtual RED4ext::Memory::PoolAI_Movement* GetMemoryPool(); 15 | virtual ~Controller(); 16 | 17 | uint32_t m_type = 0; // 4 18 | bool m_attached = false; // 8 19 | bool m_highPriotiry = false; // C 20 | Red::move::Component* MoveComponent; // 10 21 | Red::EntityID Id; 22 | }; 23 | 24 | constexpr auto IdleController_SetAnimation = Core::RawFunc< 25 | /* hash = */ 2268141838UL, 26 | /* type = */ void (*)(Game::Controller*, AnimationData&)>(); 27 | 28 | template 29 | Red::Handle FindComponent(Red::Entity* apEntity) 30 | { 31 | static auto pClass = Red::ResolveClass(); 32 | if (pClass && apEntity) 33 | { 34 | for (auto& component : apEntity->componentsStorage.components) 35 | { 36 | if (component && component->GetType()->IsA(pClass)) 37 | return Red::Cast(component); 38 | } 39 | } 40 | 41 | return {}; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/client/Game/MappinSystem.h: -------------------------------------------------------------------------------- 1 | #include "RED4ext/Scripting/Natives/Generated/game/mappins/IMappinSystem.hpp" 2 | #include "RED4ext/Scripting/Natives/Generated/game/mappins/MappinData.hpp" 3 | #include "RED4ext/Scripting/Natives/Generated/game/NewMappinID.hpp" 4 | #include "RED4ext/Scripting/Natives/Generated/game/mappins/MappinScriptData.hpp" 5 | #include "RED4ext/NativeTypes.hpp" 6 | #include "RED4ext/Scripting/Natives/Generated/Vector3.hpp" 7 | 8 | constexpr auto RegisterRemotePlayerMappin = Core::RawFunc<2624990479UL, 9 | Red::game::NewMappinID * (*)(Red::game::mappins::IMappinSystem *, Red::game::NewMappinID *, Red::game::mappins::MappinData const &, Red::WeakHandle *)>(); 10 | 11 | 12 | constexpr auto RegisterMappin = Core::RawFunc<3577160229UL, 13 | Red::game::NewMappinID * (*)(Red::game::mappins::IMappinSystem *, Red::game::NewMappinID *, Red::game::mappins::MappinData const &, Red::Vector3 *)>(); 14 | -------------------------------------------------------------------------------- /code/client/Game/MorphTargetManagerComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | inline Red::DynArray * GetTargetWeightEntries(Red::ent::MorphTargetManagerComponent * self) 7 | { 8 | return reinterpret_cast *>((uintptr_t)self + 0x98); 9 | } 10 | 11 | constexpr auto SetTargetWeightWithNormalize = Core::RawFunc<633871992UL, 12 | void (*)(Red::ent::MorphTargetManagerComponent *, Red::CName targetName, Red::CName regionName, float amount, bool force)>(); 13 | 14 | constexpr auto ResetWeights = Core::RawFunc<1054086242UL, 15 | void (*)(Red::ent::MorphTargetManagerComponent *)>(); 16 | 17 | -------------------------------------------------------------------------------- /code/client/Game/Movement.h: -------------------------------------------------------------------------------- 1 | #include "RED4ext/Scripting/Natives/Generated/game/Puppet.hpp" 2 | #include "RED4ext/SpinLock.hpp" 3 | 4 | struct MultiMovementController; 5 | 6 | namespace Game 7 | { 8 | struct StubMoveComponent 9 | { 10 | uint8_t pad[0xA8]; 11 | MultiMovementController* pController; 12 | uint8_t padB8[0x128 - 0xB0]; 13 | Red::SpinLock lock; 14 | }; 15 | } // namespace Game -------------------------------------------------------------------------------- /code/client/Game/PlayerSystem.h: -------------------------------------------------------------------------------- 1 | #include "RED4ext/Scripting/Natives/Generated/cp/PlayerSystem.hpp" 2 | #include "RED4ext/Scripting/Natives/Generated/game/Object.hpp" 3 | 4 | namespace Game 5 | { 6 | struct PlayerSystem : Red::PlayerSystem 7 | { 8 | virtual void sub_1B0(); // 1B0 9 | virtual void sub_1B8(); // 1B8 10 | virtual void sub_1C0(); // 1C0 11 | virtual void sub_1C8(); // 1C8 12 | virtual void sub_1D0(); // 1D0 13 | virtual void sub_1D8(); // 1D8 14 | virtual void GetLocalPlayerControlledGameObject(Red::Handle& aObject); // 1E0 15 | }; 16 | } -------------------------------------------------------------------------------- /code/client/Game/ScriptValidation.cpp: -------------------------------------------------------------------------------- 1 | #include "ScriptValidation.h" 2 | -------------------------------------------------------------------------------- /code/client/Game/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Utils.h" 2 | 3 | Red::WorldPosition Game::ToRed(const glm::vec3& acPosition) 4 | { 5 | Red::WorldPosition pos; 6 | pos.x = acPosition.x; 7 | pos.y = acPosition.y; 8 | pos.z = acPosition.z; 9 | return pos; 10 | } 11 | 12 | glm::vec3 Game::ToGlm(const Red::WorldPosition& acPosition) 13 | { 14 | glm::vec3 pos{acPosition.x, acPosition.y, acPosition.z}; 15 | return pos; 16 | } 17 | 18 | Red::Quaternion Game::ToRed(const glm::quat& acOrientation) 19 | { 20 | return {acOrientation.x, acOrientation.y, acOrientation.z, acOrientation.w}; 21 | } 22 | 23 | glm::quat Game::ToGlm(const Red::Quaternion& acOrientation) 24 | { 25 | return {acOrientation.r, 26 | acOrientation.i, 27 | acOrientation.j, 28 | acOrientation.k}; 29 | } -------------------------------------------------------------------------------- /code/client/Red/Alias.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Red 4 | { 5 | using namespace RED4ext; 6 | } 7 | 8 | namespace Red::Detail 9 | { 10 | using namespace RED4ext::Detail; 11 | } 12 | -------------------------------------------------------------------------------- /code/client/Red/Engine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TypeInfo/Resolving.hpp" 4 | 5 | #include "Engine/Framework.hpp" 6 | #include "Engine/LogChannel.hpp" 7 | 8 | #include "Engine/Mappings.hpp" 9 | -------------------------------------------------------------------------------- /code/client/Red/Engine/Framework.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Macros/Framework.hpp" 4 | 5 | namespace Red 6 | { 7 | template 8 | struct RuntimeSystemMapping : public std::false_type {}; 9 | 10 | namespace Detail 11 | { 12 | template 13 | concept HasRuntimeSystemMapping = RuntimeSystemMapping::value 14 | && RuntimeSystemMapping::offset >= 0 15 | && RuntimeSystemMapping::offset <= 64; 16 | } 17 | 18 | template 19 | requires std::is_base_of_v && std::is_base_of_v 20 | U* GetGameSystem() 21 | { 22 | static const auto s_type = GetType(); 23 | auto& gameInstance = CGameEngine::Get()->framework->gameInstance; 24 | return reinterpret_cast(gameInstance->GetSystem(s_type)); 25 | } 26 | 27 | template 28 | requires std::is_base_of_v && std::is_base_of_v && Detail::HasRuntimeSystemMapping 29 | U* GetRuntimeSystem() 30 | { 31 | constexpr auto systemOffset = RuntimeSystemMapping::offset * sizeof(Handle); 32 | const auto& runtimeSceneAddr = CGameEngine::Get()->framework->unk18; 33 | return reinterpret_cast*>(runtimeSceneAddr + systemOffset)->instance; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/client/Red/Engine/LogChannel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Red::Log 4 | { 5 | inline void Channel(Red::CName aChannel, const std::string& aMessage) 6 | { 7 | static auto* s_rtti = CRTTISystem::Get(); 8 | static auto* s_logFunc = s_rtti->GetFunction("LogChannel"); 9 | static auto* s_stringType = s_rtti->GetType("String"); 10 | static auto* s_stringRefType = s_rtti->GetType("script_ref:String"); 11 | static auto* s_nameType = s_rtti->GetType("CName"); 12 | 13 | CString message(aMessage.c_str()); 14 | ScriptRef messageRef; 15 | messageRef.innerType = s_stringType; 16 | messageRef.hash = s_stringType->GetName(); 17 | messageRef.ref = &message; 18 | 19 | StackArgs_t args; 20 | args.emplace_back(s_nameType, &aChannel); 21 | args.emplace_back(s_stringRefType, &messageRef); 22 | 23 | CStack stack(nullptr, args.data(), static_cast(args.size()), nullptr); 24 | 25 | s_logFunc->Execute(&stack); 26 | } 27 | 28 | template 29 | constexpr void Channel(CName aChannel, std::format_string aFormat, Args&&... aArgs) 30 | { 31 | Channel(aChannel, std::format(aFormat, std::forward(aArgs)...)); 32 | } 33 | 34 | template 35 | constexpr void Debug(std::format_string aFormat, Args&&... aArgs) 36 | { 37 | Channel("DEBUG", std::format(aFormat, std::forward(aArgs)...)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/client/Red/Engine/Macros/Framework.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define RTTI_MAP_RUNTIME_SYSTEM(_type, _offset) \ 4 | template<> \ 5 | struct Red::RuntimeSystemMapping<_type> : public std::true_type \ 6 | { \ 7 | static constexpr auto offset = _offset; \ 8 | }; 9 | -------------------------------------------------------------------------------- /code/client/Red/Specializations.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TypeInfo/Resolving.hpp" 4 | 5 | template<> 6 | struct std::hash 7 | { 8 | std::size_t operator()(RED4ext::CName aKey) const 9 | { 10 | return aKey.hash; 11 | } 12 | }; 13 | 14 | template<> 15 | struct std::hash 16 | { 17 | std::size_t operator()(RED4ext::TweakDBID aKey) const 18 | { 19 | return aKey.value; 20 | } 21 | }; 22 | 23 | template<> 24 | struct std::hash 25 | { 26 | std::size_t operator()(RED4ext::ResourcePath aKey) const 27 | { 28 | return aKey.hash; 29 | } 30 | }; 31 | 32 | template<> 33 | struct std::hash 34 | { 35 | std::size_t operator()(RED4ext::NodeRef aKey) const 36 | { 37 | return aKey.hash; 38 | } 39 | }; 40 | 41 | template 42 | requires std::is_class_v && std::is_convertible_v && Red::Detail::HasGeneratedTypeName 43 | struct std::hash 44 | { 45 | std::size_t operator()(T aKey) const 46 | { 47 | return static_cast(aKey); 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /code/client/Red/TypeInfo.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TypeInfo/Construction.hpp" 4 | #include "TypeInfo/Definition.hpp" 5 | #include "TypeInfo/Invocation.hpp" 6 | #include "TypeInfo/Registrar.hpp" 7 | #include "TypeInfo/Resolving.hpp" 8 | 9 | #include "TypeInfo/Mappings.hpp" 10 | -------------------------------------------------------------------------------- /code/client/Red/TypeInfo/Construction.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Resolving.hpp" 4 | 5 | namespace Red 6 | { 7 | template 8 | inline T* Construct() 9 | { 10 | auto type = GetType(); 11 | auto instance = reinterpret_cast(type->GetAllocator()->AllocAligned(type->GetSize(), 12 | type->GetAlignment()).memory); 13 | type->Construct(instance); 14 | return instance; 15 | } 16 | 17 | template 18 | inline void Destruct(T* aInstance) 19 | { 20 | auto type = GetType(); 21 | type->Destruct(aInstance); 22 | type->GetAllocator()->Free(aInstance); 23 | } 24 | } 25 | 26 | template 27 | requires std::is_abstract_v && Red::Detail::HasGeneratedTypeName 28 | struct RED4ext::Detail::AllocatorHook : std::true_type 29 | { 30 | inline static Memory::IAllocator* Get() 31 | { 32 | return Red::GetClass()->GetAllocator(); 33 | } 34 | }; 35 | 36 | template 37 | requires std::is_abstract_v && Red::Detail::HasGeneratedTypeName 38 | struct RED4ext::Detail::ConstructorHook : std::true_type 39 | { 40 | inline static void Apply(T* aInstance) 41 | { 42 | Red::GetClass()->ConstructCls(aInstance); 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /code/client/Red/TypeInfo/Mappings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Resolving.hpp" 4 | 5 | namespace Red 6 | { 7 | RTTI_MAP_TYPE_NAME(int8_t, "Int8"); 8 | RTTI_MAP_TYPE_NAME(uint8_t, "Uint8"); 9 | RTTI_MAP_TYPE_NAME(int16_t, "Int16"); 10 | RTTI_MAP_TYPE_NAME(uint16_t, "Uint16"); 11 | RTTI_MAP_TYPE_NAME(int32_t, "Int32"); 12 | RTTI_MAP_TYPE_NAME(uint32_t, "Uint32"); 13 | RTTI_MAP_TYPE_NAME(int64_t, "Int64"); 14 | RTTI_MAP_TYPE_NAME(uint64_t, "Uint64"); 15 | RTTI_MAP_TYPE_NAME(float, "Float"); 16 | RTTI_MAP_TYPE_NAME(double, "Double"); 17 | RTTI_MAP_TYPE_NAME(bool, "Bool"); 18 | RTTI_MAP_TYPE_NAME(CString, "String"); 19 | RTTI_MAP_TYPE_NAME(CName, "CName"); 20 | RTTI_MAP_TYPE_NAME(TweakDBID, "TweakDBID"); 21 | RTTI_MAP_TYPE_NAME(ItemID, "gameItemID"); 22 | RTTI_MAP_TYPE_NAME(NodeRef, "NodeRef"); 23 | RTTI_MAP_TYPE_NAME(Variant, "Variant"); 24 | 25 | RTTI_MAP_TYPE_PREFIX(DynArray, "array:"); 26 | RTTI_MAP_TYPE_PREFIX(Handle, "handle:"); 27 | RTTI_MAP_TYPE_PREFIX(WeakHandle, "whandle:"); 28 | RTTI_MAP_TYPE_PREFIX(ResourceReference, "rRef:"); 29 | RTTI_MAP_TYPE_PREFIX(ResourceAsyncReference, "raRef:"); 30 | 31 | RTTI_MAP_TYPE_NAME(char, "Uint8"); 32 | } 33 | -------------------------------------------------------------------------------- /code/client/Red/Utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Utils/Handles.hpp" 4 | #include "Utils/JobQueues.hpp" 5 | #include "Utils/Resources.hpp" 6 | -------------------------------------------------------------------------------- /code/client/Red/Utils/JobQueues.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Red 4 | { 5 | template 6 | inline void WaitForJob(JobHandle& aJob, const W& aTimeout) 7 | { 8 | std::mutex mutex; 9 | std::unique_lock lock(mutex); 10 | std::condition_variable cv; 11 | 12 | JobQueue queue; 13 | queue.Wait(aJob); 14 | queue.Dispatch([&lock, &cv]() { 15 | lock.release(); 16 | cv.notify_all(); 17 | }); 18 | 19 | cv.wait_for(lock, aTimeout); 20 | 21 | if (lock.owns_lock()) 22 | { 23 | cv.wait_for(lock, aTimeout); 24 | } 25 | 26 | if (!lock || !lock.owns_lock()) 27 | { 28 | mutex.unlock(); 29 | } 30 | } 31 | 32 | template 33 | inline void WaitForQueue(JobQueue& aQueue, const W& aTimeout) 34 | { 35 | WaitForJob(aQueue.unk10, aTimeout); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/client/Support/MinHook/MinHookProvider.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/TaskQueue.h" 4 | #include "Core/Foundation/Feature.hpp" 5 | #include "Core/Hooking/HookingDriver.hpp" 6 | 7 | namespace Support 8 | { 9 | class MinHookProvider 10 | : public Core::Feature 11 | , public Core::HookingDriver 12 | { 13 | public: 14 | MinHookProvider(); 15 | ~MinHookProvider() override; 16 | 17 | bool HookAttach(uintptr_t aAddress, void* aCallback) override; 18 | bool HookAttach(uintptr_t aAddress, void* aCallback, void** aOriginal) override; 19 | bool HookDetach(uintptr_t aAddress) override; 20 | void Enqueue(std::function aFunc) override; 21 | 22 | void OnGameUpdate(RED4ext::CGameApplication* apApp) override; 23 | 24 | private: 25 | 26 | TaskQueue m_queue; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /code/client/Support/RedLib/RedLibProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "RedLibProvider.hpp" 2 | #include "Red/TypeInfo/Registrar.hpp" 3 | 4 | void Support::RedLibProvider::OnBootstrap() 5 | { 6 | Red::TypeInfoRegistrar::RegisterDiscovered(); 7 | } 8 | -------------------------------------------------------------------------------- /code/client/Support/RedLib/RedLibProvider.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Foundation/Feature.hpp" 4 | 5 | namespace Support 6 | { 7 | class RedLibProvider : public Core::Feature 8 | { 9 | void OnBootstrap() override; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /code/client/Support/Spdlog/SpdlogProvider.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Foundation/Feature.hpp" 4 | #include "Core/Logging/LoggingDriver.hpp" 5 | 6 | namespace Support 7 | { 8 | class SpdlogProvider 9 | : public Core::Feature 10 | , public Core::LoggingDriver 11 | { 12 | public: 13 | void LogInfo(const std::string_view& aMessage) override; 14 | void LogWarning(const std::string_view& aMessage) override; 15 | void LogError(const std::string_view& aMessage) override; 16 | void LogDebug(const std::string_view& aMessage) override; 17 | void LogFlush() override; 18 | 19 | auto SetLogPath(const std::filesystem::path& aPath) noexcept 20 | { 21 | m_logPath = aPath; 22 | return Defer(this); 23 | } 24 | 25 | protected: 26 | void OnInitialize() override; 27 | 28 | std::filesystem::path m_logPath; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /code/common/CommonPCH.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #ifdef WIN32 13 | #define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport) 14 | #else 15 | #define EXTERN_DLL_EXPORT extern "C" 16 | #endif -------------------------------------------------------------------------------- /code/common/Core/BoundedAllocator.cpp: -------------------------------------------------------------------------------- 1 | #include "BoundedAllocator.h" 2 | 3 | 4 | BoundedAllocator::BoundedAllocator(const size_t aMaximumAllocationSize) noexcept 5 | : m_availableMemory{ aMaximumAllocationSize } 6 | { 7 | } 8 | 9 | void* BoundedAllocator::Allocate(size_t aSize) noexcept 10 | { 11 | if (m_availableMemory >= aSize) 12 | { 13 | m_availableMemory -= aSize; 14 | return MimallocAllocator::Allocate(aSize); 15 | } 16 | 17 | return nullptr; 18 | } 19 | 20 | void BoundedAllocator::Free(void* apData) noexcept 21 | { 22 | m_availableMemory += Size(apData); 23 | 24 | MimallocAllocator::Free(apData); 25 | } 26 | -------------------------------------------------------------------------------- /code/common/Core/BoundedAllocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MimallocAllocator.h" 4 | 5 | 6 | struct BoundedAllocator : MimallocAllocator 7 | { 8 | BoundedAllocator(size_t aMaximumAllocationSize) noexcept; 9 | virtual ~BoundedAllocator() = default; 10 | 11 | TP_NOCOPYMOVE(BoundedAllocator); 12 | 13 | [[nodiscard]] void* Allocate(size_t aSize) noexcept override; 14 | void Free(void* apData) noexcept override; 15 | 16 | private: 17 | 18 | size_t m_availableMemory; 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /code/common/Core/Filesystem.cpp: -------------------------------------------------------------------------------- 1 | #include "Filesystem.h" 2 | #include "Platform.h" 3 | 4 | #include 5 | 6 | #if TP_PLATFORM_WINDOWS 7 | #include 8 | 9 | EXTERN_C IMAGE_DOS_HEADER __ImageBase; 10 | #endif 11 | 12 | 13 | std::filesystem::path GetPath() noexcept 14 | { 15 | #if TP_PLATFORM_WINDOWS 16 | WCHAR dllPath[MAX_PATH] = { 0 }; 17 | GetModuleFileNameW(reinterpret_cast(&__ImageBase), dllPath, std::size(dllPath)); 18 | 19 | std::error_code ec; 20 | const auto currentPath = std::filesystem::path(dllPath).parent_path(); 21 | 22 | return currentPath; 23 | #else 24 | return std::filesystem::current_path(); 25 | #endif 26 | } 27 | 28 | String LoadFile(const std::filesystem::path& acPath) noexcept 29 | { 30 | std::ifstream file(acPath, std::ios::binary); 31 | file.seekg(0, std::ifstream::end); 32 | const size_t length = file.tellg(); 33 | file.seekg(0, std::ifstream::beg); 34 | 35 | String content(length, '\0'); 36 | file.read(content.data(), length); 37 | 38 | return content; 39 | } 40 | 41 | bool SaveFile(const std::filesystem::path& acPath, const String& acData) noexcept 42 | { 43 | std::ofstream out(acPath, std::ios::binary); 44 | if (!out.is_open()) 45 | return false; 46 | 47 | out.write(acData.data(), acData.size()); 48 | 49 | return true; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /code/common/Core/Filesystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Stl.h" 5 | 6 | 7 | 8 | std::filesystem::path GetPath() noexcept; 9 | String LoadFile(const std::filesystem::path& acPath) noexcept; 10 | bool SaveFile(const std::filesystem::path& acPath, const String& acData) noexcept; 11 | -------------------------------------------------------------------------------- /code/common/Core/Hash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace FHash 7 | { 8 | uint64_t Crc64(const unsigned char* acpData, std::size_t aLength); 9 | uint64_t FNV1a64(const char* aText, uint64_t aSeed = 0xCBF29CE484222325); 10 | 11 | template inline void Combine(std::size_t& seed, const T& v) 12 | { 13 | std::hash hasher; 14 | seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /code/common/Core/Locked.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Lockable.h" 4 | 5 | template 6 | struct Locked 7 | { 8 | Locked(SharedPtr::Data> apData) 9 | : m_pData(std::move(apData)) 10 | , m_handle(m_pData->Lock) 11 | { 12 | } 13 | 14 | operator typename Lockable::Ref() const 15 | { 16 | return { m_pData }; 17 | } 18 | 19 | bool IsValid() const 20 | { 21 | return (bool)m_pData; 22 | } 23 | 24 | operator T& () 25 | { 26 | return Get(); 27 | } 28 | 29 | operator T&() const 30 | { 31 | return Get(); 32 | } 33 | 34 | const T& Get() const noexcept 35 | { 36 | return m_pData->Value; 37 | } 38 | 39 | T& Get() noexcept 40 | { 41 | return m_pData->Value; 42 | } 43 | 44 | private: 45 | friend struct Lockable; 46 | 47 | SharedPtr::Data> m_pData; 48 | std::scoped_lock m_handle; 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /code/common/Core/Memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /code/common/Core/MimallocAllocator.cpp: -------------------------------------------------------------------------------- 1 | #include "MimallocAllocator.h" 2 | 3 | #include 4 | 5 | 6 | void* MimallocAllocator::Allocate(const size_t aSize) noexcept 7 | { 8 | return mi_malloc(aSize); 9 | } 10 | 11 | void MimallocAllocator::Free(void* apData) noexcept 12 | { 13 | mi_free(apData); 14 | } 15 | 16 | size_t MimallocAllocator::Size(void* apData) noexcept 17 | { 18 | if (apData == nullptr) return 0; 19 | 20 | return mi_malloc_size(apData); 21 | } 22 | 23 | void* MimallocAllocator::AlignedAllocate(size_t aSize, size_t aAlignment) noexcept 24 | { 25 | return mi_malloc_aligned(aSize, aAlignment); 26 | } 27 | 28 | void MimallocAllocator::AlignedFree(void* apData) noexcept 29 | { 30 | mi_free(apData); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /code/common/Core/MimallocAllocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Allocator.h" 4 | 5 | struct MimallocAllocator : Allocator 6 | { 7 | MimallocAllocator() noexcept = default; 8 | virtual ~MimallocAllocator() = default; 9 | 10 | TP_NOCOPYMOVE(MimallocAllocator); 11 | 12 | [[nodiscard]] void* Allocate(size_t aSize) noexcept override; 13 | void Free(void* apData) noexcept override; 14 | [[nodiscard]] size_t Size(void* apData) noexcept override; 15 | 16 | [[nodiscard]] static void* AlignedAllocate(size_t aSize, size_t aAlignment) noexcept; 17 | static void AlignedFree(void* apData) noexcept; 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /code/common/Core/Platform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Do mac someday ? 4 | #ifdef _WIN32 5 | #define TP_PLATFORM_WINDOWS 1 6 | #define TP_PLATFORM_LINUX 0 7 | #else 8 | #define TP_PLATFORM_WINDOWS 0 9 | #define TP_PLATFORM_LINUX 1 10 | #endif 11 | 12 | #if defined(_LP64) || defined(_WIN64) 13 | #define TP_PLATFORM_64 1 14 | #define TP_PLATFORM_32 0 15 | #else 16 | #define TP_PLATFORM_64 0 17 | #define TP_PLATFORM_32 1 18 | #endif 19 | 20 | #ifdef NDEBUG 21 | #define TP_RELEASE 1 22 | #define TP_DEBUG 0 23 | #else 24 | #define TP_RELEASE 0 25 | #define TP_DEBUG 1 26 | #endif 27 | 28 | consteval bool IsDebug() 29 | { 30 | return false; 31 | return TP_DEBUG; 32 | } 33 | 34 | #define TP_UNUSED(x) (void)x; 35 | -------------------------------------------------------------------------------- /code/common/Core/ScratchAllocator.cpp: -------------------------------------------------------------------------------- 1 | #include "ScratchAllocator.h" 2 | #include "Platform.h" 3 | #include 4 | 5 | 6 | ScratchAllocator::ScratchAllocator(const size_t aSize) noexcept 7 | : m_size(aSize) 8 | , m_baseSize(aSize) 9 | { 10 | m_pBaseData = m_pData = GetDefault()->Allocate(aSize); 11 | 12 | if (m_pData == nullptr) 13 | { 14 | m_size = 0; 15 | } 16 | } 17 | 18 | ScratchAllocator::~ScratchAllocator() 19 | { 20 | GetDefault()->Free(m_pBaseData); 21 | } 22 | 23 | void* ScratchAllocator::Allocate(const size_t aSize) noexcept 24 | { 25 | if (std::align(alignof(std::max_align_t), aSize, m_pData, m_size)) 26 | { 27 | const auto pResult = m_pData; 28 | m_pData = static_cast(m_pData) + aSize; 29 | m_size -= aSize; 30 | return pResult; 31 | } 32 | 33 | return nullptr; 34 | } 35 | 36 | void ScratchAllocator::Free(void* apData) noexcept 37 | { 38 | TP_UNUSED(apData); 39 | } 40 | 41 | size_t ScratchAllocator::Size(void* apData) noexcept 42 | { 43 | TP_UNUSED(apData); 44 | return m_size; 45 | } 46 | 47 | void ScratchAllocator::Reset() noexcept 48 | { 49 | m_size = m_baseSize; 50 | m_pData = m_pBaseData; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /code/common/Core/ScratchAllocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Allocator.h" 4 | 5 | 6 | struct ScratchAllocator : Allocator 7 | { 8 | explicit ScratchAllocator(size_t aSize) noexcept; 9 | virtual ~ScratchAllocator(); 10 | 11 | TP_NOCOPYMOVE(ScratchAllocator); 12 | 13 | [[nodiscard]] void* Allocate(size_t aSize) noexcept override; 14 | void Free(void* apData) noexcept override; 15 | [[nodiscard]] size_t Size(void* apData) noexcept override; 16 | void Reset() noexcept override; 17 | 18 | private: 19 | 20 | size_t m_size; 21 | size_t m_baseSize; 22 | void* m_pData; 23 | void* m_pBaseData; 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /code/common/Core/StandardAllocator.cpp: -------------------------------------------------------------------------------- 1 | #include "StandardAllocator.h" 2 | 3 | #include 4 | #ifdef __APPLE__ 5 | #include 6 | #else 7 | #include 8 | #endif 9 | 10 | 11 | 12 | void* StandardAllocator::Allocate(const size_t aSize) noexcept 13 | { 14 | return malloc(aSize); 15 | } 16 | 17 | void StandardAllocator::Free(void* apData) noexcept 18 | { 19 | free(apData); 20 | } 21 | 22 | size_t StandardAllocator::Size(void* apData) noexcept 23 | { 24 | if (apData == nullptr) return 0; 25 | 26 | #ifdef _WIN32 27 | return _msize(apData); 28 | #elif __linux__ 29 | return malloc_usable_size(apData); 30 | #elif __APPLE__ 31 | return malloc_size(apData); 32 | #else 33 | static_assert(false, "Not implemented"); 34 | return 0; 35 | #endif 36 | } 37 | -------------------------------------------------------------------------------- /code/common/Core/StandardAllocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Allocator.h" 4 | 5 | 6 | struct StandardAllocator : Allocator 7 | { 8 | StandardAllocator() noexcept = default; 9 | virtual ~StandardAllocator() = default; 10 | 11 | TP_NOCOPYMOVE(StandardAllocator); 12 | 13 | [[nodiscard]] void* Allocate(size_t aSize) noexcept override; 14 | void Free(void* apData) noexcept override; 15 | [[nodiscard]] size_t Size(void* apData) noexcept override; 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /code/common/Core/StlAllocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Allocator.h" 4 | #include 5 | 6 | 7 | template 8 | struct StlAllocator 9 | { 10 | using value_type = T; 11 | 12 | StlAllocator() 13 | { 14 | m_pAllocator = Allocator::Get(); 15 | } 16 | 17 | template 18 | constexpr StlAllocator(const StlAllocator& acRhs) noexcept 19 | { 20 | m_pAllocator = acRhs.m_pAllocator; 21 | } 22 | 23 | [[nodiscard]] T* allocate(std::size_t aSize) 24 | { 25 | if (aSize > std::size_t(-1) / sizeof(T)) 26 | throw std::bad_alloc(); 27 | 28 | if (auto p = static_cast(m_pAllocator->Allocate(aSize * sizeof(T)))) 29 | return p; 30 | 31 | throw std::bad_alloc(); 32 | } 33 | void deallocate(T* p, std::size_t) noexcept 34 | { 35 | m_pAllocator->Free(p); 36 | } 37 | 38 | 39 | Allocator* m_pAllocator; 40 | }; 41 | 42 | template 43 | bool operator==(const StlAllocator&, const StlAllocator&) { return true; } 44 | template 45 | bool operator!=(const StlAllocator&, const StlAllocator&) { return false; } 46 | -------------------------------------------------------------------------------- /code/common/Core/TaskQueue.cpp: -------------------------------------------------------------------------------- 1 | #include "TaskQueue.h" 2 | 3 | 4 | 5 | void TaskQueue::Add(std::function aFunction) noexcept 6 | { 7 | std::scoped_lock _{ m_mutex }; 8 | 9 | UnsafeAdd(std::move(aFunction)); 10 | } 11 | 12 | bool TaskQueue::Pop(std::function& aResultFunction) noexcept 13 | { 14 | std::scoped_lock _{ m_mutex }; 15 | 16 | return UnsafePop(aResultFunction); 17 | } 18 | 19 | size_t TaskQueue::Drain() noexcept 20 | { 21 | size_t count = 0; 22 | 23 | std::scoped_lock _{ m_mutex }; 24 | 25 | std::function func; 26 | while (UnsafePop(func)) 27 | { 28 | func(); 29 | ++count; 30 | } 31 | 32 | return count; 33 | } 34 | 35 | void TaskQueue::UnsafeAdd(std::function aFunction) noexcept 36 | { 37 | m_tasks.emplace(std::move(aFunction)); 38 | } 39 | 40 | bool TaskQueue::UnsafePop(std::function& aResultFunction) noexcept 41 | { 42 | if (m_tasks.empty()) 43 | return false; 44 | 45 | aResultFunction = std::move(m_tasks.front()); 46 | 47 | m_tasks.pop(); 48 | 49 | return true; 50 | } 51 | 52 | std::mutex& TaskQueue::Lock() noexcept 53 | { 54 | return m_mutex; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /code/common/Core/TaskQueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Stl.h" 4 | #include 5 | 6 | 7 | // Thread safe task queue 8 | struct TaskQueue 9 | { 10 | void Add(std::function aFunction) noexcept; 11 | bool Pop(std::function& aResultFunction) noexcept; 12 | size_t Drain() noexcept; 13 | 14 | void UnsafeAdd(std::function aFunction) noexcept; 15 | bool UnsafePop(std::function& aResultFunction) noexcept; 16 | 17 | [[nodiscard]] std::mutex& Lock() noexcept; 18 | 19 | private: 20 | 21 | std::mutex m_mutex; 22 | Queue> m_tasks; 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /code/common/Core/TrackAllocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Allocator.hpp" 4 | 5 | 6 | { 7 | template 8 | struct TrackAllocator : Allocator 9 | { 10 | TrackAllocator() noexcept = default; 11 | virtual ~TrackAllocator() {} 12 | 13 | TP_NOCOPYMOVE(TrackAllocator); 14 | 15 | [[nodiscard]] void* Allocate(size_t aSize) noexcept override 16 | { 17 | void* pData = m_allocator.Allocate(aSize); 18 | 19 | if (pData) 20 | m_usedMemory += m_allocator.Size(pData); 21 | 22 | return pData; 23 | } 24 | 25 | void Free(void* apData) noexcept override 26 | { 27 | m_usedMemory -= m_allocator.Size(apData); 28 | } 29 | 30 | [[nodiscard]]size_t Size(void* apData) noexcept override 31 | { 32 | return m_allocator.Size(apData); 33 | } 34 | 35 | [[nodiscard]] size_t GetUsedMemory() const noexcept 36 | { 37 | return m_usedMemory; 38 | } 39 | 40 | private: 41 | 42 | T m_allocator; 43 | size_t m_usedMemory{ 0 }; 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /code/common/Core/ViewBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "ViewBuffer.h" 2 | 3 | 4 | ViewBuffer::ViewBuffer(uint8_t* apData, size_t aSize) noexcept 5 | { 6 | m_pData = apData; 7 | m_size = aSize; 8 | } 9 | 10 | ViewBuffer::~ViewBuffer() 11 | { 12 | m_pData = nullptr; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /code/common/Core/ViewBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Buffer.h" 4 | 5 | 6 | struct ViewBuffer : Buffer 7 | { 8 | explicit ViewBuffer(uint8_t* apData, size_t aSize) noexcept; 9 | virtual ~ViewBuffer(); 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /code/common/Math/Hash.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/common/Math/Hash.h -------------------------------------------------------------------------------- /code/common/Math/Math.cpp: -------------------------------------------------------------------------------- 1 | #include "Math.h" 2 | #include 3 | 4 | 5 | float Sigmoid(float x, float lambda, float k) noexcept 6 | { 7 | return 1.f / (1.f + expf(-x * lambda + k)); 8 | } 9 | 10 | float SmoothStep(float delta) noexcept 11 | { 12 | return delta * delta * (3 - 2 * delta); 13 | } 14 | 15 | float DeltaAngle(float from, float to, bool useRadians) noexcept 16 | { 17 | const float halfCircle = useRadians ? float(Pi) : 180.f; 18 | 19 | if (fabs(from - to) >= halfCircle) 20 | { 21 | if (from < to) 22 | { 23 | return to - (from + halfCircle * 2); 24 | } 25 | 26 | return (to + halfCircle * 2) - from; 27 | } 28 | 29 | return to - from; 30 | } 31 | 32 | float Mod(float aValue, float aMax) noexcept 33 | { 34 | return fmod(aValue, aMax); 35 | } 36 | 37 | float Max(float aVal, float aMax) noexcept 38 | { 39 | return aVal < aMax ? aMax : aVal; 40 | } 41 | 42 | float Min(float aVal, float aMin) noexcept 43 | { 44 | return aVal > aMin ? aMin : aVal; 45 | } 46 | 47 | float Clamp(float aValue, float aMin, float aMax) noexcept 48 | { 49 | return Max(aMin, Min(aValue, aMax)); 50 | } 51 | 52 | float Sqrt(float aValue) noexcept 53 | { 54 | return sqrt(aValue); 55 | } 56 | 57 | double Sqrt(double aValue) noexcept 58 | { 59 | return sqrt(aValue); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /code/common/Math/Math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | constexpr double Pi = 3.14159265358979323846; 5 | 6 | [[nodiscard]] float Sigmoid(float x, float lambda, float k) noexcept; 7 | [[nodiscard]] float SmoothStep(float delta) noexcept; 8 | [[nodiscard]] float DeltaAngle(float from, float to, bool useRadians) noexcept; 9 | [[nodiscard]] float Mod(float aValue, float aMax) noexcept; 10 | [[nodiscard]] float Max(float aVal, float aMax) noexcept; 11 | [[nodiscard]] float Min(float aVal, float aMin) noexcept; 12 | [[nodiscard]] float Clamp(float aValue, float aMin, float aMax) noexcept; 13 | [[nodiscard]] float Sqrt(float aValue) noexcept; 14 | [[nodiscard]] double Sqrt(double aValue) noexcept; 15 | 16 | template [[nodiscard]] 17 | T LerpDelta(const T& a, const T& b, float delta) noexcept 18 | { 19 | return (b - a) * delta; 20 | } 21 | 22 | // delta should be between 0.f & 1.f 23 | template [[nodiscard]] 24 | T Lerp(const T& a, const T& b, float delta) noexcept 25 | { 26 | return a + LerpDelta(a, b, delta); 27 | } 28 | -------------------------------------------------------------------------------- /code/common/Math/Vector2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | template 6 | struct Vector2 : glm::vec<2, T, glm::defaultp> 7 | { 8 | Vector2(T x, T y) 9 | : glm::vec<2, T, glm::defaultp>(x, y) 10 | { 11 | } 12 | }; 13 | 14 | namespace std 15 | { 16 | template struct hash> 17 | { 18 | size_t operator()(const Vector2& aVector) const noexcept 19 | { 20 | size_t hash = 0; 21 | FHash::Combine(hash, aVector.x); 22 | FHash::Combine(hash, aVector.y); 23 | return hash; 24 | } 25 | }; 26 | } // namespace std -------------------------------------------------------------------------------- /code/common/Math/Vector3.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiltedphoques/CyberpunkMP/0ccb0cfa78222cc463ea937e0c8271060f9afd2a/code/common/Math/Vector3.h -------------------------------------------------------------------------------- /code/common/Network/Packet.cpp: -------------------------------------------------------------------------------- 1 | #include "Packet.h" 2 | #include "SteamInterface.h" 3 | 4 | 5 | Packet::Packet() noexcept 6 | : m_pData(nullptr) 7 | , m_size(0) 8 | { 9 | } 10 | 11 | Packet::Packet(const uint32_t aSize) noexcept 12 | : m_pData(nullptr) 13 | , m_size(aSize + 1) 14 | { 15 | m_pData = static_cast(GetAllocator()->Allocate(m_size)); 16 | m_pData[0] = kPayload; 17 | } 18 | 19 | Packet::~Packet() noexcept 20 | { 21 | GetAllocator()->Free(m_pData); 22 | } 23 | 24 | char* Packet::GetData() const noexcept 25 | { 26 | return m_pData + 1; 27 | } 28 | 29 | uint32_t Packet::GetSize() const noexcept 30 | { 31 | return m_size - 1; 32 | } 33 | 34 | uint32_t Packet::GetTotalSize() const noexcept 35 | { 36 | return m_size; 37 | } 38 | 39 | bool Packet::IsValid() const noexcept 40 | { 41 | return m_pData != nullptr; 42 | } 43 | 44 | PacketView::PacketView(char* aPointer, uint32_t aSize) 45 | : Packet() 46 | { 47 | m_pData = aPointer; 48 | m_size = aSize; 49 | 50 | m_pData[0] = kPayload; 51 | } 52 | 53 | PacketView::~PacketView() 54 | { 55 | m_pData = nullptr; 56 | m_size = 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /code/common/Network/Packet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Core/Meta.h" 4 | #include "Core/Allocator.h" 5 | 6 | 7 | struct Packet 8 | { 9 | TP_ALLOCATOR; 10 | 11 | Packet() noexcept; 12 | Packet(uint32_t aSize) noexcept; 13 | virtual ~Packet() noexcept; 14 | 15 | TP_NOCOPYMOVE(Packet); 16 | 17 | // Get the start of the write buffer 18 | [[nodiscard]] char* GetData() const noexcept; 19 | 20 | // Get the writable data size, note that the actual packet size may differ from that 21 | [[nodiscard]] uint32_t GetSize() const noexcept; 22 | 23 | // Get the writable data size + protocol data size 24 | [[nodiscard]] uint32_t GetTotalSize() const noexcept; 25 | 26 | // Returns true if the packet has an associated buffer, usually used to check if the underlying allocator had enough space 27 | [[nodiscard]] bool IsValid() const noexcept; 28 | 29 | protected: 30 | 31 | friend struct Server; 32 | friend struct Client; 33 | 34 | char* m_pData; 35 | uint32_t m_size; 36 | }; 37 | 38 | struct PacketView : Packet 39 | { 40 | PacketView(char* aPointer, uint32_t aSize); 41 | virtual ~PacketView(); 42 | }; 43 | 44 | -------------------------------------------------------------------------------- /code/common/Network/SteamInterface.cpp: -------------------------------------------------------------------------------- 1 | #include "SteamInterface.h" 2 | #include "steam/steamnetworkingsockets.h" 3 | 4 | #include 5 | 6 | 7 | static std::atomic s_initCounter = 0; 8 | 9 | void SteamInterface::Acquire() 10 | { 11 | if (s_initCounter.fetch_add(1, std::memory_order_relaxed) == 0) 12 | { 13 | SteamDatagramErrMsg errorMessage; 14 | if (!GameNetworkingSockets_Init(nullptr, errorMessage)) 15 | { 16 | // TODO: Error management 17 | } 18 | } 19 | } 20 | 21 | void SteamInterface::Release() 22 | { 23 | // This seems to conflict with the game's handles so disabling it 24 | if (s_initCounter.fetch_sub(1, std::memory_order_relaxed) == 1) 25 | { 26 | // GameNetworkingSockets_Kill(); 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /code/common/Network/SteamInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "steam/steamnetworkingsockets.h" 4 | 5 | 6 | enum EPacketFlags 7 | { 8 | kReliable, 9 | kUnreliable 10 | }; 11 | 12 | enum EConnectOpcode : uint8_t 13 | { 14 | kPayload = 0, 15 | kServerTime = 1, 16 | kCompressedPayload = 2, 17 | kHandshake = 3 18 | }; 19 | 20 | struct SteamInterface 21 | { 22 | static void Acquire(); 23 | static void Release(); 24 | }; 25 | 26 | using ConnectionId = HSteamNetConnection; 27 | 28 | -------------------------------------------------------------------------------- /code/common/Network/SynchronizedClock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | struct SynchronizedClock 7 | { 8 | SynchronizedClock() noexcept; 9 | [[nodiscard]] uint64_t GetCurrentTick() const noexcept; 10 | [[nodiscard]] bool IsSynchronized() const noexcept; 11 | void Synchronize(uint64_t aServerTick, uint32_t aPing) noexcept; 12 | void Reset() noexcept; 13 | void Update() noexcept; 14 | 15 | private: 16 | 17 | uint64_t m_lastServerTick; 18 | uint64_t m_simulatedTick; 19 | std::chrono::nanoseconds m_previousSimulatedTick; 20 | std::chrono::nanoseconds m_tickDelta; 21 | std::chrono::time_point m_lastSynchronizationTime{}; 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /code/common/Reverse/App.cpp: -------------------------------------------------------------------------------- 1 | #include "App.h" 2 | #include "Memory.h" 3 | #include 4 | 5 | 6 | App::App() noexcept 7 | : m_ready(false) 8 | { 9 | } 10 | 11 | App::~App() = default; 12 | 13 | void App::Start() noexcept 14 | { 15 | m_ready = true; 16 | 17 | BeginMain(); 18 | } 19 | 20 | bool App::IsReady() const noexcept 21 | { 22 | return m_ready; 23 | } 24 | -------------------------------------------------------------------------------- /code/common/Reverse/App.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct App 4 | { 5 | App() noexcept; 6 | virtual ~App(); 7 | 8 | // Retrieve the program's main address, if null is returned the main function will not be hooked 9 | [[nodiscard]] virtual void* GetMainAddress() const = 0; 10 | 11 | // Called right before the program's main function is called 12 | virtual bool BeginMain() = 0; 13 | 14 | // Called after the program's main function exits 15 | virtual bool EndMain() = 0; 16 | 17 | // Called when the dll is attached, before anything else 18 | virtual bool Attach() = 0; 19 | 20 | // Called when the dll is detached 21 | virtual bool Detach() = 0; 22 | 23 | // Must be called once per frame 24 | virtual void Update() = 0; 25 | 26 | void Start() noexcept; 27 | 28 | // Functions that can be called by class users 29 | [[nodiscard]] bool IsReady() const noexcept; 30 | 31 | 32 | static App& GetInstance() noexcept; 33 | 34 | private: 35 | 36 | bool m_ready; 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /code/common/Reverse/AutoPtr.cpp: -------------------------------------------------------------------------------- 1 | #include "AutoPtr.h" 2 | #include "AutoPtrManager.h" 3 | 4 | #include 5 | 6 | 7 | BasicAutoPtr::BasicAutoPtr(Pattern aPattern) noexcept 8 | { 9 | m_pPtr = AutoPtrManager::GetInstance().Find(std::move(aPattern)); 10 | 11 | assert(m_pPtr != nullptr); 12 | } 13 | 14 | BasicAutoPtr::BasicAutoPtr(const uintptr_t aAddress) noexcept 15 | { 16 | m_pPtr = reinterpret_cast(aAddress + AutoPtrManager::GetInstance().GetBaseAddress()); 17 | } 18 | 19 | void* BasicAutoPtr::GetPtr() const noexcept 20 | { 21 | return m_pPtr; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /code/common/Reverse/AutoPtr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Pattern.h" 4 | 5 | 6 | struct BasicAutoPtr 7 | { 8 | explicit BasicAutoPtr(Pattern aPattern) noexcept; 9 | explicit BasicAutoPtr(uintptr_t aAddress) noexcept; 10 | 11 | BasicAutoPtr() = delete; 12 | BasicAutoPtr(BasicAutoPtr&) = delete; 13 | BasicAutoPtr& operator=(BasicAutoPtr&) = delete; 14 | 15 | [[nodiscard]] void* GetPtr() const noexcept; 16 | 17 | private: 18 | 19 | void* m_pPtr; 20 | }; 21 | 22 | template 23 | struct AutoPtr : BasicAutoPtr 24 | { 25 | explicit AutoPtr(Pattern aPattren) noexcept : BasicAutoPtr(std::move(aPattren)) {} 26 | explicit AutoPtr(const uintptr_t aAddress) noexcept : BasicAutoPtr(aAddress) {} 27 | 28 | AutoPtr() = delete; 29 | AutoPtr(AutoPtr&) = delete; 30 | AutoPtr& operator=(AutoPtr&) = delete; 31 | 32 | operator T* () const noexcept { return Get(); } 33 | T* operator->() const noexcept { return Get(); } 34 | 35 | T* Get() const noexcept { return static_cast(GetPtr()); } 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /code/common/Reverse/AutoPtrManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Pattern.h" 5 | 6 | 7 | struct AutoPtrManager 8 | { 9 | TP_NOCOPYMOVE(AutoPtrManager); 10 | 11 | [[nodiscard]] uintptr_t GetBaseAddress() const noexcept; 12 | [[nodiscard]] void* Find(Pattern aPattern) const noexcept; 13 | 14 | static AutoPtrManager& GetInstance() noexcept 15 | { 16 | return s_instance; 17 | } 18 | 19 | private: 20 | 21 | AutoPtrManager() noexcept; 22 | ~AutoPtrManager() noexcept; 23 | 24 | uintptr_t m_baseAddress; 25 | uintptr_t m_textStartAddress; 26 | size_t m_textSize; 27 | uint64_t m_textHash; 28 | 29 | static AutoPtrManager s_instance; 30 | }; 31 | -------------------------------------------------------------------------------- /code/common/Reverse/Debug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Debug 4 | { 5 | static void WaitForDebugger() noexcept; 6 | static void CreateConsole() noexcept; 7 | static void OnAttach() noexcept; 8 | static void OnDetach() noexcept; 9 | }; 10 | 11 | -------------------------------------------------------------------------------- /code/common/Reverse/Entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | struct App; 8 | 9 | namespace details 10 | { 11 | BOOL ReverseMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved, const std::function()>& aAppFactory) noexcept; 12 | } 13 | 14 | template 15 | BOOL CreateReverseApp(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) noexcept 16 | { 17 | static_assert(std::is_base_of_v); 18 | 19 | return details::ReverseMain(hModule, fdwReason, lpReserved, []() { return std::make_unique(); }); 20 | } 21 | 22 | 23 | #define DEFINE_DLL_ENTRY_INITIALIZER(className) \ 24 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) \ 25 | { \ 26 | return TiltedPhoques::CreateReverseApp(hModule, fdwReason, lpReserved); \ 27 | } 28 | -------------------------------------------------------------------------------- /code/common/Reverse/JitAssembly.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef REVERSE_ALLOC_STUB 4 | #define REVERSE_ALLOC_STUB(x) malloc(x) 5 | #endif 6 | 7 | #include 8 | 9 | 10 | { 11 | // Wraps the generator in a core stub page. 12 | struct CodeGenerator : Xbyak::CodeGenerator 13 | { 14 | // Warning(Force): Ensure those are exponents of 2. 15 | static constexpr size_t kDefaultAllocStubsize = 64; 16 | 17 | CodeGenerator(const size_t aAllocSize = kDefaultAllocStubsize) : 18 | Xbyak::CodeGenerator(aAllocSize, REVERSE_ALLOC_STUB(aAllocSize)){} 19 | 20 | void jmp_S(const mem::pointer acEa) { 21 | Xbyak::CodeGenerator::jmp(acEa.as()); 22 | } 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /code/common/Reverse/MemoryVP.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | class ScopedContext 9 | { 10 | public: 11 | inline ScopedContext(const mem::pointer aEa, size_t aSize) noexcept; 12 | inline ~ScopedContext(); 13 | 14 | template 15 | bool Write(const T& acData, const size_t aOffset = 0) const noexcept 16 | { 17 | return WriteBuffer(reinterpret_cast(&acData), sizeof(T), aOffset); 18 | } 19 | 20 | inline bool WriteBuffer(const uint8_t* acpData, size_t aSize, size_t aOffset) const noexcept; 21 | 22 | private: 23 | size_t m_size; 24 | uint32_t m_oldProtect; 25 | mem::pointer m_ea; 26 | }; 27 | 28 | 29 | #if TP_PLATFORM_WINDOWS 30 | #include "Memory_Win.inl" 31 | #endif 32 | // TODO: maybe Linux? 33 | -------------------------------------------------------------------------------- /code/common/Reverse/Memory_Win.inl: -------------------------------------------------------------------------------- 1 | ScopedContext::ScopedContext(const mem::pointer aEa, const size_t aSize) noexcept 2 | : m_oldProtect(0) 3 | , m_ea(aEa) 4 | , m_size(aSize) 5 | { 6 | VirtualProtect(aEa.as(), m_size, PAGE_EXECUTE_READWRITE, reinterpret_cast(&m_oldProtect)); 7 | } 8 | 9 | ScopedContext::~ScopedContext() 10 | { 11 | VirtualProtect(m_ea.as(), m_size, m_oldProtect, reinterpret_cast(&m_oldProtect)); 12 | } 13 | 14 | bool ScopedContext::WriteBuffer(const uint8_t* acpData, const size_t aSize, const size_t aOffset) const noexcept 15 | { 16 | if (aSize + aOffset > m_size) 17 | return false; 18 | 19 | auto memory = m_ea + aOffset; 20 | std::copy(acpData, acpData + aSize, memory.as()); 21 | 22 | return true; 23 | } -------------------------------------------------------------------------------- /code/common/Reverse/Pattern.cpp: -------------------------------------------------------------------------------- 1 | #include "Pattern.h" 2 | 3 | 4 | Pattern::Pattern(Vector aBytePattern, const size_t aExpected, const EType aPatternType, const intptr_t aOffset /* = 0 */, const size_t aIndex /* = 0 */) noexcept 5 | : BytePattern(std::move(aBytePattern)) 6 | , Expected(aExpected) 7 | , Type(aPatternType) 8 | , Offset(aOffset) 9 | , Index(aIndex) 10 | { 11 | } 12 | 13 | -------------------------------------------------------------------------------- /code/common/Reverse/Pattern.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | 6 | struct Pattern 7 | { 8 | enum EType 9 | { 10 | kRelativeIndirection4, 11 | kDirect 12 | }; 13 | 14 | Pattern(Vector aBytePattern, size_t aExpected, EType aPatternType, intptr_t aOffset = 0, size_t aIndex = 0) noexcept; 15 | 16 | Vector BytePattern; 17 | size_t Expected; 18 | EType Type; 19 | intptr_t Offset{ 0 }; 20 | size_t Index{ 0 }; 21 | }; 22 | 23 | 24 | namespace std 25 | { 26 | template<> struct less 27 | { 28 | bool operator() (const Pattern& lhs, const Pattern& rhs) const noexcept 29 | { 30 | return lhs.BytePattern < rhs.BytePattern; 31 | } 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /code/common/System/Log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Core/Stl.h" 3 | 4 | struct Path; 5 | 6 | struct Log 7 | { 8 | Log(Path& aPath); 9 | ~Log(); 10 | 11 | std::shared_ptr Create( 12 | const String& aName, spdlog::sink_ptr aExtraSink = nullptr, const String& aPattern = "[%Y-%m-%d %H:%M:%S UTC%z] [%^%l%$] [%n] %v"); 13 | 14 | private: 15 | std::filesystem::path m_logRoot; 16 | }; 17 | -------------------------------------------------------------------------------- /code/common/System/Path.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Path 4 | { 5 | Path(); 6 | const std::filesystem::path GetRoot() const; 7 | const std::filesystem::path GetModsRoot() const; 8 | 9 | private: 10 | std::filesystem::path m_root; 11 | std::filesystem::path m_mods; 12 | }; 13 | 14 | std::filesystem::path GetAbsolutePath(std::filesystem::path aFilePath, const std::filesystem::path& acRootPath, const bool acAllowNonExisting, const bool acAllowSymlink); 15 | -------------------------------------------------------------------------------- /code/common/Tests/main.cpp: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | return 0; 4 | } -------------------------------------------------------------------------------- /code/common/xmake.lua: -------------------------------------------------------------------------------- 1 | add_requires("hopscotch-map", "snappy", "gamenetworkingsockets", "catch2 2.13.9", "libuv", "openssl", "spdlog") 2 | add_requireconfs("*.protobuf*", { build = true }) 3 | add_requireconfs("mimalloc", {configs = {rltgenrandom = true}}) 4 | 5 | if is_plat("windows") then 6 | add_requires("minhook", "mem", "xbyak") 7 | end 8 | 9 | target("Common") 10 | set_kind("static") 11 | add_files("**.cpp") 12 | remove_files("Tests/**") 13 | set_group("Libraries") 14 | add_headerfiles("**.h", "**.hpp", "**.inl") 15 | 16 | set_pcxxheader("CommonPCH.h") 17 | add_includedirs(".", {public = true}) 18 | add_includedirs( 19 | "../../build", 20 | "../../vendor" 21 | ) 22 | 23 | add_packages("hopscotch-map", "snappy", "gamenetworkingsockets", "libuv") 24 | if is_plat("windows") then 25 | add_packages("minhook", "mem", "xbyak") 26 | else 27 | remove_files("Reverse/**") 28 | end 29 | 30 | add_cxflags("-fPIC") 31 | add_defines("STEAMNETWORKINGSOCKETS_STATIC_LINK") 32 | 33 | add_packages( 34 | "spdlog", 35 | "glm", 36 | "hopscotch-map", 37 | "mimalloc", 38 | "gamenetworkingsockets", 39 | "snappy", 40 | "openssl", 41 | "libuv") 42 | -------------------------------------------------------------------------------- /code/launcher/.env: -------------------------------------------------------------------------------- 1 | VITE_CJS_TRACE=true 2 | -------------------------------------------------------------------------------- /code/launcher/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | electron/dist 12 | electron/out 13 | dist-ssr 14 | *.local 15 | 16 | # Editor directories and files 17 | .vscode/* 18 | !.vscode/extensions.json 19 | .idea 20 | .DS_Store 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw? 26 | -------------------------------------------------------------------------------- /code/launcher/electron/.gitignore: -------------------------------------------------------------------------------- 1 | mod/** -------------------------------------------------------------------------------- /code/launcher/electron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CyberpunkMP", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "start:electron": "cross-env ELECTRON_DEV=1 ow-electron .", 10 | "build:electron": "ow-electron-builder --publish=never" 11 | }, 12 | "author": { 13 | "name": "Tilted Phoques SRL" 14 | }, 15 | "productName": "CyberpunkMP", 16 | "build": { 17 | "productName": "CyberpunkMP", 18 | "includeSubNodeModules": "true", 19 | "directories": { 20 | "output": "out" 21 | }, 22 | "extraFiles": [ 23 | "./dist/**", 24 | "./preload.mjs" 25 | ], 26 | "files": [ 27 | "./dist/**/*", 28 | "./app.js", 29 | "./preload.mjs" 30 | ], 31 | "extraResources": [ 32 | "./preload.mjs" 33 | ] 34 | }, 35 | "private": true, 36 | "devDependencies": { 37 | "@overwolf/ow-electron": "^31.7.3", 38 | "@overwolf/ow-electron-builder": "^25.0.6", 39 | "electron-devtools-installer": "^3.2.0", 40 | "react-devtools": "^6.0.1" 41 | }, 42 | "dependencies": { 43 | "decompress": "^4.2.1", 44 | "electron-store": "^10.0.0", 45 | "readable-stream": "^4.5.2" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /code/launcher/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cyberpunk Multiplayer 8 | 9 | 10 |
11 | <%- devtools %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /code/launcher/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /code/launcher/src/components/Owadview.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties, useEffect, useRef } from 'react' 2 | 3 | interface Props { 4 | style?: CSSProperties 5 | } 6 | 7 | export default function Owadview (props: Props) { 8 | const adviewDivRef = useRef(null) 9 | 10 | useEffect(() => { 11 | const adviewElement = document.createElement('owadview') 12 | adviewDivRef.current?.appendChild(adviewElement) 13 | }) 14 | 15 | return
16 | } 17 | -------------------------------------------------------------------------------- /code/launcher/src/data/ModData.ts: -------------------------------------------------------------------------------- 1 | export default interface ModData { 2 | name: string, 3 | hash: string, 4 | downloadUrl: string 5 | } 6 | -------------------------------------------------------------------------------- /code/launcher/src/data/ServerData.ts: -------------------------------------------------------------------------------- 1 | export default interface ServerData { 2 | name: string 3 | players: string 4 | tags: string 5 | ip: string 6 | _ip: string 7 | _port: string 8 | version: string 9 | favorite: number, 10 | modsEndpoint: string 11 | } 12 | -------------------------------------------------------------------------------- /code/launcher/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | margin: 0; 7 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 8 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 9 | sans-serif; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | } 13 | 14 | code { 15 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 16 | monospace; 17 | } 18 | 19 | .textContainer { 20 | display: block; 21 | white-space: nowrap; 22 | overflow: hidden; 23 | text-overflow: ellipsis; 24 | } 25 | 26 | /* width */ 27 | ::-webkit-scrollbar { 28 | margin-right: 5px; 29 | width: 10px; 30 | } 31 | 32 | /* Track */ 33 | ::-webkit-scrollbar-track { 34 | box-shadow: inset 0 0 5px grey; 35 | border-radius: 10px; 36 | } 37 | 38 | /* Handle */ 39 | ::-webkit-scrollbar-thumb { 40 | background: gray; 41 | border-radius: 5px; 42 | } -------------------------------------------------------------------------------- /code/launcher/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | import '@fontsource/roboto/300.css' 7 | import '@fontsource/roboto/400.css' 8 | import '@fontsource/roboto/500.css' 9 | import '@fontsource/roboto/700.css' 10 | 11 | ReactDOM.createRoot(document.getElementById('root')!).render( 12 | 13 | 14 | 15 | ) 16 | -------------------------------------------------------------------------------- /code/launcher/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | electronAPI: any 3 | } 4 | -------------------------------------------------------------------------------- /code/launcher/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import.meta.env.DEV = true 3 | -------------------------------------------------------------------------------- /code/launcher/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | export default { 2 | content: [ 3 | './index.html', 4 | './src/**/*.{js,ts,jsx,tsx}' 5 | ], 6 | theme: { 7 | extend: {} 8 | }, 9 | plugins: [] 10 | } 11 | -------------------------------------------------------------------------------- /code/launcher/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "allowSyntheticDefaultImports": true 23 | }, 24 | "include": ["src"], 25 | "references": [{ "path": "./tsconfig.node.json" }] 26 | } 27 | -------------------------------------------------------------------------------- /code/launcher/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /code/launcher/vite.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { createHtmlPlugin } from 'vite-plugin-html' 3 | 4 | export default defineConfig({ 5 | build: { 6 | outDir: './electron/dist', 7 | rollupOptions: { 8 | // Hides MUI warning 9 | onwarn (warning, warn) { 10 | if (warning.code === 'MODULE_LEVEL_DIRECTIVE') { 11 | return 12 | } 13 | warn(warning) 14 | } 15 | } 16 | }, 17 | base: './', 18 | plugins: [ 19 | createHtmlPlugin({ 20 | minify: true, 21 | entry: 'src/main.tsx', 22 | inject: { 23 | data: { 24 | devtools: process.env.NODE_ENV === 'development' ? '' : '' 25 | } 26 | } 27 | }) 28 | ] 29 | }) 30 | -------------------------------------------------------------------------------- /code/netpack/ErrorHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "ErrorHandler.h" 2 | 3 | void ErrorHandler::RecordError(absl::string_view filename, int line, int column, absl::string_view message) 4 | { 5 | std::string fullPath(filename.data(), filename.size()); 6 | #if TP_PLATFORM_WINDOWS 7 | std::ranges::replace(fullPath, '/', '\\'); 8 | #endif 9 | 10 | fullPath = (std::filesystem::current_path() / fullPath).string(); 11 | throw std::runtime_error(fmt::format("{}({},{}): error 0: {}\n", fullPath, line, column, message)); 12 | } 13 | -------------------------------------------------------------------------------- /code/netpack/ErrorHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct ErrorHandler : google::protobuf::compiler::MultiFileErrorCollector 4 | { 5 | void RecordError(absl::string_view filename, int line, int column, absl::string_view message) override; 6 | }; -------------------------------------------------------------------------------- /code/netpack/Indent.cpp: -------------------------------------------------------------------------------- 1 | #include "Indent.h" 2 | 3 | 4 | Indent::Indent(std::streambuf* dest, int indent) 5 | : m_dest{dest} 6 | , m_indent(indent, ' ') 7 | { 8 | } 9 | 10 | Indent::Indent(std::ostream& dest, int indent) 11 | : m_dest{dest.rdbuf()} 12 | , m_indent(indent, ' ') 13 | , m_owner{&dest} 14 | { 15 | m_owner->rdbuf(this); 16 | } 17 | Indent ::~Indent() 18 | { 19 | if (m_owner != nullptr) 20 | { 21 | m_owner->rdbuf(m_dest); 22 | } 23 | } 24 | 25 | int Indent::overflow(int ch) 26 | { 27 | if (m_is_at_start_of_line && ch != '\n') 28 | { 29 | m_dest->sputn(m_indent.data(), m_indent.size()); 30 | } 31 | m_is_at_start_of_line = ch == '\n'; 32 | return m_dest->sputc(ch); 33 | } 34 | -------------------------------------------------------------------------------- /code/netpack/Indent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Indent : std::streambuf 4 | { 5 | explicit Indent(std::streambuf* dest, int indent = 4); 6 | explicit Indent(std::ostream& dest, int indent = 4); 7 | ~Indent() override; 8 | 9 | protected: 10 | int overflow(int ch) override; 11 | 12 | private: 13 | std::streambuf* m_dest{}; 14 | bool m_is_at_start_of_line{true}; 15 | std::string m_indent{}; 16 | std::ostream* m_owner{}; 17 | }; 18 | -------------------------------------------------------------------------------- /code/netpack/NetPackPCH.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include -------------------------------------------------------------------------------- /code/netpack/xmake.lua: -------------------------------------------------------------------------------- 1 | add_requires("cxxopts") 2 | 3 | target("NetPack") 4 | set_kind("binary") 5 | add_files("**.cpp", "**.cc") 6 | set_group("Tools") 7 | add_headerfiles("**.h", "**.hpp", "**.inl") 8 | set_policy("build.across_targets_in_parallel", false) 9 | 10 | set_pcxxheader("NetPackPCH.h") 11 | add_includedirs( 12 | ".", 13 | "../../build", 14 | "../../vendor" 15 | ) 16 | 17 | add_deps("Common") 18 | 19 | add_packages( 20 | "mimalloc", 21 | "spdlog", 22 | "hopscotch-map", 23 | "cxxopts", 24 | "protobuf-cpp") -------------------------------------------------------------------------------- /code/protocol/Protocol.cpp: -------------------------------------------------------------------------------- 1 | #include "ProtocolPCH.h" -------------------------------------------------------------------------------- /code/protocol/ProtocolPCH.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | template 11 | struct PacketEvent : T 12 | { 13 | using Type = T; 14 | 15 | uint32_t ConnectionId{0}; 16 | }; -------------------------------------------------------------------------------- /code/protocol/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package common; 4 | 5 | message Vector3 { 6 | float x = 1; 7 | float y = 2; 8 | float z = 3; 9 | } -------------------------------------------------------------------------------- /code/protocol/xmake.lua: -------------------------------------------------------------------------------- 1 | target("Protocol") 2 | set_kind("static") 3 | set_group("Libraries") 4 | add_rules("codegen") 5 | add_files("**.cpp") 6 | add_files("**.proto") 7 | add_extrafiles("**.proto") 8 | add_headerfiles("**.h", "**.hpp", "**.inl") 9 | set_policy("build.across_targets_in_parallel", false) 10 | 11 | set_pcxxheader("ProtocolPCH.h") 12 | add_includedirs(".", {public = true}) 13 | add_includedirs( 14 | "../../build", 15 | "../../vendor" 16 | ) 17 | add_deps("Common") 18 | 19 | add_packages( 20 | "mimalloc", 21 | "spdlog", 22 | "hopscotch-map", 23 | "glm", 24 | "flecs", 25 | "entt") -------------------------------------------------------------------------------- /code/server/admin/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /code/server/admin/globals.d.ts: -------------------------------------------------------------------------------- 1 | import {useToasts} from "./src/Stores/ToastStore.ts"; 2 | 3 | declare global { 4 | interface Window { 5 | Redux: typeof import('react-redux'); 6 | MUI: typeof import('@mui/material'); 7 | MUIIcons: typeof import('@mui/icons-material'); 8 | MDI: typeof import('@mdi/react'); 9 | MDIIcons: typeof import('@mdi/js'); 10 | StatusCodes: typeof import('http-status-codes'); 11 | App: { 12 | useToasts: typeof useToasts; 13 | } 14 | } 15 | } 16 | 17 | export {}; 18 | -------------------------------------------------------------------------------- /code/server/admin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | CyberpunkMP · Admin Panel 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /code/server/admin/src/Components/Toast/ToastProvider.tsx: -------------------------------------------------------------------------------- 1 | import {Alert, Snackbar} from "@mui/material"; 2 | import {useEffect, useState} from "react"; 3 | import {useAppDispatch, useAppSelector} from "../../Stores/AppStore.ts"; 4 | import {closeToast, ToastState} from "../../Stores/ToastStore.ts"; 5 | import {Toast} from "../../Data/ToastData.ts"; 6 | 7 | export default function ToastProvider() { 8 | const state: ToastState = useAppSelector(state => state.toast); 9 | const dispatch = useAppDispatch(); 10 | const [show, setShow] = useState(false); 11 | const [toast, setToast] = useState({message: '', duration: 4000}); 12 | 13 | useEffect(() => { 14 | if (!state.toast) { 15 | return; 16 | } 17 | setToast(state.toast); 18 | setShow(true); 19 | }, [state]); 20 | 21 | const handleClose = () => { 22 | setShow(false); 23 | // NOTE: wait for animation to finish. 24 | setTimeout(() => { 25 | dispatch(closeToast()); 26 | }, 500); 27 | }; 28 | 29 | return ( 30 | 34 | 37 | {toast.message} 38 | 39 | 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /code/server/admin/src/Components/Toolbar/ThemeSwitch.tsx: -------------------------------------------------------------------------------- 1 | import Box from "@mui/material/Box"; 2 | import {Tooltip, useColorScheme} from "@mui/material"; 3 | import IconButton from "@mui/material/IconButton"; 4 | import {AutoMode, DarkMode, LightMode} from "@mui/icons-material"; 5 | 6 | export default function ThemeSwitch() { 7 | const {mode, setMode} = useColorScheme(); 8 | 9 | const updateMode = () => { 10 | let newMode: 'light' | 'dark' | 'system' | null = null; 11 | 12 | if (mode === 'light') { 13 | newMode = 'dark'; 14 | } else if (mode === 'dark') { 15 | newMode = 'system'; 16 | } else if (mode === 'system') { 17 | newMode = 'light'; 18 | } 19 | setMode(newMode); 20 | } 21 | 22 | return ( 23 | 24 | 25 | 26 | {mode === 'light' && } 27 | {mode === 'dark' && } 28 | {mode === 'system' && } 29 | 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /code/server/admin/src/Components/Toolbar/Toolbar.tsx: -------------------------------------------------------------------------------- 1 | import MUIToolbar from "@mui/material/Toolbar"; 2 | import Box from "@mui/material/Box"; 3 | import IconButton from "@mui/material/IconButton"; 4 | import MenuIcon from "@mui/icons-material/Menu"; 5 | import Typography from "@mui/material/Typography"; 6 | import ThemeSwitch from "./ThemeSwitch.tsx"; 7 | import {ToolbarProps} from "../../App.tsx"; 8 | 9 | export default function Toolbar({open, onOpenDrawer}: ToolbarProps) { 10 | return ( 11 | 12 | 13 | 25 | 26 | 27 | 28 | 29 | CyberpunkMP · Admin Panel 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /code/server/admin/src/Data/PluginData.ts: -------------------------------------------------------------------------------- 1 | import {Layout} from "react-grid-layout"; 2 | import {FunctionComponent} from "react"; 3 | 4 | export interface PluginDto { 5 | readonly Name: string; 6 | } 7 | 8 | export interface PluginManifest { 9 | name: string; 10 | url: string; 11 | author: string; 12 | version: string; 13 | } 14 | 15 | /* 16 | export interface PluginSettings { 17 | [key: string]: any; 18 | } 19 | */ 20 | 21 | export interface PluginWidget { 22 | component: FunctionComponent; 23 | layout: Partial; 24 | } 25 | 26 | export type PluginPage = unknown 27 | 28 | export interface PluginModule { 29 | updatedAt?: string; 30 | manifest: PluginManifest; 31 | //settings?: PluginSettings; 32 | widget?: PluginWidget; 33 | page?: PluginPage; 34 | } 35 | -------------------------------------------------------------------------------- /code/server/admin/src/Data/ToastData.ts: -------------------------------------------------------------------------------- 1 | export type ToastStyle = 'info' | 'success' | 'warning' | 'error'; 2 | 3 | export type ShowToastCallback = (toast: Toast) => void; 4 | 5 | export interface Toast { 6 | message: string; 7 | style?: ToastStyle; 8 | duration?: number; 9 | onClosed?: () => void; 10 | } 11 | 12 | export function equalsToast(a?: Toast, b?: Toast): boolean { 13 | return a?.style === b?.style && 14 | a?.duration === b?.duration && 15 | a?.message === b?.message && 16 | a?.onClosed === b?.onClosed; 17 | } 18 | -------------------------------------------------------------------------------- /code/server/admin/src/Pages/About/About.tsx: -------------------------------------------------------------------------------- 1 | import Box from "@mui/material/Box"; 2 | import {Card} from "@mui/material"; 3 | import Typography from "@mui/material/Typography"; 4 | import {Link} from "react-router"; 5 | 6 | export default function About() { 7 | return ( 8 | 9 | 10 | 11 | About 12 | 13 | 14 | 15 | This webapp is part of the 16 | CyberpunkMP framework by 17 | Tilted Phoques. This web application 18 | is licensed under the MIT License, granting users freedom to use, modify, and distribute this software. 19 | 20 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /code/server/admin/src/Pages/Settings/Settings.tsx: -------------------------------------------------------------------------------- 1 | import Box from "@mui/material/Box"; 2 | import {Alert} from "@mui/material"; 3 | 4 | export default function Settings() { 5 | return ( 6 | 7 | Work in progress 8 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /code/server/admin/src/Stores/AppStore.ts: -------------------------------------------------------------------------------- 1 | import {configureStore} from "@reduxjs/toolkit"; 2 | import {useDispatch, useSelector} from "react-redux"; 3 | import pluginReducer from './PluginStore'; 4 | import toastReducer from './ToastStore'; 5 | import storageReducer from './StorageStore'; 6 | 7 | const store = configureStore({ 8 | middleware: (getDefaultMiddleware) => 9 | getDefaultMiddleware({ 10 | serializableCheck: { 11 | ignoredActions: [ 12 | 'plugin/loadPlugins', 'plugin/updatePlugin', 13 | ], 14 | ignoredPaths: ['plugin.plugins'], 15 | }, 16 | }), 17 | reducer: { 18 | plugin: pluginReducer, 19 | toast: toastReducer, 20 | storage: storageReducer, 21 | }, 22 | }); 23 | 24 | export default store; 25 | 26 | export type AppStore = ReturnType; 27 | export type AppDispatch = typeof store.dispatch; 28 | 29 | export const useAppDispatch = useDispatch.withTypes(); 30 | export const useAppSelector = useSelector.withTypes(); 31 | -------------------------------------------------------------------------------- /code/server/admin/src/Stores/PluginStore.ts: -------------------------------------------------------------------------------- 1 | import {createSlice, PayloadAction} from "@reduxjs/toolkit"; 2 | import {PluginModule} from "../Data/PluginData.ts"; 3 | 4 | interface PluginState { 5 | isLoaded: boolean; 6 | plugins: PluginModule[]; 7 | } 8 | 9 | const initialState: PluginState = { 10 | isLoaded: false, 11 | plugins: [], 12 | }; 13 | 14 | function sortPlugins(a: PluginModule, b: PluginModule): number { 15 | return a.manifest.name.localeCompare(b.manifest.name); 16 | } 17 | 18 | export const pluginSlice = createSlice({ 19 | name: 'plugin', 20 | initialState, 21 | reducers: { 22 | loadPlugins: (_state, action: PayloadAction) => { 23 | return { 24 | plugins: action.payload.sort(sortPlugins), 25 | isLoaded: true, 26 | } 27 | }, 28 | updatePlugin: (state, action: PayloadAction) => { 29 | const plugin: PluginModule = action.payload; 30 | const plugins: PluginModule[] = state.plugins.filter(item => item.manifest.name !== plugin.manifest.name); 31 | 32 | return { 33 | plugins: [...plugins, plugin].sort(sortPlugins), 34 | isLoaded: state.isLoaded 35 | } 36 | }, 37 | } 38 | }); 39 | 40 | export const {loadPlugins, updatePlugin} = pluginSlice.actions; 41 | export default pluginSlice.reducer; 42 | -------------------------------------------------------------------------------- /code/server/admin/src/Theme.ts: -------------------------------------------------------------------------------- 1 | import {createTheme} from "@mui/material"; 2 | import {blue, orange} from "@mui/material/colors"; 3 | 4 | export const theme = createTheme({ 5 | cssVariables: { 6 | colorSchemeSelector: 'class' 7 | }, 8 | colorSchemes: { 9 | light: { 10 | palette: { 11 | primary: blue, 12 | secondary: orange, 13 | }, 14 | }, 15 | dark: { 16 | palette: { 17 | primary: blue, 18 | secondary: orange, 19 | }, 20 | }, 21 | }, 22 | components: { 23 | MuiCard: { 24 | styleOverrides: { 25 | root: { 26 | padding: '24px' 27 | } 28 | }, 29 | }, 30 | }, 31 | }); 32 | -------------------------------------------------------------------------------- /code/server/admin/src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | width: 100%; 5 | height: 100%; 6 | margin: 0; 7 | padding: 0; 8 | 9 | font-family: Roboto, Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 10 | } 11 | 12 | a { 13 | text-decoration: none; 14 | } 15 | 16 | .page { 17 | display: flex; 18 | flex-flow: column; 19 | } 20 | 21 | .page.center { 22 | justify-content: center; 23 | width: 100%; 24 | height: 100%; 25 | } 26 | -------------------------------------------------------------------------------- /code/server/admin/src/main.tsx: -------------------------------------------------------------------------------- 1 | import 'systemjs'; 2 | import React, {StrictMode} from 'react'; 3 | import {BrowserRouter} from "react-router"; 4 | import {createRoot} from 'react-dom/client'; 5 | import * as MUI from '@mui/material'; 6 | import * as MUIIcons from '@mui/icons-material'; 7 | import * as MDI from '@mdi/react'; 8 | import * as MDIIcons from '@mdi/js'; 9 | import * as Redux from "react-redux"; 10 | import * as StatusCodes from "http-status-codes"; 11 | import {Provider} from "react-redux"; 12 | import './index.css'; 13 | import '../node_modules/react-grid-layout/css/styles.css'; 14 | import '../node_modules/react-resizable/css/styles.css'; 15 | import App from './App.tsx'; 16 | import store from './Stores/AppStore'; 17 | import {useToasts} from "./Stores/ToastStore.ts"; 18 | 19 | // NOTE: declare external dependencies globally for plugins. 20 | window.React = React; 21 | window.Redux = Redux; 22 | window.MUI = MUI; 23 | window.MUIIcons = MUIIcons; 24 | window.MDI = MDI; 25 | window.MDIIcons = MDIIcons; 26 | window.StatusCodes = StatusCodes; 27 | window.App = { 28 | useToasts: useToasts 29 | }; 30 | window.StatusCodes = StatusCodes; 31 | 32 | createRoot(document.getElementById('root')!).render( 33 | 34 | 35 | 36 | 37 | 38 | 39 | , 40 | ); 41 | -------------------------------------------------------------------------------- /code/server/admin/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /code/server/admin/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 | "target": "ES2020", 5 | "useDefineForClassFields": true, 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "module": "ESNext", 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "isolatedModules": true, 14 | "moduleDetection": "force", 15 | "noEmit": true, 16 | "jsx": "react-jsx", 17 | 18 | /* Linting */ 19 | "strict": true, 20 | "noUnusedLocals": true, 21 | "noUnusedParameters": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noUncheckedSideEffectImports": true 24 | }, 25 | "include": [ 26 | "src", 27 | "globals.d.ts" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /code/server/admin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /code/server/admin/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /code/server/admin/vite.config.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vite.dev/config/ 5 | export default defineConfig({ 6 | plugins: [ 7 | react() 8 | ], 9 | build: { 10 | rollupOptions: { 11 | output: { 12 | manualChunks: { 13 | 'vendor-0': ['systemjs'], 14 | 'vendor-1': [ 15 | 'react', 'react-dom', 'react-error-boundary', 'react-router', 16 | 'react-redux', 'react-grid-layout', 'react-resizable' 17 | ], 18 | 'vendor-2': ['@emotion/react', '@emotion/styled'], 19 | 'vendor-3-0': ['@mui/material'], 20 | 'vendor-3-1': ['@mui/icons-material'], 21 | 'vendor-3-2': ['@mdi/react'], 22 | 'vendor-3-3': ['@mdi/js'], 23 | 'vendor-4': ['http-status-codes'], 24 | } 25 | } 26 | } 27 | }, 28 | server: { 29 | proxy: { 30 | '/api': 'http://localhost:11778' 31 | }, 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /code/server/admin/watcher.js: -------------------------------------------------------------------------------- 1 | // NOTE: common script for plugins when implementing a widget in Admin/. 2 | // run `pnpm build:watch` to watch changes, build widget, copy output in 3 | // debug directory of the plugin. You'll need to hit F5 to reload the 4 | // widget when running `pnpm start` in `code/server/admin`. 5 | import chokidar from 'chokidar'; 6 | import fs from 'fs'; 7 | import path from 'path'; 8 | 9 | const plugin = path.basename(path.dirname(process.cwd())); 10 | const src = path.resolve(path.join(process.cwd(), 'dist')); 11 | const dst = path.resolve(path.join('..', '..', '..', '..', '..', 'build', 'windows', 'x64', 'debug', 'plugins', plugin, 'assets')); 12 | 13 | console.log(`watching Admin.${plugin}`); 14 | console.log(`copying from "${src}"`); 15 | console.log(` to "${dst}"`); 16 | 17 | const watcher = chokidar.watch('./dist'); 18 | 19 | process.once('SIGINT', abort); 20 | process.once('SIGTERM', abort); 21 | 22 | watcher.on('all', () => { 23 | fs.cpSync(src, dst, {recursive: true}); 24 | }); 25 | 26 | function abort() { 27 | console.log('Stopping watcher...'); 28 | watcher.close(); 29 | } 30 | -------------------------------------------------------------------------------- /code/server/loader/.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | bin/ 3 | obj/ 4 | CyberpunkMp.cs 5 | CyberpunkMp-symbols.cpp 6 | Std.cs -------------------------------------------------------------------------------- /code/server/loader/EnvironmentHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Server.Loader; 2 | 3 | public static class EnvironmentHelper 4 | { 5 | #if DEBUG 6 | public const bool IsDebug = true; 7 | public const bool IsRelease = false; 8 | #else 9 | public const bool IsDebug = false; 10 | public const bool IsRelease = true; 11 | #endif 12 | } -------------------------------------------------------------------------------- /code/server/loader/Extensions/EmbedIO.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using System.Reflection; 3 | using CyberpunkSdk; 4 | using EmbedIO.WebApi; 5 | 6 | namespace Server.Loader.Extensions; 7 | 8 | public static class EmbedIoExtensions 9 | { 10 | public static WebApiModule WithController(this WebApiModule webApiModule, PluginWebApiController controller) 11 | { 12 | Delegate factoryFunc = Expression 13 | .Lambda( 14 | Expression.Call( 15 | Expression.Constant(controller), 16 | typeof(PluginWebApiController) 17 | .GetMethod("Build")! 18 | .MakeGenericMethod(controller.GetType()) 19 | ) 20 | ) 21 | .Compile(); 22 | return (WebApiModule)typeof(WebApiModuleExtensions) 23 | .GetMethods(BindingFlags.Static | BindingFlags.Public) 24 | .Single(mi => mi.IsGenericMethod & mi.Name == "WithController" && mi.GetParameters().Length == 2) 25 | .MakeGenericMethod(controller.GetType()) 26 | .Invoke(null, new object[] { webApiModule, factoryFunc.DynamicInvoke(Array.Empty()) }); 27 | } 28 | } -------------------------------------------------------------------------------- /code/server/loader/FileSystemHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace Server.Loader; 4 | 5 | public static class FileSystemHelper 6 | { 7 | public static string GetRootPath() => GetPath(); 8 | 9 | public static string GetPath(params string[] segments) 10 | { 11 | var assemblyPath = Assembly.GetExecutingAssembly().Location; 12 | var rootPath = Path.GetDirectoryName(assemblyPath)!; 13 | 14 | foreach (var segment in segments) 15 | { 16 | rootPath = Path.Combine(rootPath, segment); 17 | } 18 | 19 | return rootPath; 20 | } 21 | } -------------------------------------------------------------------------------- /code/server/loader/Game/PlayerManager.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Game; 2 | using CyberpunkSdk.Internal; 3 | 4 | namespace Server.Loader.Game 5 | { 6 | public class PlayerSystem : CyberpunkSdk.Game.PlayerSystem 7 | { 8 | public override IEnumerable PlayerIds => _players; 9 | 10 | private readonly List _players = []; 11 | 12 | internal PlayerSystem() 13 | { 14 | } 15 | 16 | internal void PlayerJoin(ulong Id) 17 | { 18 | OnPlayerJoin(Id); 19 | _players.Add(Id); 20 | } 21 | 22 | internal void PlayerLeft(ulong Id) 23 | { 24 | _players.Remove(Id); 25 | OnPlayerLeft(Id); 26 | } 27 | 28 | public override Player GetById(ulong Id) 29 | { 30 | return new Player(IPlayerManager.Get().GetPlayer(Id)); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/server/loader/Game/World.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Server.Loader.Game 9 | { 10 | public class World : CyberpunkSdk.Game.World 11 | { 12 | internal World() 13 | { 14 | } 15 | 16 | internal void Update(float Delta) 17 | { 18 | OnUpdate(Delta); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /code/server/loader/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | internal class Program 4 | { 5 | 6 | private static void SetupCallbacks() 7 | { 8 | CyberpunkMp.TUpdateCallback updateCallback = new CyberpunkMp.TUpdateCallback(Server.Loader.Server.Update); 9 | GCHandle.Alloc(updateCallback); 10 | CyberpunkMp.ServerAPI.SetUpdateCallback(updateCallback); 11 | 12 | CyberpunkMp.TPlayerEvent joinCallback = new CyberpunkMp.TPlayerEvent(Server.Loader.Server.PlayerJoin); 13 | GCHandle.Alloc(joinCallback); 14 | CyberpunkMp.ServerAPI.SetPlayerJoinCallback(joinCallback); 15 | 16 | CyberpunkMp.TPlayerEvent leaveCallback = new CyberpunkMp.TPlayerEvent(Server.Loader.Server.PlayerLeft); 17 | GCHandle.Alloc(leaveCallback); 18 | CyberpunkMp.ServerAPI.SetPlayerLeftCallback(leaveCallback); 19 | } 20 | 21 | private static void Main(string[] args) 22 | { 23 | try 24 | { 25 | if (CyberpunkMp.ServerAPI.Initialize()) 26 | { 27 | SetupCallbacks(); 28 | 29 | CyberpunkMp.ServerAPI.Run(); 30 | } 31 | } 32 | catch (Exception e) 33 | { 34 | Console.WriteLine(e); 35 | } 36 | finally 37 | { 38 | CyberpunkMp.ServerAPI.Exit(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /code/server/loader/Server.Loader.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | True 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /code/server/loader/Systems/Statistics.cs: -------------------------------------------------------------------------------- 1 | namespace Server.Loader.Systems 2 | { 3 | internal class Statistics 4 | { 5 | public class RpcRecord 6 | { 7 | public string Name = ""; 8 | public int CallCount; 9 | public bool Server; 10 | public ulong Bytes; 11 | } 12 | 13 | private readonly List rpcStatistics = new List(); 14 | 15 | public IList Rpcs => rpcStatistics; 16 | 17 | public void AddRpcFunction(string name, bool server) 18 | { 19 | rpcStatistics.Add(new RpcRecord 20 | { 21 | Name = name, 22 | CallCount = 0, 23 | Server = server, 24 | Bytes = 0 25 | }); 26 | } 27 | 28 | public void RecordCall(int opcode, int bytes) 29 | { 30 | var record = rpcStatistics[opcode]; 31 | 32 | record.CallCount++; 33 | record.Bytes += (ulong)bytes; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /code/server/native/Components/AppearanceComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct AppearanceComponent 4 | { 5 | Vector equipment; 6 | Vector ccstate; 7 | }; -------------------------------------------------------------------------------- /code/server/native/Components/AttachmentComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct AttachmentComponent 4 | { 5 | flecs::entity Parent; 6 | uint64_t SlotId; 7 | 8 | static void Register(flecs::world& aWorld); 9 | }; -------------------------------------------------------------------------------- /code/server/native/Components/CellComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Game/GridCell.h" 4 | 5 | struct CellComponent 6 | { 7 | gsl::not_null pCell; 8 | }; -------------------------------------------------------------------------------- /code/server/native/Components/CharacterComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct CharacterComponent 4 | { 5 | bool IsPlayerPuppet{false}; 6 | }; -------------------------------------------------------------------------------- /code/server/native/Components/InterpolationComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct InterpolationComponent 4 | { 5 | struct Timepoint 6 | { 7 | glm::vec3 Position; 8 | glm::vec3 Rotation; 9 | glm::vec3 Velocity; 10 | uint64_t Tick; 11 | }; 12 | 13 | List TimePoints; 14 | }; -------------------------------------------------------------------------------- /code/server/native/Components/LevelTag.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct LevelActorTag{}; 4 | struct LevelSystemTag{}; -------------------------------------------------------------------------------- /code/server/native/Components/MovementComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct MovementComponent 4 | { 5 | glm::vec3 Position; 6 | glm::vec3 Rotation; 7 | float Velocity; 8 | uint64_t Tick; 9 | 10 | static void Register(flecs::world& aWorld); 11 | }; -------------------------------------------------------------------------------- /code/server/native/Components/PlayerComponent.cpp: -------------------------------------------------------------------------------- 1 | #include "PlayerComponent.h" 2 | 3 | void PlayerComponent::Register(flecs::world& aWorld) 4 | { 5 | aWorld.component() 6 | .member("Connection", &PlayerComponent::Connection) 7 | .member("Puppet", &PlayerComponent::Puppet) 8 | .member("Username", &PlayerComponent::Username); 9 | } 10 | 11 | const char* PlayerComponent::GetUsername() const 12 | { 13 | return Username.c_str(); 14 | } 15 | -------------------------------------------------------------------------------- /code/server/native/Components/PlayerComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct PlayerComponent 4 | { 5 | ConnectionId Connection; 6 | flecs::entity Puppet; 7 | std::string Username; 8 | 9 | const char* GetUsername() const; 10 | 11 | static void Register(flecs::world& aWorld); 12 | }; 13 | -------------------------------------------------------------------------------- /code/server/native/Components/VehicleComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct VehicleComponent 4 | { 5 | uint64_t TweakDBID{0}; 6 | 7 | static void Register(flecs::world& aWorld); 8 | }; -------------------------------------------------------------------------------- /code/server/native/Config.cpp: -------------------------------------------------------------------------------- 1 | #include "Config.h" 2 | -------------------------------------------------------------------------------- /code/server/native/Game/GridCell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Math/Vector2.h" 4 | 5 | 6 | struct GridCell 7 | { 8 | using TPosition = Vector2; 9 | 10 | GridCell(TPosition aPosition); 11 | ~GridCell(); 12 | 13 | void Add(flecs::entity aEntity) noexcept; 14 | void Remove(flecs::entity aEntity) noexcept; 15 | 16 | [[nodiscard]] TPosition GetPosition() const noexcept { return m_position; } 17 | [[nodiscard]] size_t Count() const noexcept { return m_entities.size(); } 18 | 19 | template void ForEach(T func) 20 | { 21 | for (auto pChar : m_entities) 22 | func(pChar); 23 | } 24 | 25 | template void ForEach(T func) 26 | { 27 | for (auto pChar : m_entities) 28 | { 29 | if(pChar.has()) 30 | func(pChar); 31 | } 32 | } 33 | 34 | private: 35 | 36 | Vector m_entities; 37 | TPosition m_position; 38 | }; 39 | -------------------------------------------------------------------------------- /code/server/native/Game/World.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Config.h" 4 | #include "Scripting/WorldScriptInstance.h" 5 | 6 | struct World : flecs::world 7 | { 8 | TP_NOCOPYMOVE(World); 9 | 10 | World(const FlecsConfig& acFlecsConfig); 11 | ~World(); 12 | 13 | void Update(float aDelta); 14 | 15 | gsl::not_null GetScriptInstance() noexcept; 16 | gsl::not_null GetScriptInstance() const noexcept; 17 | 18 | private: 19 | 20 | WorldScriptInstance m_scriptInstance; 21 | }; 22 | -------------------------------------------------------------------------------- /code/server/native/Scripting/AttachmentComponentScriptInstance.cpp: -------------------------------------------------------------------------------- 1 | #include "Components/AttachmentComponent.h" 2 | #include "AttachmentComponentScriptInstance.h" 3 | #include 4 | 5 | 6 | AttachmentComponentScriptInstance::AttachmentComponentScriptInstance(flecs::entity aPuppet) 7 | : m_puppet(aPuppet) 8 | { 9 | 10 | } 11 | 12 | AttachmentComponentScriptInstance::~AttachmentComponentScriptInstance() 13 | { 14 | } 15 | 16 | uint64_t AttachmentComponentScriptInstance::GetParent() 17 | { 18 | const auto pComponent = m_puppet.get(); 19 | if (pComponent) 20 | { 21 | auto pAttachmentComponent = pComponent->Puppet.get(); 22 | if (pAttachmentComponent) 23 | { 24 | return pAttachmentComponent->Parent.raw_id(); 25 | } 26 | } 27 | return 0; 28 | } 29 | 30 | uint64_t AttachmentComponentScriptInstance::GetSlot() 31 | { 32 | const auto pComponent = m_puppet.get(); 33 | if (pComponent) 34 | { 35 | auto pAttachmentComponent = pComponent->Puppet.get(); 36 | if (pAttachmentComponent) 37 | { 38 | return pAttachmentComponent->SlotId; 39 | } 40 | } 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /code/server/native/Scripting/AttachmentComponentScriptInstance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IAttachmentComponent.h" 4 | 5 | struct AttachmentComponentScriptInstance final : IAttachmentComponent 6 | { 7 | AttachmentComponentScriptInstance(flecs::entity aPuppet); 8 | ~AttachmentComponentScriptInstance() override; 9 | 10 | // Inherited via IAttachmentComponent 11 | virtual uint64_t GetParent() override; 12 | virtual uint64_t GetSlot() override; 13 | 14 | protected: 15 | flecs::entity m_puppet; 16 | }; 17 | -------------------------------------------------------------------------------- /code/server/native/Scripting/ConfigScriptInstance.cpp: -------------------------------------------------------------------------------- 1 | #include "IConfig.h" 2 | 3 | #include 4 | 5 | TP_EXPORT const IConfig* IConfig::Get() 6 | { 7 | return GServer->GetConfig(); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /code/server/native/Scripting/IAttachmentComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | struct TP_EXPORT IAttachmentComponent 6 | { 7 | CS_INTERNAL IAttachmentComponent() = default; 8 | IAttachmentComponent(const IAttachmentComponent&) = delete; 9 | virtual ~IAttachmentComponent() {} 10 | 11 | virtual uint64_t GetParent() = 0; 12 | virtual uint64_t GetSlot() = 0; 13 | }; 14 | -------------------------------------------------------------------------------- /code/server/native/Scripting/IConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | struct IConfig 6 | { 7 | virtual const char* GetName() const = 0; 8 | virtual const char* GetDescription() const = 0; 9 | virtual const char* GetApiKey() const = 0; 10 | virtual const char* GetIconUrl() const = 0; 11 | virtual const char* GetTags() const = 0; 12 | virtual const char* GetPassword() const = 0; 13 | virtual uint16_t GetMaxPlayer() const = 0; 14 | virtual uint16_t GetPort() const = 0; 15 | virtual uint16_t GetWebPort() const = 0; 16 | virtual uint16_t GetTickRate() const = 0; 17 | virtual uint16_t GetUpdateRate() const = 0; 18 | virtual bool GetPublic() const = 0; 19 | 20 | TP_EXPORT static const IConfig* Get(); 21 | }; -------------------------------------------------------------------------------- /code/server/native/Scripting/ILogger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | struct ILogger 6 | { 7 | virtual void Debug(const char* aMessage) = 0; 8 | virtual void Info(const char* aMessage) = 0; 9 | virtual void Warn(const char* aMessage) = 0; 10 | virtual void Error(const char* aMessage) = 0; 11 | 12 | TP_EXPORT static ILogger* Get(const char* aName); 13 | }; -------------------------------------------------------------------------------- /code/server/native/Scripting/IMovementComponent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | struct Vector3 6 | { 7 | float X; 8 | float Y; 9 | float Z; 10 | }; 11 | 12 | struct IMovementComponent 13 | { 14 | IMovementComponent(const IMovementComponent&) = delete; 15 | virtual ~IMovementComponent() {} 16 | 17 | virtual Vector3 GetPosition() = 0; 18 | virtual Vector3 GetRotation() = 0; 19 | virtual float GetVelocity() = 0; 20 | 21 | protected: 22 | 23 | IMovementComponent() = default; 24 | }; 25 | -------------------------------------------------------------------------------- /code/server/native/Scripting/IPlayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | struct IBuffer; 6 | struct IMovementComponent; 7 | struct IAttachmentComponent; 8 | 9 | struct IPlayer 10 | { 11 | IPlayer(const IPlayer&) = delete; 12 | 13 | virtual ~IPlayer(){} 14 | virtual uint64_t GetId() const = 0; 15 | virtual uint64_t GetPuppetId() const = 0; 16 | virtual uint32_t GetConnectionId() const = 0; 17 | virtual IMovementComponent* GetMovementComponent() = 0; 18 | virtual IAttachmentComponent* GetAttachmentComponent() = 0; 19 | virtual const char* GetUsername() const = 0; 20 | virtual void SendChat(const char* From, const char* Message) = 0; 21 | virtual void Call(uint64_t Klass, uint64_t Function, IBuffer* Arguments) = 0; 22 | 23 | protected: 24 | 25 | IPlayer() = default; 26 | }; 27 | -------------------------------------------------------------------------------- /code/server/native/Scripting/IPlayerManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | struct IPlayer; 6 | CS_INTERNAL struct IPlayerManager 7 | { 8 | using PlayerIdHandler = void (*)(uint64_t Id); 9 | 10 | virtual ~IPlayerManager(){} 11 | virtual IPlayer* GetPlayer(uint64_t Id) = 0; 12 | 13 | TP_EXPORT static IPlayerManager* Get(); 14 | }; -------------------------------------------------------------------------------- /code/server/native/Scripting/IRpc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | struct IPlayer; 6 | struct IBuffer; 7 | 8 | CS_INTERNAL struct RpcCall 9 | { 10 | uint32_t Id; 11 | IBuffer* Args; 12 | uint64_t PlayerId; 13 | }; 14 | 15 | CS_INTERNAL struct IRpc 16 | { 17 | virtual void Call(uint64_t PlayerId, uint64_t Klass, uint64_t Function, IBuffer* Arguments) = 0; 18 | 19 | TP_EXPORT static IRpc* Get(); 20 | 21 | CS_INTERNAL virtual uint32_t Count() = 0; 22 | CS_INTERNAL virtual RpcCall* GetRpc(uint32_t aIndex) = 0; 23 | CS_INTERNAL virtual void Clear() = 0; 24 | CS_INTERNAL virtual uint32_t RegisterServer(uint64_t Klass, uint64_t Function) = 0; 25 | CS_INTERNAL virtual uint32_t RegisterClient(uint64_t Klass, uint64_t Function) = 0; 26 | }; -------------------------------------------------------------------------------- /code/server/native/Scripting/IWorld.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | struct IWorld 6 | { 7 | TP_EXPORT static IWorld* Get(); 8 | }; -------------------------------------------------------------------------------- /code/server/native/Scripting/LoggerScriptInstance.h: -------------------------------------------------------------------------------- 1 | #include "ILogger.h" 2 | 3 | struct LoggerScriptInstance : ILogger 4 | { 5 | LoggerScriptInstance(const char* aName); 6 | 7 | void Debug(const char* aMessage) override; 8 | void Info(const char* aMessage) override; 9 | void Warn(const char* aMessage) override; 10 | void Error(const char* aMessage) override; 11 | 12 | private: 13 | std::shared_ptr m_logger; 14 | }; 15 | -------------------------------------------------------------------------------- /code/server/native/Scripting/MovementComponentScriptInstance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IMovementComponent.h" 4 | 5 | struct MovementComponentScriptInstance final : IMovementComponent 6 | { 7 | MovementComponentScriptInstance(flecs::entity aPuppet); 8 | ~MovementComponentScriptInstance() override; 9 | 10 | // Inherited via IMovementComponent 11 | Vector3 GetPosition() override; 12 | Vector3 GetRotation() override; 13 | float GetVelocity() override; 14 | 15 | protected: 16 | flecs::entity m_puppet; 17 | }; 18 | -------------------------------------------------------------------------------- /code/server/native/Scripting/PlayerManagerScriptInstance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IPlayerManager.h" 4 | 5 | struct PlayerScriptInstance; 6 | struct PlayerManager; 7 | 8 | 9 | using TPlayerCallback = void (*)(uint64_t); 10 | struct PlayerManagerScriptInstance final : IPlayerManager 11 | { 12 | PlayerManagerScriptInstance(PlayerManager* apPlayerManager); 13 | ~PlayerManagerScriptInstance() override; 14 | IPlayer* GetPlayer(uint64_t Id) override; 15 | 16 | void SetPlayerJoinCallback(TPlayerCallback callback); 17 | void SetPlayerLeftCallback(TPlayerCallback callback); 18 | 19 | protected: 20 | 21 | void PlayerJoin(uint64_t aId) const; 22 | void PlayerLeft(uint64_t aId) const; 23 | 24 | private: 25 | PlayerManager* m_pPlayerManager{nullptr}; 26 | Map> m_scriptInstances; 27 | TPlayerCallback m_joinCallback{nullptr}; 28 | TPlayerCallback m_leftCallback{nullptr}; 29 | }; 30 | -------------------------------------------------------------------------------- /code/server/native/Scripting/PlayerScriptInstance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IPlayer.h" 4 | #include "MovementComponentScriptInstance.h" 5 | #include "AttachmentComponentScriptInstance.h" 6 | 7 | struct PlayerScriptInstance final : IPlayer 8 | { 9 | PlayerScriptInstance(flecs::entity aPlayer); 10 | ~PlayerScriptInstance() override; 11 | 12 | uint64_t GetId() const override; 13 | uint32_t GetConnectionId() const override; 14 | uint64_t GetPuppetId() const override; 15 | IMovementComponent* GetMovementComponent() override; 16 | IAttachmentComponent* GetAttachmentComponent() override; 17 | const char* GetUsername() const override; 18 | void SendChat(const char* From, const char* Message) override; 19 | void Call(uint64_t Klass, uint64_t Function, IBuffer* Arguments) override; 20 | 21 | protected: 22 | flecs::entity m_player; 23 | MovementComponentScriptInstance m_movementComponent; 24 | AttachmentComponentScriptInstance m_attachmentComponent; 25 | }; 26 | -------------------------------------------------------------------------------- /code/server/native/Scripting/ScriptingBase.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef CPPSHARP_GENERATOR 6 | #define SCRIPTING_SKIP(x) 7 | #define TP_EXPORT 8 | #else 9 | #define SCRIPTING_SKIP(x) x 10 | #ifdef WIN32 11 | #define TP_EXPORT __declspec(dllexport) 12 | #else 13 | #define TP_EXPORT __attribute__((visibility("default"))) 14 | #endif 15 | #endif 16 | 17 | #define CS_INTERNAL 18 | #define CS_READONLY -------------------------------------------------------------------------------- /code/server/native/Scripting/ServerAPI.cpp: -------------------------------------------------------------------------------- 1 | #include "ServerAPI.h" 2 | 3 | #include "GameServer.h" 4 | 5 | #include "WorldScriptInstance.h" 6 | #include 7 | 8 | static UniquePtr s_server; 9 | 10 | bool ServerAPI::Initialize() 11 | { 12 | s_server = MakeUnique(); 13 | 14 | std::atexit(&ServerAPI::Exit); 15 | 16 | return s_server->IsListening(); 17 | } 18 | 19 | void ServerAPI::Run() 20 | { 21 | s_server->Run(); 22 | } 23 | 24 | void ServerAPI::Exit() 25 | { 26 | s_server = nullptr; 27 | } 28 | 29 | TP_EXPORT void ServerAPI::SetUpdateCallback(TUpdateCallback apCallback) 30 | { 31 | GServer->GetWorld()->GetScriptInstance()->SetUpdateCallback(apCallback); 32 | } 33 | 34 | void ServerAPI::SetPlayerJoinCallback(TPlayerEvent callback) 35 | { 36 | GServer->GetWorld()->get_mut()->GetScriptInstance()->SetPlayerJoinCallback(callback); 37 | } 38 | 39 | void ServerAPI::SetPlayerLeftCallback(TPlayerEvent callback) 40 | { 41 | GServer->GetWorld()->get_mut()->GetScriptInstance()->SetPlayerLeftCallback(callback); 42 | } 43 | -------------------------------------------------------------------------------- /code/server/native/Scripting/ServerAPI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptingBase.h" 4 | 5 | using TUpdateCallback = void(*)(float); 6 | using TPlayerEvent = void(*)(uint64_t); 7 | 8 | struct ServerAPI 9 | { 10 | TP_EXPORT static bool Initialize(); 11 | TP_EXPORT static void Run(); 12 | TP_EXPORT static void Exit(); 13 | TP_EXPORT static void SetUpdateCallback(TUpdateCallback callback); 14 | TP_EXPORT static void SetPlayerJoinCallback(TPlayerEvent callback); 15 | TP_EXPORT static void SetPlayerLeftCallback(TPlayerEvent callback); 16 | }; -------------------------------------------------------------------------------- /code/server/native/Scripting/WorldScriptInstance.cpp: -------------------------------------------------------------------------------- 1 | #include "WorldScriptInstance.h" 2 | 3 | #include "GameServer.h" 4 | 5 | TP_EXPORT IWorld* IWorld::Get() 6 | { 7 | return GServer->GetWorld()->GetScriptInstance(); 8 | } 9 | 10 | void WorldScriptInstance::SetUpdateCallback(TUpdateCallback apCallback) 11 | { 12 | m_callback = apCallback; 13 | } 14 | 15 | WorldScriptInstance::WorldScriptInstance() 16 | { 17 | 18 | } 19 | 20 | WorldScriptInstance::~WorldScriptInstance() 21 | { 22 | } 23 | 24 | void WorldScriptInstance::Initialize() 25 | { 26 | m_updateSystem = GServer->GetWorld()->system("Script Update") 27 | .kind(flecs::OnUpdate) 28 | .run([this](flecs::iter& iter) 29 | { 30 | float delta = iter.delta_time(); 31 | if (m_callback != nullptr) 32 | m_callback(delta); 33 | }); 34 | 35 | m_updateSystem.child_of(GServer->GetWorld()->entity("systems")); 36 | } 37 | 38 | -------------------------------------------------------------------------------- /code/server/native/Scripting/WorldScriptInstance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IWorld.h" 4 | 5 | using TUpdateCallback = void (*)(float); 6 | 7 | struct WorldScriptInstance : IWorld 8 | { 9 | WorldScriptInstance(); 10 | virtual ~WorldScriptInstance(); 11 | 12 | void Initialize(); 13 | 14 | void SetUpdateCallback(TUpdateCallback apCallback); 15 | 16 | private: 17 | 18 | flecs::system m_updateSystem; 19 | TUpdateCallback m_callback{nullptr}; 20 | }; 21 | -------------------------------------------------------------------------------- /code/server/native/ServerPCH.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #undef check 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #define CPPHTTPLIB_OPENSSL_SUPPORT 39 | #include 40 | 41 | #include 42 | #include -------------------------------------------------------------------------------- /code/server/native/Systems/ChatSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct World; 4 | struct ChatSystem 5 | { 6 | ChatSystem(gsl::not_null apWorld); 7 | 8 | void Broadcast(String acUsername, String acMessage); 9 | 10 | protected: 11 | 12 | void HandleChatMessageRequest(const PacketEvent& aMessage); 13 | 14 | private: 15 | 16 | gsl::not_null m_pWorld; 17 | }; 18 | 19 | -------------------------------------------------------------------------------- /code/server/native/Systems/ServerListSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct World; 4 | struct ServerListSystem 5 | { 6 | ServerListSystem(gsl::not_null apWorld); 7 | 8 | private: 9 | void Tick() noexcept; 10 | void Announce() noexcept; 11 | 12 | static void PostAnnouncement( 13 | const std::string& acName, const std::string& acDesc, const std::string& acIconUrl, uint16_t aPort, uint16_t aTick, uint16_t aPlayerCount, uint16_t aPlayerMaxCount, 14 | const std::string& acTagList, bool aPublic, bool aPassword, int32 aFlags) noexcept; 15 | 16 | gsl::not_null m_pWorld; 17 | flecs::system m_updateSystem; 18 | flecs::observer m_serverListObserver; 19 | mutable std::chrono::steady_clock::time_point m_nextAnnounce; 20 | }; 21 | -------------------------------------------------------------------------------- /code/server/native/xmake.lua: -------------------------------------------------------------------------------- 1 | target("Server.Native") 2 | set_kind("shared") 3 | set_group("Server") 4 | add_files("**.cpp") 5 | 6 | add_headerfiles("**.h", "**.hpp", "**.inl") 7 | set_pcxxheader("ServerPCH.h") 8 | add_includedirs( 9 | ".", 10 | "../../../build", 11 | "../../../vendor" 12 | ) 13 | 14 | add_defines("STEAMNETWORKINGSOCKETS_STATIC_LINK") 15 | 16 | add_deps("Common", "Protocol", "Server.Scripting") 17 | 18 | add_packages( 19 | "gamenetworkingsockets", 20 | "mimalloc", 21 | "spdlog", 22 | "hopscotch-map", 23 | "cryptopp", 24 | "glm", 25 | "openssl", 26 | "zlib", 27 | "nlohmann_json", 28 | "flecs", 29 | "entt", 30 | "microsoft-gsl") 31 | 32 | after_install(function (target) 33 | os.cp(path.join(target:installdir("bin"), "Server.Native.dll"), path.join(target:installdir("launcher"), "server", "Server.Native.dll")) 34 | end) -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | CyberpunkSdk.cs 4 | Std.cs 5 | *.cpp 6 | CyberpunkSdk.Internal.cs 7 | CyberpunkSdk.Internal-symbols.cpp 8 | Std.cs -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Server.Loader")] 4 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Game/Components/AttachmentComponent.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Internal; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace CyberpunkSdk.Game.Components 9 | { 10 | public class AttachmentComponent 11 | { 12 | private IAttachmentComponent attachmentComponent; 13 | 14 | internal AttachmentComponent(IAttachmentComponent attachmentComponent) 15 | { 16 | this.attachmentComponent = attachmentComponent; 17 | } 18 | 19 | public ulong Parent 20 | { 21 | get { return attachmentComponent.Parent; } 22 | } 23 | public ulong Slot 24 | { 25 | get { return attachmentComponent.Slot; } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Game/Components/MovementComponent.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Internal; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace CyberpunkSdk.Game.Components 9 | { 10 | public class MovementComponent 11 | { 12 | private IMovementComponent movementComponent; 13 | 14 | internal MovementComponent(IMovementComponent movementComponent) 15 | { 16 | this.movementComponent = movementComponent; 17 | } 18 | 19 | public Vector3 Position 20 | { 21 | get { return movementComponent.Position; } 22 | } 23 | 24 | public Vector3 Rotation 25 | { 26 | get { return movementComponent.Rotation; } 27 | } 28 | 29 | public float Velocity 30 | { 31 | get { return movementComponent.Velocity; } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Game/Player.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Internal; 2 | 3 | namespace CyberpunkSdk.Game 4 | { 5 | public class Player 6 | { 7 | private IPlayer player; 8 | 9 | internal Player(IPlayer player) 10 | { 11 | this.player = player; 12 | } 13 | 14 | public void SendChat(string From, string Message) 15 | { 16 | player.SendChat(From, Message); 17 | } 18 | 19 | public ulong Id 20 | { 21 | get { return player.Id; } 22 | } 23 | 24 | public ulong PuppetId 25 | { 26 | get { return player.PuppetId; } 27 | } 28 | 29 | public uint ConnectionId 30 | { 31 | get { return player.ConnectionId; } 32 | } 33 | 34 | public Components.MovementComponent MovementComponent 35 | { 36 | get { return new Components.MovementComponent(player.MovementComponent); } 37 | } 38 | 39 | public Components.AttachmentComponent AttachmentComponent 40 | { 41 | get { return new Components.AttachmentComponent(player.AttachmentComponent); } 42 | } 43 | 44 | public string Username 45 | { 46 | get { return player.Username; } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Game/PlayerManager.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Internal; 2 | 3 | namespace CyberpunkSdk.Game 4 | { 5 | public abstract class PlayerSystem 6 | { 7 | public delegate void PlayerEvent(ulong Id); 8 | 9 | public event PlayerEvent? PlayerJoinEvent; 10 | public event PlayerEvent? PlayerLeftEvent; 11 | public abstract IEnumerable PlayerIds { get; } 12 | 13 | public abstract Player GetById(ulong Id); 14 | 15 | protected void OnPlayerJoin(ulong Id) 16 | { 17 | PlayerJoinEvent?.Invoke(Id); 18 | } 19 | 20 | protected void OnPlayerLeft(ulong Id) 21 | { 22 | PlayerLeftEvent?.Invoke(Id); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Game/Timer.cs: -------------------------------------------------------------------------------- 1 | namespace CyberpunkSdk.Game 2 | { 3 | public abstract class Timer 4 | { 5 | public delegate void TickDelegate(float delta); 6 | 7 | public abstract void Add(TickDelegate t, float interval); 8 | public abstract void Remove(TickDelegate t); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Game/World.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace CyberpunkSdk.Game 9 | { 10 | public abstract class World 11 | { 12 | public delegate void UpdateDelegate(float Delta); 13 | 14 | public event UpdateDelegate? UpdateEvent; 15 | 16 | protected void OnUpdate(float Delta) 17 | { 18 | UpdateEvent?.Invoke(Delta); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Server.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using CyberpunkSdk.Game; 4 | using CyberpunkSdk.Systems; 5 | using Timer = CyberpunkSdk.Game.Timer; 6 | 7 | namespace CyberpunkSdk 8 | { 9 | public static class Server 10 | { 11 | static public PlayerSystem PlayerSystem { get; internal set; } 12 | static public World World { get; internal set; } 13 | static public Timer Timer { get; internal set; } 14 | static public IRpcManager RpcManager { get; internal set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Systems/Logger.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Internal; 2 | 3 | namespace CyberpunkSdk.Systems 4 | { 5 | public class Logger 6 | { 7 | private ILogger logger; 8 | 9 | public Logger(string name) 10 | { 11 | logger = ILogger.Get(name); 12 | } 13 | 14 | public void Debug(string aMessage) 15 | { 16 | logger.Debug(aMessage); 17 | } 18 | 19 | public void Info(string aMessage) 20 | { 21 | logger.Info(aMessage); 22 | } 23 | 24 | public void Warn(string aMessage) 25 | { 26 | logger.Warn(aMessage); 27 | } 28 | 29 | public void Error(string aMessage) 30 | { 31 | logger.Error(aMessage); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Systems/Rpc.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Internal; 2 | using CyberpunkSdk.Types; 3 | using System.Reflection; 4 | 5 | namespace CyberpunkSdk.Systems 6 | { 7 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 8 | public class ServerRpcAttribute : Attribute 9 | { 10 | public ulong Class = 0; 11 | public ulong Function = 0; 12 | } 13 | 14 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 15 | public class ClientRpcAttribute : Attribute 16 | { 17 | public ulong Class = 0; 18 | public ulong Function = 0; 19 | } 20 | 21 | public interface IRpcManager 22 | { 23 | void Call(ulong playerId, ulong klass, ulong func, IBuffer args); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Types/GameTime.cs: -------------------------------------------------------------------------------- 1 | namespace CyberpunkSdk.Types 2 | { 3 | public class GameTime 4 | { 5 | public uint Seconds { get; private set; } 6 | 7 | public GameTime(uint seconds) 8 | { 9 | Seconds = seconds; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Types/TweakDBID.cs: -------------------------------------------------------------------------------- 1 | namespace CyberpunkSdk.Types 2 | { 3 | public class TweakDBID 4 | { 5 | public uint Hash { get; private set; } 6 | public byte Length { get; private set; } 7 | 8 | public TweakDBID(uint hash, byte length) 9 | { 10 | Hash = hash; 11 | Length = length; 12 | } 13 | 14 | public TweakDBID(string name) 15 | { 16 | Hash = Utils.CRC32.Compute(name); 17 | Length = (byte)name.Length; 18 | } 19 | 20 | public override int GetHashCode() 21 | { 22 | return Hash.GetHashCode(); 23 | } 24 | 25 | public override bool Equals(object? obj) 26 | { 27 | return Equals((TweakDBID?)obj); 28 | } 29 | 30 | public bool Equals(TweakDBID? other) 31 | { 32 | return other != null && Hash == other.Hash; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/Utils/CRC32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace CyberpunkSdk.Utils 8 | { 9 | public class CRC32 10 | { 11 | private static uint[] table; 12 | 13 | static CRC32() 14 | { 15 | table = new uint[256]; 16 | for (uint i = 0; i < 256; i++) 17 | { 18 | uint crc = i; 19 | for (int j = 0; j < 8; j++) 20 | crc = (crc & 1) == 1 ? (crc >> 1) ^ 0xEDB88320 : crc >> 1; 21 | table[i] = crc; 22 | } 23 | } 24 | 25 | public static uint Compute(string input) 26 | { 27 | byte[] bytes = Encoding.ASCII.GetBytes(input); 28 | uint crc = 0xFFFFFFFF; 29 | for (int i = 0; i < bytes.Length; i++) 30 | { 31 | byte index = (byte)(((crc) & 0xFF) ^ bytes[i]); 32 | crc = (crc >> 8) ^ table[index]; 33 | } 34 | return ~crc; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/server/scripting/CyberpunkSdk/WebApi.cs: -------------------------------------------------------------------------------- 1 | using EmbedIO; 2 | using EmbedIO.WebApi; 3 | 4 | namespace CyberpunkSdk; 5 | 6 | public interface IWebApiHook 7 | { 8 | public Func BuildController(); 9 | } 10 | 11 | public class PluginWebApiController : WebApiController 12 | { 13 | public Func Build() where T : WebApiController => () => this as T; 14 | } -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/Admin/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/Admin/index.ts: -------------------------------------------------------------------------------- 1 | import {Widget} from './src/widget'; 2 | import {Layout as RGLLayout} from 'react-grid-layout'; 3 | 4 | const Layout: Partial = { 5 | w: 3, 6 | h: 2, 7 | minW: 2, 8 | minH: 2, 9 | maxW: 4, 10 | maxH: 3, 11 | }; 12 | 13 | const Plugin = { 14 | manifest: { 15 | name: 'Emote', 16 | author: 'Rayshader', 17 | version: '1.0.0', 18 | }, 19 | widget: { 20 | component: Widget, 21 | layout: Layout 22 | }, 23 | page: undefined 24 | }; 25 | 26 | export default Plugin; -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/Admin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emotesystem", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "author": "Rayshader", 6 | "scripts": { 7 | "dev": "vite", 8 | "start": "vite", 9 | "build": "vite build", 10 | "build:watch": "npx concurrently --kill-others \"vite build --watch\" \"node ..\\..\\..\\admin\\watcher.js\"" 11 | }, 12 | "dependencies": { 13 | "@emotion/react": "^11.14.0", 14 | "@emotion/styled": "^11.14.0", 15 | "@mui/material": "^6.2.1", 16 | "http-status-codes": "^2.3.0", 17 | "react": "^18.3.1", 18 | "react-dom": "^18.3.1" 19 | }, 20 | "devDependencies": { 21 | "@types/react": "^18.3.18", 22 | "@types/react-grid-layout": "^1.3.5", 23 | "@vitejs/plugin-react": "^4.3.4", 24 | "typescript": "^5.7.2", 25 | "vite": "^6.0.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/Admin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "target": "ES2020", 5 | "moduleResolution": "Bundler", 6 | "jsx": "react", 7 | "lib": [ 8 | "es6", 9 | "dom" 10 | ], 11 | "esModuleInterop": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "noImplicitAny": true, 14 | "noImplicitThis": true, 15 | "strictNullChecks": true, 16 | "allowSyntheticDefaultImports": true, 17 | "strict": true, 18 | "skipLibCheck": true 19 | }, 20 | "include": ["src"], 21 | } 22 | -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/Client/Plugins.EmoteClient.cs: -------------------------------------------------------------------------------- 1 | // This file is automatically generated 2 | 3 | #pragma warning disable CS8618 4 | #pragma warning disable CS0219 5 | 6 | using CyberpunkSdk; 7 | using CyberpunkSdk.Types; 8 | 9 | using CyberpunkSdk.Systems; 10 | 11 | using CyberpunkSdk.Internal; 12 | 13 | namespace Cyberpunk.Rpc.Client.Plugins 14 | { 15 | public static class EmoteClient 16 | { 17 | [ClientRpc(Class = 17492243237040389260, Function = 5701494315076382889)] 18 | public static void TriggerEmote(ulong playerId, ulong serverId, string name) 19 | { 20 | ushort length = 0; 21 | var data = IBuffer.Create(); 22 | try{ 23 | data.WriteUint64(serverId); 24 | data.WriteString(name); 25 | CyberpunkSdk.Server.RpcManager.Call(playerId, 17492243237040389260, 5701494315076382889, data); 26 | } finally { 27 | IBuffer.Release(data); 28 | } 29 | } 30 | 31 | } 32 | } -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/Plugin.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk; 2 | 3 | namespace EmoteSystem 4 | { 5 | public class Plugin : IWebApiHook 6 | { 7 | public static Plugin Instance { get; set; } 8 | 9 | static Plugin() 10 | { 11 | Instance = new Plugin(); 12 | } 13 | 14 | public EmoteDto? LastEmote 15 | { 16 | get 17 | { 18 | lock (_emoteLock) 19 | { 20 | return _lastEmote; 21 | } 22 | } 23 | private set 24 | { 25 | lock (_emoteLock) 26 | { 27 | _lastEmote = value; 28 | } 29 | } 30 | } 31 | 32 | private EmoteDto? _lastEmote; 33 | private readonly object _emoteLock = new(); 34 | 35 | private Plugin() 36 | { 37 | } 38 | 39 | public void UpdateLastEmote(string username, string emote) 40 | { 41 | LastEmote = new EmoteDto(username, emote); 42 | } 43 | 44 | public Func BuildController() 45 | { 46 | return () => new EmoteController(Instance); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/Server/Plugins.EmoteServer.cs: -------------------------------------------------------------------------------- 1 | // This file is automatically generated 2 | 3 | #pragma warning disable CS8618 4 | #pragma warning disable CS0219 5 | 6 | using CyberpunkSdk; 7 | using CyberpunkSdk.Types; 8 | 9 | using CyberpunkSdk.Systems; 10 | 11 | using CyberpunkSdk.Internal; 12 | 13 | namespace Cyberpunk.Rpc.Server.Plugins 14 | { 15 | public static partial class EmoteServer 16 | { 17 | [ServerRpc(Class = 16273172002596938280, Function = 8330132648100619273)] 18 | public static void TriggerEmote(ulong playerId, IBuffer data) 19 | { 20 | ushort length = 0; 21 | var name = data.ReadString(); 22 | 23 | TriggerEmote_Impl(playerId, name); 24 | } 25 | 26 | public static partial void TriggerEmote_Impl(ulong playerId, string name); 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/ServerImpl.cs: -------------------------------------------------------------------------------- 1 | using CurseForge.APIClient.Models.Games; 2 | using Cyberpunk.Rpc.Client.Plugins; 3 | using CyberpunkSdk; 4 | using EmoteSystem; 5 | 6 | namespace Cyberpunk.Rpc.Server.Plugins 7 | { 8 | public static partial class EmoteServer 9 | { 10 | public static partial void TriggerEmote_Impl(ulong playerId, string name) 11 | { 12 | var player = CyberpunkSdk.Server.PlayerSystem.GetById(playerId); 13 | 14 | foreach(var id in CyberpunkSdk.Server.PlayerSystem.PlayerIds) 15 | { 16 | //if (id == playerId) 17 | // continue; 18 | 19 | EmoteClient.TriggerEmote(id, player.PuppetId, name); 20 | } 21 | Plugin.Instance.UpdateLastEmote(player.Username, name); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/server/scripting/EmoteSystem/WebApi.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk; 2 | using EmbedIO; 3 | using EmbedIO.Routing; 4 | 5 | namespace EmoteSystem; 6 | 7 | public record EmoteDto(string Username, string Emote); 8 | 9 | internal class EmoteController : PluginWebApiController 10 | { 11 | private readonly Plugin _plugin; 12 | 13 | internal EmoteController(Plugin plugin) 14 | { 15 | _plugin = plugin; 16 | } 17 | 18 | [Route(HttpVerbs.Get, "/")] 19 | public EmoteDto GetLastEmote() 20 | { 21 | var lastEmote = _plugin.LastEmote; 22 | 23 | if (lastEmote == null) 24 | { 25 | throw HttpException.NotFound(); 26 | } 27 | 28 | return lastEmote; 29 | } 30 | } -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/Client/Plugins.JobsClient.cs: -------------------------------------------------------------------------------- 1 | // This file is automatically generated 2 | 3 | #pragma warning disable CS8618 4 | #pragma warning disable CS0219 5 | 6 | using CyberpunkSdk; 7 | using CyberpunkSdk.Types; 8 | 9 | using CyberpunkSdk.Systems; 10 | 11 | using CyberpunkSdk.Internal; 12 | 13 | namespace Cyberpunk.Rpc.Client.Plugins 14 | { 15 | public static class JobsClient 16 | { 17 | [ClientRpc(Class = 1545051913836928782, Function = 3896777535515081057)] 18 | public static void SetActiveJob(ulong playerId, CName job) 19 | { 20 | ushort length = 0; 21 | var data = IBuffer.Create(); 22 | try{ 23 | data.WriteUint64(job.Hash); 24 | CyberpunkSdk.Server.RpcManager.Call(playerId, 1545051913836928782, 3896777535515081057, data); 25 | } finally { 26 | IBuffer.Release(data); 27 | } 28 | } 29 | 30 | } 31 | } -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/Client/Plugins.TaxiRiderClient.cs: -------------------------------------------------------------------------------- 1 | // This file is automatically generated 2 | 3 | #pragma warning disable CS8618 4 | #pragma warning disable CS0219 5 | 6 | using CyberpunkSdk; 7 | using CyberpunkSdk.Types; 8 | 9 | using CyberpunkSdk.Systems; 10 | 11 | using CyberpunkSdk.Internal; 12 | 13 | namespace Cyberpunk.Rpc.Client.Plugins 14 | { 15 | public static class TaxiRiderClient 16 | { 17 | [ClientRpc(Class = 14498540813421764700, Function = 16060324207638237351)] 18 | public static void StartTrip(ulong playerId, ulong vehicle_server_id) 19 | { 20 | ushort length = 0; 21 | var data = IBuffer.Create(); 22 | try{ 23 | data.WriteUint64(vehicle_server_id); 24 | CyberpunkSdk.Server.RpcManager.Call(playerId, 14498540813421764700, 16060324207638237351, data); 25 | } finally { 26 | IBuffer.Release(data); 27 | } 28 | } 29 | 30 | [ClientRpc(Class = 14498540813421764700, Function = 12778657023157887943)] 31 | public static void EndTrip(ulong playerId, bool success, uint cost) 32 | { 33 | ushort length = 0; 34 | var data = IBuffer.Create(); 35 | try{ 36 | data.WriteBool(success); 37 | data.WriteUint32(cost); 38 | CyberpunkSdk.Server.RpcManager.Call(playerId, 14498540813421764700, 12778657023157887943, data); 39 | } finally { 40 | IBuffer.Release(data); 41 | } 42 | } 43 | 44 | } 45 | } -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/Job.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Types; 2 | 3 | namespace JobSystem 4 | { 5 | public abstract class Job 6 | { 7 | public abstract CName Name { get; } 8 | 9 | public ulong Id { get; private set; } 10 | 11 | public Job(ulong id) 12 | { 13 | this.Id = id; 14 | } 15 | 16 | public abstract void Update(float delta); 17 | 18 | public abstract void HeavyUpdate(float delta); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/JobSystem.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ..\..\..\..\build\windows\x64\debug\plugins\JobSystem 15 | ..\..\..\..\build\windows\x64\debug\plugins\JobSystem 16 | 1701;1702;3270 17 | false 18 | false 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/JobSystem.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | <_LastSelectedProfileId>F:\Dev\CyberpunkMP\code\scripting\JobSystem\Properties\PublishProfiles\FolderProfile.pubxml 5 | 6 | -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/Plugin.cs: -------------------------------------------------------------------------------- 1 | namespace JobSystem 2 | { 3 | public class Plugin 4 | { 5 | public static Plugin Instance { get; set; } 6 | internal JobManager JobManager { get; private set; } 7 | 8 | public float Time = 0.0f; 9 | public List PlayerIds = new List(); 10 | 11 | static Plugin() 12 | { 13 | Instance = new Plugin(); 14 | } 15 | 16 | Plugin() 17 | { 18 | JobManager = new JobManager(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/Police.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk.Types; 2 | 3 | namespace JobSystem 4 | { 5 | internal class Police : Job 6 | { 7 | public static readonly CName Job = new("Police"); 8 | 9 | public override CName Name { get { return Job; } } 10 | 11 | public Police(ulong id) : base(id) 12 | { 13 | } 14 | public override void Update(float delta) 15 | { 16 | throw new NotImplementedException(); 17 | } 18 | 19 | public override void HeavyUpdate(float delta) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | Debug 8 | Any CPU 9 | bin\Release\net8.0\publish\ 10 | FileSystem 11 | <_TargetId>Folder 12 | net8.0 13 | false 14 | 15 | -------------------------------------------------------------------------------- /code/server/scripting/JobSystem/Server/Plugins.JobsServer.cs: -------------------------------------------------------------------------------- 1 | // This file is automatically generated 2 | 3 | #pragma warning disable CS8618 4 | #pragma warning disable CS0219 5 | 6 | using CyberpunkSdk; 7 | using CyberpunkSdk.Types; 8 | 9 | using CyberpunkSdk.Systems; 10 | 11 | using CyberpunkSdk.Internal; 12 | 13 | namespace Cyberpunk.Rpc.Server.Plugins 14 | { 15 | public static partial class JobsServer 16 | { 17 | [ServerRpc(Class = 8330855795318389666, Function = 3664815350867387508)] 18 | public static void SelectJob(ulong playerId, IBuffer data) 19 | { 20 | ushort length = 0; 21 | var job = new CName(data.ReadUint64()); 22 | 23 | SelectJob_Impl(playerId, job); 24 | } 25 | 26 | public static partial void SelectJob_Impl(ulong playerId, CName job); 27 | 28 | [ServerRpc(Class = 8330855795318389666, Function = 7008247452236044793)] 29 | public static void QuitJob(ulong playerId, IBuffer data) 30 | { 31 | ushort length = 0; 32 | 33 | QuitJob_Impl(playerId); 34 | } 35 | 36 | public static partial void QuitJob_Impl(ulong playerId); 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /code/server/scripting/SdkGenerator/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ -------------------------------------------------------------------------------- /code/server/scripting/SdkGenerator/SdkGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | x64 9 | 10 | 11 | 12 | 1701;1702 13 | 14 | 15 | 16 | 1701;1702 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /code/server/scripting/VehicleSystem/.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ -------------------------------------------------------------------------------- /code/server/scripting/VehicleSystem/Plugin.cs: -------------------------------------------------------------------------------- 1 | using CyberpunkSdk; 2 | 3 | namespace EmoteSystem 4 | { 5 | public class Plugin 6 | { 7 | public static Plugin Instance { get; set; } 8 | 9 | static Plugin() 10 | { 11 | Instance = new Plugin(); 12 | } 13 | 14 | Plugin() 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /code/server/scripting/VehicleSystem/Server/Plugins.EmoteServer.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS8618 2 | #pragma warning disable CS0219 3 | 4 | using CyberpunkSdk; 5 | using CyberpunkSdk.Types; 6 | 7 | using CyberpunkSdk.Systems; 8 | 9 | using CyberpunkSdk.Internal; 10 | 11 | namespace Cyberpunk.Rpc.Server.Plugins 12 | { 13 | public static partial class EmoteServer 14 | { 15 | [ServerRpc(Class = 16273172002596938280, Function = 8330132648100619273)] 16 | public static void TriggerEmote(ulong playerId, IBuffer data) 17 | { 18 | ushort length = 0; 19 | var name = data.ReadString(); 20 | 21 | TriggerEmote_Impl(playerId, name); 22 | } 23 | 24 | public static partial void TriggerEmote_Impl(ulong playerId, string name); 25 | 26 | } 27 | } -------------------------------------------------------------------------------- /code/server/scripting/VehicleSystem/ServerImpl.cs: -------------------------------------------------------------------------------- 1 | using CurseForge.APIClient.Models.Games; 2 | using Cyberpunk.Rpc.Client.Plugins; 3 | using CyberpunkSdk; 4 | 5 | namespace Cyberpunk.Rpc.Server.Plugins 6 | { 7 | public static partial class EmoteServer 8 | { 9 | public static partial void TriggerEmote_Impl(ulong playerId, string name) 10 | { 11 | var player = CyberpunkSdk.Server.PlayerSystem.GetById(playerId); 12 | 13 | foreach(var id in CyberpunkSdk.Server.PlayerSystem.PlayerIds) 14 | { 15 | //if (id == playerId) 16 | // continue; 17 | 18 | EmoteClient.TriggerEmote(id, player.PuppetId, name); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /code/server/scripting/VehicleSystem/VehicleSystem.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ..\..\..\..\build\windows\x64\debug\plugins\EmoteSystem 15 | ..\..\..\..\build\windows\x64\debug\plugins\EmoteSystem 16 | 1701;1702;3270 17 | false 18 | false 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /code/server/xmake.lua: -------------------------------------------------------------------------------- 1 | includes("native") 2 | includes("loader") 3 | includes("scripting") 4 | includes("admin") 5 | -------------------------------------------------------------------------------- /log.reds: -------------------------------------------------------------------------------- 1 | native func Log(const text: script_ref) -> Void 2 | native func LogWarning(const text: script_ref) -> Void 3 | native func LogError(const text: script_ref) -> Void 4 | 5 | // output goes to CET window 6 | native func LogChannel(channel: CName, const text: script_ref) 7 | native func LogChannelWarning(channel: CName, const text: script_ref) -> Void 8 | native func LogChannelError(channel: CName, const text: script_ref) -> Void 9 | 10 | native func FTLog(const value: script_ref) -> Void 11 | native func FTLogWarning(const value: script_ref) -> Void 12 | native func FTLogError(const value: script_ref) -> Void 13 | 14 | native func Trace() -> Void 15 | native func TraceToString() -> String -------------------------------------------------------------------------------- /tools/VftableCounter.py: -------------------------------------------------------------------------------- 1 | import ida_kernwin 2 | import idaapi 3 | 4 | # Point to the first function address in the vftable 5 | ea = ida_kernwin.get_screen_ea() 6 | vftable_size = 0 7 | 8 | while True: 9 | address = idaapi.get_qword(ea) 10 | 11 | if not idaapi.is_code(idaapi.get_flags(address)): 12 | break 13 | 14 | vftable_size = vftable_size + 1 15 | if vftable_size > 1000: 16 | break 17 | 18 | ea = ea + 8 19 | 20 | print(vftable_size) -------------------------------------------------------------------------------- /tools/csharp/xmake.lua: -------------------------------------------------------------------------------- 1 | rule("csharp") 2 | set_extensions(".csproj") 3 | on_build_file(function (target, sourcefile) 4 | os.runv("dotnet", {"build", sourcefile, "-o", target:targetdir()}) 5 | end) 6 | on_run(function (target, sourcefile) 7 | os.runv("dotnet", {"run", sourcefile, "-o", target:targetdir()}) 8 | end) 9 | on_link(function() end) 10 | rule_end() -------------------------------------------------------------------------------- /vendor/xmake.lua: -------------------------------------------------------------------------------- 1 | target("RED4ext.SDK") 2 | set_kind("static") 3 | set_group("vendor") 4 | add_files("RED4ext.SDK/src/**.cpp") 5 | add_headerfiles("RED4ext.SDK/include/**.hpp") 6 | add_includedirs("RED4ext.SDK/include/", { public = true }) 7 | on_install(function() end) 8 | --------------------------------------------------------------------------------