From 7326bee095ca1fcc003842f0f6ed5ec622695853 Mon Sep 17 00:00:00 2001 From: dreamstalker Date: Mon, 4 May 2015 22:25:41 +0400 Subject: [PATCH] Initial commit --- .gitignore | 16 + build.gradle | 44 + buildSrc/build.gradle | 37 + .../builder/FileSystemTreeBuilder.groovy | 58 + .../dirsync/builder/FileTreeMerger.groovy | 60 + .../dirsync/builder/PostBuildPass.groovy | 22 + .../dirsync/builder/ZipTreeBuilder.groovy | 53 + .../dirsync/merger/FileTreeComparator.groovy | 97 + .../dirsync/merger/FileTreeDiffApplier.groovy | 103 + .../model/synccmd/AbstractSyncCmd.groovy | 4 + .../dirsync/model/synccmd/CopyDirCmd.groovy | 8 + .../dirsync/model/synccmd/CopyFileCmd.groovy | 9 + .../dirsync/model/synccmd/DeleteDirCmd.groovy | 7 + .../model/synccmd/DeleteFileCmd.groovy | 7 + .../model/synccmd/ReplaceFileCmd.groovy | 8 + .../model/tree/AbstractFileTreeNode.groovy | 27 + .../dirsync/model/tree/DirectoryNode.groovy | 42 + .../groovy/dirsync/model/tree/FSMapper.groovy | 50 + .../groovy/dirsync/model/tree/FileNode.groovy | 8 + .../dirsync/model/tree/TreePhysMapper.groovy | 11 + .../groovy/dirsync/model/tree/ZipData.groovy | 9 + .../dirsync/model/tree/ZipTreeMapper.groovy | 72 + .../gradlecpp/CppUnitTestExtension.groovy | 19 + .../groovy/gradlecpp/CppUnitTestPlugin.groovy | 242 + .../gradlecpp/RehldsPlayTestPlugin.groovy | 17 + .../gradlecpp/RehldsPlayTestTask.groovy | 80 + .../groovy/gradlecpp/VelocityUtils.groovy | 38 + .../teamcity/TeamCityIntegration.groovy | 84 + .../rehlds/testdemo/RehldsDemoRunner.groovy | 81 + .../rehlds/testdemo/RehldsTestInfo.groovy | 9 + .../rehlds/testdemo/RehldsTestParser.groovy | 63 + .../src/main/groovy/versioning/GitInfo.groovy | 12 + .../groovy/versioning/GitVersioner.groovy | 41 + .../versioning/RehldsVersionInfo.groovy | 35 + .../dirsync/builder/ZipTreeBuilderTest.groovy | 44 + dep/bzip2/build.gradle | 75 + dep/bzip2/include/bzip2/bzlib.h | 282 + dep/bzip2/msvc/bzip2.vcxproj | 157 + dep/bzip2/msvc/bzip2.vcxproj.filters | 51 + dep/bzip2/src/blocksort.c | 1094 +++ dep/bzip2/src/bzlib.c | 1580 ++++ dep/bzip2/src/bzlib_private.h | 509 ++ dep/bzip2/src/compress.c | 672 ++ dep/bzip2/src/crctable.c | 104 + dep/bzip2/src/decompress.c | 646 ++ dep/bzip2/src/huffman.c | 205 + dep/bzip2/src/precompiled.c | 1 + dep/bzip2/src/randtable.c | 84 + dep/cppunitlite/build.gradle | 60 + .../include/cppunitlite/Assertions.h | 18 + dep/cppunitlite/include/cppunitlite/Failure.h | 53 + .../include/cppunitlite/GradleAdapter.h | 9 + dep/cppunitlite/include/cppunitlite/Test.h | 84 + .../include/cppunitlite/TestHarness.h | 18 + .../include/cppunitlite/TestRegistry.h | 32 + .../include/cppunitlite/TestResult.h | 18 + dep/cppunitlite/msvc/cppunitlite.vcxproj | 156 + .../msvc/cppunitlite.vcxproj.filters | 51 + dep/cppunitlite/src/Assertions.cpp | 56 + dep/cppunitlite/src/GradleAdapter.cpp | 98 + dep/cppunitlite/src/Test.cpp | 41 + dep/cppunitlite/src/TestRegistry.cpp | 50 + dep/cppunitlite/src/TestResult.cpp | 36 + gradle.properties | 2 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 52279 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 + gradlew.bat | 90 + msvc/ReHLDS.sln | 88 + publish.gradle | 132 + rehlds/build.gradle | 382 + rehlds/common/IGameServerData.h | 13 + rehlds/common/Sequence.h | 201 + rehlds/common/SteamCommon.h | 703 ++ rehlds/common/beamdef.h | 62 + rehlds/common/cl_entity.h | 115 + rehlds/common/com_model.h | 340 + rehlds/common/con_nprint.h | 38 + rehlds/common/const.h | 791 ++ rehlds/common/crc.h | 55 + rehlds/common/cvardef.h | 39 + rehlds/common/demo_api.h | 31 + rehlds/common/director_cmds.h | 38 + rehlds/common/dlight.h | 33 + rehlds/common/dll_state.h | 23 + rehlds/common/entity_state.h | 197 + rehlds/common/entity_types.h | 26 + rehlds/common/enums.h | 27 + rehlds/common/event_api.h | 51 + rehlds/common/event_args.h | 50 + rehlds/common/event_flags.h | 47 + rehlds/common/hltv.h | 61 + rehlds/common/in_buttons.h | 38 + rehlds/common/ivoicetweak.h | 38 + rehlds/common/kbutton.h | 44 + rehlds/common/mathlib.h | 49 + rehlds/common/net_api.h | 99 + rehlds/common/netadr.h | 40 + rehlds/common/nowin.h | 16 + rehlds/common/parsemsg.cpp | 259 + rehlds/common/parsemsg.h | 66 + rehlds/common/particledef.h | 57 + rehlds/common/pmtrace.h | 43 + rehlds/common/port.h | 119 + rehlds/common/qfont.h | 41 + rehlds/common/quakedef.h | 41 + rehlds/common/r_efx.h | 197 + rehlds/common/r_studioint.h | 151 + rehlds/common/ref_params.h | 75 + rehlds/common/screenfade.h | 24 + rehlds/common/studio_event.h | 29 + rehlds/common/triangleapi.h | 64 + rehlds/common/usercmd.h | 41 + rehlds/common/vmodes.h | 35 + rehlds/common/weaponinfo.h | 53 + rehlds/common/winsani_in.h | 7 + rehlds/common/winsani_out.h | 4 + rehlds/dlls/activity.h | 109 + rehlds/dlls/activitymap.h | 97 + rehlds/dlls/animation.h | 47 + rehlds/dlls/basemonster.h | 94 + rehlds/dlls/cbase.h | 802 ++ rehlds/dlls/cdll_dll.h | 46 + rehlds/dlls/client.h | 65 + rehlds/dlls/decals.h | 84 + rehlds/dlls/doors.h | 33 + rehlds/dlls/effects.h | 209 + rehlds/dlls/enginecallback.h | 160 + rehlds/dlls/explode.h | 32 + rehlds/dlls/extdll.h | 94 + rehlds/dlls/func_break.h | 74 + rehlds/dlls/game.h | 45 + rehlds/dlls/gamerules.h | 360 + rehlds/dlls/hornet.h | 58 + rehlds/dlls/items.h | 29 + rehlds/dlls/maprules.h | 22 + rehlds/dlls/monsterevent.h | 34 + rehlds/dlls/monsters.h | 183 + rehlds/dlls/nodes.h | 379 + rehlds/dlls/plane.h | 43 + rehlds/dlls/player.h | 336 + rehlds/dlls/saverestore.h | 169 + rehlds/dlls/schedule.h | 290 + rehlds/dlls/scriptevent.h | 29 + rehlds/dlls/skill.h | 147 + rehlds/dlls/soundent.h | 95 + rehlds/dlls/spectator.h | 27 + rehlds/dlls/talkmonster.h | 26 + rehlds/dlls/teamplay_gamerules.h | 57 + rehlds/dlls/trains.h | 127 + rehlds/dlls/util.h | 547 ++ rehlds/dlls/vector.h | 113 + rehlds/dlls/weapons.h | 1019 +++ rehlds/engine/APIProxy.h | 939 +++ rehlds/engine/anorms.h | 177 + rehlds/engine/buildnum.cpp | 77 + rehlds/engine/cdll_int.h | 465 ++ rehlds/engine/cl_null.cpp | 233 + rehlds/engine/client.h | 377 + rehlds/engine/cmd.cpp | 1165 +++ rehlds/engine/cmd.h | 123 + rehlds/engine/cmodel.cpp | 288 + rehlds/engine/cmodel.h | 67 + rehlds/engine/com_custom.cpp | 201 + rehlds/engine/com_custom.h | 43 + rehlds/engine/common.cpp | 2693 +++++++ rehlds/engine/common.h | 297 + rehlds/engine/consistency.h | 48 + rehlds/engine/crc.cpp | 584 ++ rehlds/engine/custom_int.h | 21 + rehlds/engine/cvar.cpp | 735 ++ rehlds/engine/cvar.h | 71 + rehlds/engine/decal.h | 113 + rehlds/engine/decals.cpp | 846 ++ rehlds/engine/delta.cpp | 1538 ++++ rehlds/engine/delta.h | 149 + rehlds/engine/delta_packet.h | 46 + rehlds/engine/ed_strpool.cpp | 89 + rehlds/engine/ed_strpool.h | 8 + rehlds/engine/event.h | 45 + rehlds/engine/filesystem.cpp | 516 ++ rehlds/engine/filesystem_.h | 72 + rehlds/engine/filesystem_internal.cpp | 373 + rehlds/engine/filesystem_internal.h | 93 + rehlds/engine/filter.h | 58 + rehlds/engine/hashpak.cpp | 1382 ++++ rehlds/engine/hashpak.h | 109 + rehlds/engine/host.cpp | 1285 +++ rehlds/engine/host.h | 162 + rehlds/engine/host_cmd.cpp | 3116 +++++++ rehlds/engine/host_cmd.h | 215 + rehlds/engine/iengine.h | 181 + rehlds/engine/igame.h | 102 + rehlds/engine/info.cpp | 618 ++ rehlds/engine/info.h | 56 + rehlds/engine/inst_baseline.h | 47 + rehlds/engine/ipratelimit.cpp | 80 + rehlds/engine/ipratelimit.h | 87 + rehlds/engine/ipratelimitWrapper.cpp | 53 + rehlds/engine/ipratelimitWrapper.h | 46 + rehlds/engine/keys.h | 7 + rehlds/engine/l_studio.cpp | 92 + rehlds/engine/l_studio.h | 49 + rehlds/engine/mathlib.cpp | 467 ++ rehlds/engine/mathlib_e.h | 90 + rehlds/engine/mem.cpp | 68 + rehlds/engine/mem.h | 43 + rehlds/engine/model.cpp | 1903 +++++ rehlds/engine/model_rehlds.h | 116 + rehlds/engine/modinfo.h | 64 + rehlds/engine/module.cpp | 36 + rehlds/engine/net.h | 373 + rehlds/engine/net_chan.cpp | 1721 ++++ rehlds/engine/net_chan.h | 101 + rehlds/engine/net_ws.cpp | 2146 +++++ rehlds/engine/net_ws.h | 281 + rehlds/engine/pmove.cpp | 182 + rehlds/engine/pmove.h | 65 + rehlds/engine/pmovetst.cpp | 789 ++ rehlds/engine/pmovetst.h | 77 + rehlds/engine/pr_cmds.cpp | 2783 +++++++ rehlds/engine/pr_cmds.h | 215 + rehlds/engine/pr_dlls.h | 62 + rehlds/engine/pr_edict.cpp | 647 ++ rehlds/engine/pr_edict.h | 75 + rehlds/engine/r_studio.cpp | 1171 +++ rehlds/engine/server.h | 752 ++ rehlds/engine/server_static.h | 84 + rehlds/engine/snd_null.cpp | 104 + rehlds/engine/sound.h | 74 + rehlds/engine/studio_rehlds.h | 107 + rehlds/engine/sv_log.cpp | 424 + rehlds/engine/sv_log.h | 59 + rehlds/engine/sv_main.cpp | 7132 +++++++++++++++++ rehlds/engine/sv_move.cpp | 571 ++ rehlds/engine/sv_move.h | 60 + rehlds/engine/sv_phys.cpp | 1474 ++++ rehlds/engine/sv_phys.h | 88 + rehlds/engine/sv_pmove.cpp | 59 + rehlds/engine/sv_pmove.h | 42 + rehlds/engine/sv_remoteaccess.cpp | 306 + rehlds/engine/sv_remoteaccess.h | 84 + rehlds/engine/sv_steam3.cpp | 949 +++ rehlds/engine/sv_steam3.h | 233 + rehlds/engine/sv_upld.cpp | 508 ++ rehlds/engine/sv_upld.h | 54 + rehlds/engine/sv_user.cpp | 1791 +++++ rehlds/engine/sv_user.h | 156 + rehlds/engine/sys_dll.cpp | 1400 ++++ rehlds/engine/sys_dll.h | 194 + rehlds/engine/sys_dll2.cpp | 785 ++ rehlds/engine/sys_dll2.h | 122 + rehlds/engine/sys_engine.cpp | 335 + rehlds/engine/sys_engine.h | 137 + rehlds/engine/sys_linuxwind.cpp | 194 + rehlds/engine/sys_linuxwnd.h | 85 + rehlds/engine/textures.cpp | 245 + rehlds/engine/textures.h | 84 + rehlds/engine/tmessage.cpp | 516 ++ rehlds/engine/tmessage.h | 81 + rehlds/engine/traceinit.cpp | 123 + rehlds/engine/traceinit.h | 84 + rehlds/engine/unicode_strtools.cpp | 488 ++ rehlds/engine/unicode_strtools.h | 66 + rehlds/engine/userid.h | 32 + rehlds/engine/usermsg.h | 49 + rehlds/engine/vid_null.cpp | 135 + rehlds/engine/vid_null.h | 62 + rehlds/engine/wad.cpp | 164 + rehlds/engine/wad.h | 98 + rehlds/engine/world.cpp | 1154 +++ rehlds/engine/world.h | 127 + rehlds/engine/zone.cpp | 1205 +++ rehlds/engine/zone.h | 110 + rehlds/hookers/6132_hooker.cpp | 2549 ++++++ rehlds/hookers/engine.h | 84 + rehlds/hookers/hooker.cpp | 184 + rehlds/hookers/hooker.h | 8 + rehlds/hookers/main.cpp | 120 + rehlds/hookers/main_swds.cpp | 68 + rehlds/hookers/memory.cpp | 768 ++ rehlds/hookers/memory.h | 139 + rehlds/hookers/rehlds_debug.cpp | 652 ++ rehlds/hookers/rehlds_debug.h | 46 + rehlds/lib/linux32/libsteam_api.so | Bin 0 -> 76032 bytes rehlds/lib/steam_api.dll | Bin 0 -> 103920 bytes rehlds/lib/steam_api.lib | Bin 0 -> 15118 bytes rehlds/msvc/PostBuild.bat | 39 + rehlds/msvc/PostBuild_swds.bat | 39 + rehlds/msvc/PreBuild.bat | 205 + rehlds/msvc/ReHLDS.vcxproj | 873 ++ rehlds/msvc/ReHLDS.vcxproj.filters | 1041 +++ rehlds/pm_shared/pm_debug.h | 26 + rehlds/pm_shared/pm_defs.h | 228 + rehlds/pm_shared/pm_info.h | 25 + rehlds/pm_shared/pm_materials.h | 36 + rehlds/pm_shared/pm_movevars.h | 47 + rehlds/pm_shared/pm_shared.h | 38 + rehlds/public/FileSystem.h | 189 + rehlds/public/archtypes.h | 21 + rehlds/public/basetypes.h | 300 + rehlds/public/cl_dll/IGameClientExports.h | 34 + rehlds/public/commonmacros.h | 30 + rehlds/public/engine_hlds_api.h | 47 + rehlds/public/engine_launcher_api.h | 47 + rehlds/public/idedicatedexports.h | 25 + rehlds/public/interface.cpp | 263 + rehlds/public/interface.h | 150 + rehlds/public/iregistry.h | 40 + rehlds/public/keydefs.h | 124 + rehlds/public/particleman.h | 101 + rehlds/public/pman_particlemem.h | 197 + rehlds/public/pman_triangleffect.h | 209 + rehlds/public/protected_things.h | 187 + rehlds/public/registry.cpp | 264 + rehlds/public/rehlds/FlightRecorder.h | 61 + rehlds/public/rehlds/Sequence.h | 201 + rehlds/public/rehlds/archtypes.h | 63 + rehlds/public/rehlds/bspfile.h | 169 + rehlds/public/rehlds/cmd_rehlds.h | 53 + rehlds/public/rehlds/common_rehlds.h | 76 + rehlds/public/rehlds/crc32.cpp | 132 + rehlds/public/rehlds/crc32.h | 21 + rehlds/public/rehlds/custom.h | 92 + rehlds/public/rehlds/customentity.h | 38 + rehlds/public/rehlds/d_local.h | 46 + rehlds/public/rehlds/edict.h | 36 + rehlds/public/rehlds/eiface.h | 536 ++ rehlds/public/rehlds/hookchains.h | 67 + rehlds/public/rehlds/keydefs.h | 131 + rehlds/public/rehlds/maintypes.h | 58 + rehlds/public/rehlds/model.h | 415 + rehlds/public/rehlds/modelgen.h | 144 + rehlds/public/rehlds/osconfig.h | 199 + rehlds/public/rehlds/progdefs.h | 224 + rehlds/public/rehlds/progs.h | 82 + rehlds/public/rehlds/rehlds_api.h | 177 + rehlds/public/rehlds/rehlds_interfaces.h | 105 + rehlds/public/rehlds/shake.h | 57 + rehlds/public/rehlds/spritegn.h | 90 + rehlds/public/rehlds/static_map.h | 204 + rehlds/public/rehlds/studio.h | 358 + rehlds/public/rehlds/sys_shared.cpp | 45 + rehlds/public/rehlds/sys_shared.h | 31 + rehlds/public/rehlds/userid_rehlds.h | 39 + rehlds/public/savegame_version.h | 17 + rehlds/public/steam/isteamapps.h | 127 + rehlds/public/steam/isteambilling.h | 108 + rehlds/public/steam/isteamclient.h | 349 + rehlds/public/steam/isteamcontroller.h | 62 + rehlds/public/steam/isteamfriends.h | 606 ++ rehlds/public/steam/isteamgameserver.h | 391 + rehlds/public/steam/isteamgameserverstats.h | 99 + rehlds/public/steam/isteamhttp.h | 176 + rehlds/public/steam/isteammatchmaking.h | 731 ++ rehlds/public/steam/isteamnetworking.h | 306 + rehlds/public/steam/isteamremotestorage.h | 610 ++ rehlds/public/steam/isteamscreenshots.h | 96 + rehlds/public/steam/isteamunifiedmessages.h | 63 + rehlds/public/steam/isteamuser.h | 339 + rehlds/public/steam/isteamuserstats.h | 463 ++ rehlds/public/steam/isteamutils.h | 304 + rehlds/public/steam/matchmakingtypes.h | 249 + rehlds/public/steam/steam_api.h | 536 ++ rehlds/public/steam/steam_gameserver.h | 163 + rehlds/public/steam/steamclientpublic.h | 1086 +++ rehlds/public/steam/steamhttpenums.h | 94 + rehlds/public/steam/steamtypes.h | 136 + rehlds/public/steamid.cpp | 32 + rehlds/public/string_t.h | 106 + rehlds/public/tier0/dbg.cpp | 435 + rehlds/public/tier0/dbg.h | 453 ++ rehlds/public/tier0/fasttimer.h | 424 + rehlds/public/tier0/mem.h | 37 + rehlds/public/tier0/memalloc.h | 77 + rehlds/public/tier0/memdbgoff.h | 21 + rehlds/public/tier0/memdbgon.h | 93 + rehlds/public/tier0/platform.h | 651 ++ rehlds/public/tier0/platform_linux.cpp | 59 + rehlds/public/tier0/platform_win32.cpp | 88 + rehlds/public/utlbuffer.cpp | 419 + rehlds/public/utlbuffer.h | 341 + rehlds/public/utllinkedlist.h | 693 ++ rehlds/public/utlmemory.h | 323 + rehlds/public/utlrbtree.h | 1295 +++ rehlds/public/utlvector.h | 594 ++ rehlds/rehlds/FlightRecorderImpl.cpp | 224 + rehlds/rehlds/FlightRecorderImpl.h | 110 + rehlds/rehlds/RehldsRuntimeConfig.cpp | 113 + rehlds/rehlds/RehldsRuntimeConfig.h | 24 + rehlds/rehlds/flight_recorder.cpp | 56 + rehlds/rehlds/flight_recorder.h | 33 + rehlds/rehlds/hookchains_impl.cpp | 51 + rehlds/rehlds/hookchains_impl.h | 161 + rehlds/rehlds/platform.cpp | 211 + rehlds/rehlds/platform.h | 121 + rehlds/rehlds/precompiled.cpp | 1 + rehlds/rehlds/precompiled.h | 51 + rehlds/rehlds/rehlds_api_impl.cpp | 220 + rehlds/rehlds/rehlds_api_impl.h | 173 + rehlds/rehlds/rehlds_interfaces_impl.cpp | 191 + rehlds/rehlds/rehlds_interfaces_impl.h | 104 + rehlds/rehlds/structSizeCheck.cpp | 19 + rehlds/testsuite/anonymizer.cpp | 1042 +++ rehlds/testsuite/anonymizer.h | 229 + rehlds/testsuite/funccalls.cpp | 3288 ++++++++ rehlds/testsuite/funccalls.h | 1272 +++ rehlds/testsuite/player.cpp | 1071 +++ rehlds/testsuite/player.h | 202 + rehlds/testsuite/recorder.cpp | 996 +++ rehlds/testsuite/recorder.h | 201 + rehlds/testsuite/testsuite.cpp | 529 ++ rehlds/testsuite/testsuite.h | 18 + rehlds/unittests/TestRunner.cpp | 15 + rehlds/unittests/common_tests.cpp | 89 + rehlds/unittests/struct_offsets_tests.cpp | 43 + rehlds/unittests/tmessage_tests.cpp | 11 + rehlds/version/appversion.vm | 20 + rehlds/version/version.cpp | 10 + settings.gradle | 4 + shared.gradle | 33 + shared_icc.gradle | 60 + shared_msvc.gradle | 123 + 423 files changed, 113935 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/src/main/groovy/dirsync/builder/FileSystemTreeBuilder.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/builder/FileTreeMerger.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/builder/PostBuildPass.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/builder/ZipTreeBuilder.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/merger/FileTreeComparator.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/merger/FileTreeDiffApplier.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/synccmd/AbstractSyncCmd.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/synccmd/CopyDirCmd.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/synccmd/CopyFileCmd.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteDirCmd.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteFileCmd.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/synccmd/ReplaceFileCmd.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/tree/AbstractFileTreeNode.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/tree/DirectoryNode.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/tree/FSMapper.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/tree/FileNode.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/tree/TreePhysMapper.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/tree/ZipData.groovy create mode 100644 buildSrc/src/main/groovy/dirsync/model/tree/ZipTreeMapper.groovy create mode 100644 buildSrc/src/main/groovy/gradlecpp/CppUnitTestExtension.groovy create mode 100644 buildSrc/src/main/groovy/gradlecpp/CppUnitTestPlugin.groovy create mode 100644 buildSrc/src/main/groovy/gradlecpp/RehldsPlayTestPlugin.groovy create mode 100644 buildSrc/src/main/groovy/gradlecpp/RehldsPlayTestTask.groovy create mode 100644 buildSrc/src/main/groovy/gradlecpp/VelocityUtils.groovy create mode 100644 buildSrc/src/main/groovy/gradlecpp/teamcity/TeamCityIntegration.groovy create mode 100644 buildSrc/src/main/groovy/rehlds/testdemo/RehldsDemoRunner.groovy create mode 100644 buildSrc/src/main/groovy/rehlds/testdemo/RehldsTestInfo.groovy create mode 100644 buildSrc/src/main/groovy/rehlds/testdemo/RehldsTestParser.groovy create mode 100644 buildSrc/src/main/groovy/versioning/GitInfo.groovy create mode 100644 buildSrc/src/main/groovy/versioning/GitVersioner.groovy create mode 100644 buildSrc/src/main/groovy/versioning/RehldsVersionInfo.groovy create mode 100644 buildSrc/src/test/groovy/dirsync/builder/ZipTreeBuilderTest.groovy create mode 100644 dep/bzip2/build.gradle create mode 100644 dep/bzip2/include/bzip2/bzlib.h create mode 100644 dep/bzip2/msvc/bzip2.vcxproj create mode 100644 dep/bzip2/msvc/bzip2.vcxproj.filters create mode 100644 dep/bzip2/src/blocksort.c create mode 100644 dep/bzip2/src/bzlib.c create mode 100644 dep/bzip2/src/bzlib_private.h create mode 100644 dep/bzip2/src/compress.c create mode 100644 dep/bzip2/src/crctable.c create mode 100644 dep/bzip2/src/decompress.c create mode 100644 dep/bzip2/src/huffman.c create mode 100644 dep/bzip2/src/precompiled.c create mode 100644 dep/bzip2/src/randtable.c create mode 100644 dep/cppunitlite/build.gradle create mode 100644 dep/cppunitlite/include/cppunitlite/Assertions.h create mode 100644 dep/cppunitlite/include/cppunitlite/Failure.h create mode 100644 dep/cppunitlite/include/cppunitlite/GradleAdapter.h create mode 100644 dep/cppunitlite/include/cppunitlite/Test.h create mode 100644 dep/cppunitlite/include/cppunitlite/TestHarness.h create mode 100644 dep/cppunitlite/include/cppunitlite/TestRegistry.h create mode 100644 dep/cppunitlite/include/cppunitlite/TestResult.h create mode 100644 dep/cppunitlite/msvc/cppunitlite.vcxproj create mode 100644 dep/cppunitlite/msvc/cppunitlite.vcxproj.filters create mode 100644 dep/cppunitlite/src/Assertions.cpp create mode 100644 dep/cppunitlite/src/GradleAdapter.cpp create mode 100644 dep/cppunitlite/src/Test.cpp create mode 100644 dep/cppunitlite/src/TestRegistry.cpp create mode 100644 dep/cppunitlite/src/TestResult.cpp create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 msvc/ReHLDS.sln create mode 100644 publish.gradle create mode 100644 rehlds/build.gradle create mode 100644 rehlds/common/IGameServerData.h create mode 100644 rehlds/common/Sequence.h create mode 100644 rehlds/common/SteamCommon.h create mode 100644 rehlds/common/beamdef.h create mode 100644 rehlds/common/cl_entity.h create mode 100644 rehlds/common/com_model.h create mode 100644 rehlds/common/con_nprint.h create mode 100644 rehlds/common/const.h create mode 100644 rehlds/common/crc.h create mode 100644 rehlds/common/cvardef.h create mode 100644 rehlds/common/demo_api.h create mode 100644 rehlds/common/director_cmds.h create mode 100644 rehlds/common/dlight.h create mode 100644 rehlds/common/dll_state.h create mode 100644 rehlds/common/entity_state.h create mode 100644 rehlds/common/entity_types.h create mode 100644 rehlds/common/enums.h create mode 100644 rehlds/common/event_api.h create mode 100644 rehlds/common/event_args.h create mode 100644 rehlds/common/event_flags.h create mode 100644 rehlds/common/hltv.h create mode 100644 rehlds/common/in_buttons.h create mode 100644 rehlds/common/ivoicetweak.h create mode 100644 rehlds/common/kbutton.h create mode 100644 rehlds/common/mathlib.h create mode 100644 rehlds/common/net_api.h create mode 100644 rehlds/common/netadr.h create mode 100644 rehlds/common/nowin.h create mode 100644 rehlds/common/parsemsg.cpp create mode 100644 rehlds/common/parsemsg.h create mode 100644 rehlds/common/particledef.h create mode 100644 rehlds/common/pmtrace.h create mode 100644 rehlds/common/port.h create mode 100644 rehlds/common/qfont.h create mode 100644 rehlds/common/quakedef.h create mode 100644 rehlds/common/r_efx.h create mode 100644 rehlds/common/r_studioint.h create mode 100644 rehlds/common/ref_params.h create mode 100644 rehlds/common/screenfade.h create mode 100644 rehlds/common/studio_event.h create mode 100644 rehlds/common/triangleapi.h create mode 100644 rehlds/common/usercmd.h create mode 100644 rehlds/common/vmodes.h create mode 100644 rehlds/common/weaponinfo.h create mode 100644 rehlds/common/winsani_in.h create mode 100644 rehlds/common/winsani_out.h create mode 100644 rehlds/dlls/activity.h create mode 100644 rehlds/dlls/activitymap.h create mode 100644 rehlds/dlls/animation.h create mode 100644 rehlds/dlls/basemonster.h create mode 100644 rehlds/dlls/cbase.h create mode 100644 rehlds/dlls/cdll_dll.h create mode 100644 rehlds/dlls/client.h create mode 100644 rehlds/dlls/decals.h create mode 100644 rehlds/dlls/doors.h create mode 100644 rehlds/dlls/effects.h create mode 100644 rehlds/dlls/enginecallback.h create mode 100644 rehlds/dlls/explode.h create mode 100644 rehlds/dlls/extdll.h create mode 100644 rehlds/dlls/func_break.h create mode 100644 rehlds/dlls/game.h create mode 100644 rehlds/dlls/gamerules.h create mode 100644 rehlds/dlls/hornet.h create mode 100644 rehlds/dlls/items.h create mode 100644 rehlds/dlls/maprules.h create mode 100644 rehlds/dlls/monsterevent.h create mode 100644 rehlds/dlls/monsters.h create mode 100644 rehlds/dlls/nodes.h create mode 100644 rehlds/dlls/plane.h create mode 100644 rehlds/dlls/player.h create mode 100644 rehlds/dlls/saverestore.h create mode 100644 rehlds/dlls/schedule.h create mode 100644 rehlds/dlls/scriptevent.h create mode 100644 rehlds/dlls/skill.h create mode 100644 rehlds/dlls/soundent.h create mode 100644 rehlds/dlls/spectator.h create mode 100644 rehlds/dlls/talkmonster.h create mode 100644 rehlds/dlls/teamplay_gamerules.h create mode 100644 rehlds/dlls/trains.h create mode 100644 rehlds/dlls/util.h create mode 100644 rehlds/dlls/vector.h create mode 100644 rehlds/dlls/weapons.h create mode 100644 rehlds/engine/APIProxy.h create mode 100644 rehlds/engine/anorms.h create mode 100644 rehlds/engine/buildnum.cpp create mode 100644 rehlds/engine/cdll_int.h create mode 100644 rehlds/engine/cl_null.cpp create mode 100644 rehlds/engine/client.h create mode 100644 rehlds/engine/cmd.cpp create mode 100644 rehlds/engine/cmd.h create mode 100644 rehlds/engine/cmodel.cpp create mode 100644 rehlds/engine/cmodel.h create mode 100644 rehlds/engine/com_custom.cpp create mode 100644 rehlds/engine/com_custom.h create mode 100644 rehlds/engine/common.cpp create mode 100644 rehlds/engine/common.h create mode 100644 rehlds/engine/consistency.h create mode 100644 rehlds/engine/crc.cpp create mode 100644 rehlds/engine/custom_int.h create mode 100644 rehlds/engine/cvar.cpp create mode 100644 rehlds/engine/cvar.h create mode 100644 rehlds/engine/decal.h create mode 100644 rehlds/engine/decals.cpp create mode 100644 rehlds/engine/delta.cpp create mode 100644 rehlds/engine/delta.h create mode 100644 rehlds/engine/delta_packet.h create mode 100644 rehlds/engine/ed_strpool.cpp create mode 100644 rehlds/engine/ed_strpool.h create mode 100644 rehlds/engine/event.h create mode 100644 rehlds/engine/filesystem.cpp create mode 100644 rehlds/engine/filesystem_.h create mode 100644 rehlds/engine/filesystem_internal.cpp create mode 100644 rehlds/engine/filesystem_internal.h create mode 100644 rehlds/engine/filter.h create mode 100644 rehlds/engine/hashpak.cpp create mode 100644 rehlds/engine/hashpak.h create mode 100644 rehlds/engine/host.cpp create mode 100644 rehlds/engine/host.h create mode 100644 rehlds/engine/host_cmd.cpp create mode 100644 rehlds/engine/host_cmd.h create mode 100644 rehlds/engine/iengine.h create mode 100644 rehlds/engine/igame.h create mode 100644 rehlds/engine/info.cpp create mode 100644 rehlds/engine/info.h create mode 100644 rehlds/engine/inst_baseline.h create mode 100644 rehlds/engine/ipratelimit.cpp create mode 100644 rehlds/engine/ipratelimit.h create mode 100644 rehlds/engine/ipratelimitWrapper.cpp create mode 100644 rehlds/engine/ipratelimitWrapper.h create mode 100644 rehlds/engine/keys.h create mode 100644 rehlds/engine/l_studio.cpp create mode 100644 rehlds/engine/l_studio.h create mode 100644 rehlds/engine/mathlib.cpp create mode 100644 rehlds/engine/mathlib_e.h create mode 100644 rehlds/engine/mem.cpp create mode 100644 rehlds/engine/mem.h create mode 100644 rehlds/engine/model.cpp create mode 100644 rehlds/engine/model_rehlds.h create mode 100644 rehlds/engine/modinfo.h create mode 100644 rehlds/engine/module.cpp create mode 100644 rehlds/engine/net.h create mode 100644 rehlds/engine/net_chan.cpp create mode 100644 rehlds/engine/net_chan.h create mode 100644 rehlds/engine/net_ws.cpp create mode 100644 rehlds/engine/net_ws.h create mode 100644 rehlds/engine/pmove.cpp create mode 100644 rehlds/engine/pmove.h create mode 100644 rehlds/engine/pmovetst.cpp create mode 100644 rehlds/engine/pmovetst.h create mode 100644 rehlds/engine/pr_cmds.cpp create mode 100644 rehlds/engine/pr_cmds.h create mode 100644 rehlds/engine/pr_dlls.h create mode 100644 rehlds/engine/pr_edict.cpp create mode 100644 rehlds/engine/pr_edict.h create mode 100644 rehlds/engine/r_studio.cpp create mode 100644 rehlds/engine/server.h create mode 100644 rehlds/engine/server_static.h create mode 100644 rehlds/engine/snd_null.cpp create mode 100644 rehlds/engine/sound.h create mode 100644 rehlds/engine/studio_rehlds.h create mode 100644 rehlds/engine/sv_log.cpp create mode 100644 rehlds/engine/sv_log.h create mode 100644 rehlds/engine/sv_main.cpp create mode 100644 rehlds/engine/sv_move.cpp create mode 100644 rehlds/engine/sv_move.h create mode 100644 rehlds/engine/sv_phys.cpp create mode 100644 rehlds/engine/sv_phys.h create mode 100644 rehlds/engine/sv_pmove.cpp create mode 100644 rehlds/engine/sv_pmove.h create mode 100644 rehlds/engine/sv_remoteaccess.cpp create mode 100644 rehlds/engine/sv_remoteaccess.h create mode 100644 rehlds/engine/sv_steam3.cpp create mode 100644 rehlds/engine/sv_steam3.h create mode 100644 rehlds/engine/sv_upld.cpp create mode 100644 rehlds/engine/sv_upld.h create mode 100644 rehlds/engine/sv_user.cpp create mode 100644 rehlds/engine/sv_user.h create mode 100644 rehlds/engine/sys_dll.cpp create mode 100644 rehlds/engine/sys_dll.h create mode 100644 rehlds/engine/sys_dll2.cpp create mode 100644 rehlds/engine/sys_dll2.h create mode 100644 rehlds/engine/sys_engine.cpp create mode 100644 rehlds/engine/sys_engine.h create mode 100644 rehlds/engine/sys_linuxwind.cpp create mode 100644 rehlds/engine/sys_linuxwnd.h create mode 100644 rehlds/engine/textures.cpp create mode 100644 rehlds/engine/textures.h create mode 100644 rehlds/engine/tmessage.cpp create mode 100644 rehlds/engine/tmessage.h create mode 100644 rehlds/engine/traceinit.cpp create mode 100644 rehlds/engine/traceinit.h create mode 100644 rehlds/engine/unicode_strtools.cpp create mode 100644 rehlds/engine/unicode_strtools.h create mode 100644 rehlds/engine/userid.h create mode 100644 rehlds/engine/usermsg.h create mode 100644 rehlds/engine/vid_null.cpp create mode 100644 rehlds/engine/vid_null.h create mode 100644 rehlds/engine/wad.cpp create mode 100644 rehlds/engine/wad.h create mode 100644 rehlds/engine/world.cpp create mode 100644 rehlds/engine/world.h create mode 100644 rehlds/engine/zone.cpp create mode 100644 rehlds/engine/zone.h create mode 100644 rehlds/hookers/6132_hooker.cpp create mode 100644 rehlds/hookers/engine.h create mode 100644 rehlds/hookers/hooker.cpp create mode 100644 rehlds/hookers/hooker.h create mode 100644 rehlds/hookers/main.cpp create mode 100644 rehlds/hookers/main_swds.cpp create mode 100644 rehlds/hookers/memory.cpp create mode 100644 rehlds/hookers/memory.h create mode 100644 rehlds/hookers/rehlds_debug.cpp create mode 100644 rehlds/hookers/rehlds_debug.h create mode 100644 rehlds/lib/linux32/libsteam_api.so create mode 100644 rehlds/lib/steam_api.dll create mode 100644 rehlds/lib/steam_api.lib create mode 100644 rehlds/msvc/PostBuild.bat create mode 100644 rehlds/msvc/PostBuild_swds.bat create mode 100644 rehlds/msvc/PreBuild.bat create mode 100644 rehlds/msvc/ReHLDS.vcxproj create mode 100644 rehlds/msvc/ReHLDS.vcxproj.filters create mode 100644 rehlds/pm_shared/pm_debug.h create mode 100644 rehlds/pm_shared/pm_defs.h create mode 100644 rehlds/pm_shared/pm_info.h create mode 100644 rehlds/pm_shared/pm_materials.h create mode 100644 rehlds/pm_shared/pm_movevars.h create mode 100644 rehlds/pm_shared/pm_shared.h create mode 100644 rehlds/public/FileSystem.h create mode 100644 rehlds/public/archtypes.h create mode 100644 rehlds/public/basetypes.h create mode 100644 rehlds/public/cl_dll/IGameClientExports.h create mode 100644 rehlds/public/commonmacros.h create mode 100644 rehlds/public/engine_hlds_api.h create mode 100644 rehlds/public/engine_launcher_api.h create mode 100644 rehlds/public/idedicatedexports.h create mode 100644 rehlds/public/interface.cpp create mode 100644 rehlds/public/interface.h create mode 100644 rehlds/public/iregistry.h create mode 100644 rehlds/public/keydefs.h create mode 100644 rehlds/public/particleman.h create mode 100644 rehlds/public/pman_particlemem.h create mode 100644 rehlds/public/pman_triangleffect.h create mode 100644 rehlds/public/protected_things.h create mode 100644 rehlds/public/registry.cpp create mode 100644 rehlds/public/rehlds/FlightRecorder.h create mode 100644 rehlds/public/rehlds/Sequence.h create mode 100644 rehlds/public/rehlds/archtypes.h create mode 100644 rehlds/public/rehlds/bspfile.h create mode 100644 rehlds/public/rehlds/cmd_rehlds.h create mode 100644 rehlds/public/rehlds/common_rehlds.h create mode 100644 rehlds/public/rehlds/crc32.cpp create mode 100644 rehlds/public/rehlds/crc32.h create mode 100644 rehlds/public/rehlds/custom.h create mode 100644 rehlds/public/rehlds/customentity.h create mode 100644 rehlds/public/rehlds/d_local.h create mode 100644 rehlds/public/rehlds/edict.h create mode 100644 rehlds/public/rehlds/eiface.h create mode 100644 rehlds/public/rehlds/hookchains.h create mode 100644 rehlds/public/rehlds/keydefs.h create mode 100644 rehlds/public/rehlds/maintypes.h create mode 100644 rehlds/public/rehlds/model.h create mode 100644 rehlds/public/rehlds/modelgen.h create mode 100644 rehlds/public/rehlds/osconfig.h create mode 100644 rehlds/public/rehlds/progdefs.h create mode 100644 rehlds/public/rehlds/progs.h create mode 100644 rehlds/public/rehlds/rehlds_api.h create mode 100644 rehlds/public/rehlds/rehlds_interfaces.h create mode 100644 rehlds/public/rehlds/shake.h create mode 100644 rehlds/public/rehlds/spritegn.h create mode 100644 rehlds/public/rehlds/static_map.h create mode 100644 rehlds/public/rehlds/studio.h create mode 100644 rehlds/public/rehlds/sys_shared.cpp create mode 100644 rehlds/public/rehlds/sys_shared.h create mode 100644 rehlds/public/rehlds/userid_rehlds.h create mode 100644 rehlds/public/savegame_version.h create mode 100644 rehlds/public/steam/isteamapps.h create mode 100644 rehlds/public/steam/isteambilling.h create mode 100644 rehlds/public/steam/isteamclient.h create mode 100644 rehlds/public/steam/isteamcontroller.h create mode 100644 rehlds/public/steam/isteamfriends.h create mode 100644 rehlds/public/steam/isteamgameserver.h create mode 100644 rehlds/public/steam/isteamgameserverstats.h create mode 100644 rehlds/public/steam/isteamhttp.h create mode 100644 rehlds/public/steam/isteammatchmaking.h create mode 100644 rehlds/public/steam/isteamnetworking.h create mode 100644 rehlds/public/steam/isteamremotestorage.h create mode 100644 rehlds/public/steam/isteamscreenshots.h create mode 100644 rehlds/public/steam/isteamunifiedmessages.h create mode 100644 rehlds/public/steam/isteamuser.h create mode 100644 rehlds/public/steam/isteamuserstats.h create mode 100644 rehlds/public/steam/isteamutils.h create mode 100644 rehlds/public/steam/matchmakingtypes.h create mode 100644 rehlds/public/steam/steam_api.h create mode 100644 rehlds/public/steam/steam_gameserver.h create mode 100644 rehlds/public/steam/steamclientpublic.h create mode 100644 rehlds/public/steam/steamhttpenums.h create mode 100644 rehlds/public/steam/steamtypes.h create mode 100644 rehlds/public/steamid.cpp create mode 100644 rehlds/public/string_t.h create mode 100644 rehlds/public/tier0/dbg.cpp create mode 100644 rehlds/public/tier0/dbg.h create mode 100644 rehlds/public/tier0/fasttimer.h create mode 100644 rehlds/public/tier0/mem.h create mode 100644 rehlds/public/tier0/memalloc.h create mode 100644 rehlds/public/tier0/memdbgoff.h create mode 100644 rehlds/public/tier0/memdbgon.h create mode 100644 rehlds/public/tier0/platform.h create mode 100644 rehlds/public/tier0/platform_linux.cpp create mode 100644 rehlds/public/tier0/platform_win32.cpp create mode 100644 rehlds/public/utlbuffer.cpp create mode 100644 rehlds/public/utlbuffer.h create mode 100644 rehlds/public/utllinkedlist.h create mode 100644 rehlds/public/utlmemory.h create mode 100644 rehlds/public/utlrbtree.h create mode 100644 rehlds/public/utlvector.h create mode 100644 rehlds/rehlds/FlightRecorderImpl.cpp create mode 100644 rehlds/rehlds/FlightRecorderImpl.h create mode 100644 rehlds/rehlds/RehldsRuntimeConfig.cpp create mode 100644 rehlds/rehlds/RehldsRuntimeConfig.h create mode 100644 rehlds/rehlds/flight_recorder.cpp create mode 100644 rehlds/rehlds/flight_recorder.h create mode 100644 rehlds/rehlds/hookchains_impl.cpp create mode 100644 rehlds/rehlds/hookchains_impl.h create mode 100644 rehlds/rehlds/platform.cpp create mode 100644 rehlds/rehlds/platform.h create mode 100644 rehlds/rehlds/precompiled.cpp create mode 100644 rehlds/rehlds/precompiled.h create mode 100644 rehlds/rehlds/rehlds_api_impl.cpp create mode 100644 rehlds/rehlds/rehlds_api_impl.h create mode 100644 rehlds/rehlds/rehlds_interfaces_impl.cpp create mode 100644 rehlds/rehlds/rehlds_interfaces_impl.h create mode 100644 rehlds/rehlds/structSizeCheck.cpp create mode 100644 rehlds/testsuite/anonymizer.cpp create mode 100644 rehlds/testsuite/anonymizer.h create mode 100644 rehlds/testsuite/funccalls.cpp create mode 100644 rehlds/testsuite/funccalls.h create mode 100644 rehlds/testsuite/player.cpp create mode 100644 rehlds/testsuite/player.h create mode 100644 rehlds/testsuite/recorder.cpp create mode 100644 rehlds/testsuite/recorder.h create mode 100644 rehlds/testsuite/testsuite.cpp create mode 100644 rehlds/testsuite/testsuite.h create mode 100644 rehlds/unittests/TestRunner.cpp create mode 100644 rehlds/unittests/common_tests.cpp create mode 100644 rehlds/unittests/struct_offsets_tests.cpp create mode 100644 rehlds/unittests/tmessage_tests.cpp create mode 100644 rehlds/version/appversion.vm create mode 100644 rehlds/version/version.cpp create mode 100644 settings.gradle create mode 100644 shared.gradle create mode 100644 shared_icc.gradle create mode 100644 shared_msvc.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..212e6ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +**/build +**/.gradle +.idea +*.iml +**/msvc/Debug* +**/msvc/Release* +**/msvc/*.sdf +**/msvc/*.opensdf +**/msvc/*.user +**/msvc/*.suo +**/msvc/ipch + +rehlds/version/appversion.h +rehlds/msvc/PublishPath*.txt +rehlds/_rehldsTestImg +publish diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..5710cf7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,44 @@ +import versioning.GitVersioner +import versioning.RehldsVersionInfo + +apply plugin: 'maven-publish' +apply from: 'shared.gradle' +group = 'rehlds' + +def gitInfo = GitVersioner.versionForDir(project.rootDir) +if (!gitInfo) { + throw new RuntimeException('Running outside git repository') +} + + + +RehldsVersionInfo versionInfo +if (gitInfo.tag && gitInfo.tag[0] == 'v') { + def m = gitInfo.tag =~ /^v(\d+)\.(\d+)(\.(\d+))?$/ + if (!m.find()) { + throw new RuntimeException("Invalid git version tag name ${gitInfo.tag}") + } + + versionInfo = new RehldsVersionInfo( + majorVersion: m.group(1) as int, + minorVersion: m.group(2) as int, + maintenanceVersion: m.group(4) ? (m.group(4) as int) : null, + lastCommitDate: gitInfo.lastCommitDate + ) +} else { + versionInfo = new RehldsVersionInfo( + majorVersion: project.majorVersion as int, + minorVersion: project.minorVersion as int, + suffix: 'SNAPSHOT', + lastCommitDate: gitInfo.lastCommitDate + ) +} + +project.ext.rehldsVersionInfo = versionInfo +project.version = versionInfo.asMavenVersion() + +apply from: 'publish.gradle' + +task wrapper(type: Wrapper) { + gradleVersion = '2.4-rc-2' +} diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000..6c01617 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,37 @@ +apply plugin: 'groovy' + +repositories { + //mavenLocal() + mavenCentral() + maven { + url 'http://nexus.rehlds.org/nexus/content/repositories/rehlds-releases/' + } + maven { + url 'http://nexus.rehlds.org/nexus/content/repositories/rehlds-snapshots/' + } + +} + +configurations { + rehlds_it_image +} + +dependencies { + compile gradleApi() + compile localGroovy() + compile 'commons-io:commons-io:2.4' + compile 'commons-lang:commons-lang:2.6' + compile 'joda-time:joda-time:2.7' + + compile 'org.doomedsociety.gradlecpp:gradle-cpp-plugin:1.1' + + compile 'org.eclipse.jgit:org.eclipse.jgit:3.7.0.201502260915-r' + + compile 'org.apache.velocity:velocity:1.7' +} + +buildscript { + configurations { + rehlds_it_image + } +} diff --git a/buildSrc/src/main/groovy/dirsync/builder/FileSystemTreeBuilder.groovy b/buildSrc/src/main/groovy/dirsync/builder/FileSystemTreeBuilder.groovy new file mode 100644 index 0000000..dad66d7 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/builder/FileSystemTreeBuilder.groovy @@ -0,0 +1,58 @@ +package dirsync.builder + +import dirsync.model.tree.DirectoryNode +import dirsync.model.tree.FileNode +import groovy.transform.CompileStatic + +class FileSystemTreeBuilder { + + @CompileStatic + private static FileNode buildNodeForFile(File file, DirectoryNode parent) { + if (parent.getChildren(file.name)) { + throw new RuntimeException("Parent dir ${parent.name} already contains child node ${file.name}"); + } + + return new FileNode( + name: file.name, + lastModifiedDate: file.lastModified(), + data: file, + parent: parent, + size: file.size() + ); + } + + @CompileStatic + private static DirectoryNode buildNodeForDirectoryRecursive(File dir, DirectoryNode parent) { + if (!dir.isDirectory()) { + throw new RuntimeException("File ${dir.absolutePath} is not a directory") + } + + if (parent != null && parent.getChildren(dir.name)) { + throw new RuntimeException("Parent dir ${parent.name} already contains child node ${dir.name}"); + } + + DirectoryNode thisNode = new DirectoryNode( + name: dir.name, + lastModifiedDate: dir.lastModified(), + data: dir, + parent: parent + ); + + dir.eachFile { File f -> + if (f.isDirectory()) { + thisNode.childNodes[f.name] = buildNodeForDirectoryRecursive(f, thisNode) + } else { + thisNode.childNodes[f.name] = buildNodeForFile(f, thisNode) + } + } + + return thisNode; + } + + static DirectoryNode buildFileSystemTree(File rootDir) { + def root = buildNodeForDirectoryRecursive(rootDir, null); + PostBuildPass.doPostBuild(root) + + return root + } +} diff --git a/buildSrc/src/main/groovy/dirsync/builder/FileTreeMerger.groovy b/buildSrc/src/main/groovy/dirsync/builder/FileTreeMerger.groovy new file mode 100644 index 0000000..9251e2f --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/builder/FileTreeMerger.groovy @@ -0,0 +1,60 @@ +package dirsync.builder + +import dirsync.model.tree.DirectoryNode +import dirsync.model.tree.FileNode + +class FileTreeMerger { + + private static void mergeContentsRecursive(DirectoryNode newParent, DirectoryNode toMerge) { + toMerge.childNodes.each { cn -> + def node = cn.value + def existingNode = newParent.childNodes[node.name] + if (existingNode) { + if (!(existingNode instanceof DirectoryNode) || !(node instanceof DirectoryNode)) + throw new RuntimeException("Failed to merge non-directory nodes ${node.fullPath}") + + def existingDirNode = existingNode as DirectoryNode + def dirNode = node as DirectoryNode + + existingDirNode.lastModifiedDate = Math.max(existingDirNode.lastModifiedDate, dirNode.lastModifiedDate) + mergeContentsRecursive(existingDirNode, dirNode) + } else { + if (node instanceof DirectoryNode) { + def dirNode = node as DirectoryNode + def newNode = new DirectoryNode( + name: dirNode.name, + data: dirNode.data, + parent: newParent, + lastModifiedDate: dirNode.lastModifiedDate + ) + newParent.childNodes[node.name] = newNode + + mergeContentsRecursive(newNode, dirNode) + } else { + FileNode fileNode = node as FileNode + FileNode newNode = new FileNode( + name: fileNode.name, + data: fileNode.data, + parent: newParent, + lastModifiedDate: fileNode.lastModifiedDate, + size: fileNode.size + ) + + newParent.childNodes[node.name] = newNode + } + } + } + } + + public static DirectoryNode mergeTrees(DirectoryNode tree1, DirectoryNode tree2) { + DirectoryNode newRoot = new DirectoryNode( + name: tree1.name ?: tree2.name + ) + + mergeContentsRecursive(newRoot, tree1) + mergeContentsRecursive(newRoot, tree2) + PostBuildPass.doPostBuild(newRoot) + + return newRoot + } +} diff --git a/buildSrc/src/main/groovy/dirsync/builder/PostBuildPass.groovy b/buildSrc/src/main/groovy/dirsync/builder/PostBuildPass.groovy new file mode 100644 index 0000000..6dc41aa --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/builder/PostBuildPass.groovy @@ -0,0 +1,22 @@ +package dirsync.builder + +import dirsync.model.tree.DirectoryNode + +class PostBuildPass { + + private static void postProcessRecursive(DirectoryNode dir) { + dir.childNodes.each { cne -> + def childNode = cne.value + childNode.fullPath = dir.fullPath ? dir.fullPath + '/' + childNode.name : childNode.name + if (childNode instanceof DirectoryNode) { + def childDirNode = childNode as DirectoryNode + postProcessRecursive(childDirNode) + } + } + } + + static void doPostBuild(DirectoryNode root) { + root.fullPath = '' + postProcessRecursive(root) + } +} diff --git a/buildSrc/src/main/groovy/dirsync/builder/ZipTreeBuilder.groovy b/buildSrc/src/main/groovy/dirsync/builder/ZipTreeBuilder.groovy new file mode 100644 index 0000000..94e6ffe --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/builder/ZipTreeBuilder.groovy @@ -0,0 +1,53 @@ +package dirsync.builder + +import dirsync.model.tree.DirectoryNode +import dirsync.model.tree.FileNode +import dirsync.model.tree.ZipData + +import java.util.zip.ZipFile + +class ZipTreeBuilder { + static DirectoryNode buildForZipArchive(String zipArchive, ZipFile zf) { + DirectoryNode root = new DirectoryNode<>() + + zf.entries().each { ze -> + def path = ze.name.replace('\\', '/') + if (path.endsWith('/')) + path = path.substring(0, path.length() - 1) + + def parentPath = path.contains('/') ? path.substring(0, path.lastIndexOf('/')) : '' + def childPath = path.contains('/') ? path.substring(path.lastIndexOf('/') + 1) : path + + def parentNode = (DirectoryNode) root.getByPath(parentPath) + if (parentNode == null) + throw new RuntimeException("Error reading ${zipArchive}: could not find parent path ${parentPath} for path ${path}") + + def childNode = parentNode.getChildren(childPath) + if (childNode) + throw new RuntimeException("Error reading ${zipArchive}: duplicate path ${path}") + + if (ze.directory) { + childNode = new DirectoryNode( + name: childPath, + lastModifiedDate: ze.time, + data: new ZipData(zipEntryName: ze.name, zipArchiveName: zipArchive), + parent: parentNode + ); + } else { + childNode = new FileNode( + name: childPath, + lastModifiedDate: ze.time, + data: new ZipData(zipEntryName: ze.name, zipArchiveName: zipArchive), + parent: parentNode, + size: ze.size + ); + } + parentNode.childNodes[childPath] = childNode + + //println '' + ze.directory + ' ' + ze.name + ' ' + parentPath + ' ' + childPath + } + + PostBuildPass.doPostBuild(root) + return root + } +} diff --git a/buildSrc/src/main/groovy/dirsync/merger/FileTreeComparator.groovy b/buildSrc/src/main/groovy/dirsync/merger/FileTreeComparator.groovy new file mode 100644 index 0000000..89b0c76 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/merger/FileTreeComparator.groovy @@ -0,0 +1,97 @@ +package dirsync.merger + +import dirsync.model.synccmd.AbstractSyncCmd +import dirsync.model.synccmd.CopyDirCmd +import dirsync.model.synccmd.CopyFileCmd +import dirsync.model.synccmd.DeleteDirCmd +import dirsync.model.synccmd.DeleteFileCmd +import dirsync.model.synccmd.ReplaceFileCmd +import dirsync.model.tree.DirectoryNode +import dirsync.model.tree.FileNode +import groovy.transform.TypeChecked + +@TypeChecked +class FileTreeComparator { + + private static void mergeDirsRecursive(DirectoryNode left, DirectoryNode right, List> diffs) { + + // left => right + left.childNodes.each { le -> + def leftNode = le.value + def rightNode = right.childNodes[leftNode.name] + + if (rightNode == null) { + switch (leftNode) { + case DirectoryNode: + def leftDirNode = leftNode as DirectoryNode + diffs << new CopyDirCmd<>(src: leftDirNode, dstParentDir: right) + break + + case FileNode: + def leftFileNode = leftNode as FileNode + diffs << new CopyFileCmd<>(src: leftFileNode, dstDir: right) + break + + default: + throw new RuntimeException("Invalid node class ${leftNode.class.name}") + } + + return + } + + if (rightNode.class != leftNode.class) { + throw new RuntimeException("node classes mismatch: ${leftNode.class.name} != ${rightNode.class.name}") + } + + switch (rightNode) { + case DirectoryNode: + def leftDirNode = leftNode as DirectoryNode + def rightDirNode = rightNode as DirectoryNode + mergeDirsRecursive(leftDirNode, rightDirNode, diffs) + break + + case FileNode: + def leftFileNode = leftNode as FileNode + def rightFileNode = rightNode as FileNode + if (leftFileNode.size != rightFileNode.size || leftFileNode.lastModifiedDate != rightFileNode.lastModifiedDate) { + diffs << new ReplaceFileCmd<>(src: leftFileNode, dst: rightFileNode) + } + break + + default: + throw new RuntimeException("Invalid node class ${rightNode.class.name}") + } + } // ~left => right + + //right => left + right.childNodes.each { re -> + def rightNode = re.value + def leftNode = left.childNodes[rightNode.name] + + if (leftNode != null) { + return //already processed in left => right + } + + switch (rightNode) { + case DirectoryNode: + def rightDirNode = rightNode as DirectoryNode + diffs << new DeleteDirCmd<>(dirNode: rightDirNode) + break + + case FileNode: + def rightFileNode = rightNode as FileNode + diffs << new DeleteFileCmd<>(node: rightFileNode) + break + + default: + throw new RuntimeException("Invalid node class ${rightNode.class.name}") + } + } // ~right => left + } + + static List> mergeTrees(DirectoryNode leftRoot, DirectoryNode rightRoot) { + List> res = [] + mergeDirsRecursive(leftRoot, rightRoot, res) + return res + } +} diff --git a/buildSrc/src/main/groovy/dirsync/merger/FileTreeDiffApplier.groovy b/buildSrc/src/main/groovy/dirsync/merger/FileTreeDiffApplier.groovy new file mode 100644 index 0000000..59fe4b6 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/merger/FileTreeDiffApplier.groovy @@ -0,0 +1,103 @@ +package dirsync.merger + +import dirsync.model.synccmd.AbstractSyncCmd +import dirsync.model.synccmd.CopyDirCmd +import dirsync.model.synccmd.CopyFileCmd +import dirsync.model.synccmd.DeleteDirCmd +import dirsync.model.synccmd.DeleteFileCmd +import dirsync.model.synccmd.ReplaceFileCmd +import dirsync.model.tree.DirectoryNode +import dirsync.model.tree.FileNode +import dirsync.model.tree.TreePhysMapper +import groovy.transform.TypeChecked +import org.apache.commons.io.IOUtils + +@TypeChecked +public class FileTreeDiffApplier { + + static void copyDirRecursive(DirectoryNode src, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { + dstMapper.createDirectory(src.fullPath) + src.childNodes.each { ce -> + def childNode = ce.value + def childPath = childNode.fullPath + switch (childNode) { + case FileNode: + srcMapper.fileContent(childNode.data).withStream { InputStream inStream -> + dstMapper.createFile(childPath).withStream { OutputStream outStream -> + IOUtils.copy(inStream, outStream) + } + + dstMapper.setFileLastUpdatedDate(childPath, childNode.lastModifiedDate) + } + break; + + case DirectoryNode: + copyDirRecursive(childNode as DirectoryNode, srcMapper, dstMapper) + break; + + default: + throw new RuntimeException("Invalid node class: ${childNode.class.name}") + } + } + } + + static void handleCopyFile(CopyFileCmd fileCopy, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { + def dstPath = fileCopy.dstDir.fullPath ? fileCopy.dstDir.fullPath + '/' + fileCopy.src.name : fileCopy.src.name + srcMapper.fileContent(fileCopy.src.data).withStream { InputStream inStream -> + dstMapper.createFile(dstPath).withStream { OutputStream outStream -> + IOUtils.copy(inStream, outStream) + } + + dstMapper.setFileLastUpdatedDate(dstPath, fileCopy.src.lastModifiedDate) + } + } + + static void handleDeleteDir(DeleteDirCmd delDir, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { + dstMapper.removeDirectory(delDir.dirNode.fullPath) + } + + static void handleDeleteFile(DeleteFileCmd delFile, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { + dstMapper.removeFile(delFile.node.fullPath) + } + + static void handleReplaceFile(ReplaceFileCmd replaceFile, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { + dstMapper.removeFile(replaceFile.dst.fullPath) + srcMapper.fileContent(replaceFile.src.data).withStream { InputStream inStream -> + dstMapper.createFile(replaceFile.dst.fullPath).withStream { OutputStream outStream -> + IOUtils.copy(inStream, outStream) + } + + dstMapper.setFileLastUpdatedDate(replaceFile.dst.fullPath, replaceFile.src.lastModifiedDate) + } + } + + static void applyDiffs(List> diffs, TreePhysMapper srcMapper, TreePhysMapper dstMapper) { + diffs.each { diff -> + switch (diff) { + case CopyDirCmd: + def copyDir = diff as CopyDirCmd + copyDirRecursive(copyDir.src, srcMapper, dstMapper) + break + + case CopyFileCmd: + handleCopyFile(diff as CopyFileCmd, srcMapper, dstMapper) + break + + case DeleteDirCmd: + handleDeleteDir(diff as DeleteDirCmd, srcMapper, dstMapper) + break + + case DeleteFileCmd: + handleDeleteFile(diff as DeleteFileCmd, srcMapper, dstMapper) + break + + case ReplaceFileCmd: + handleReplaceFile(diff as ReplaceFileCmd, srcMapper, dstMapper) + break + + default: + throw new RuntimeException("Invalid diff command ${diff.class.name}") + } + } + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/AbstractSyncCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/AbstractSyncCmd.groovy new file mode 100644 index 0000000..6351762 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/synccmd/AbstractSyncCmd.groovy @@ -0,0 +1,4 @@ +package dirsync.model.synccmd + +class AbstractSyncCmd { +} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyDirCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyDirCmd.groovy new file mode 100644 index 0000000..bead311 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyDirCmd.groovy @@ -0,0 +1,8 @@ +package dirsync.model.synccmd + +import dirsync.model.tree.DirectoryNode + +class CopyDirCmd extends AbstractSyncCmd { + DirectoryNode src + DirectoryNode dstParentDir +} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyFileCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyFileCmd.groovy new file mode 100644 index 0000000..2f25866 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/synccmd/CopyFileCmd.groovy @@ -0,0 +1,9 @@ +package dirsync.model.synccmd + +import dirsync.model.tree.DirectoryNode +import dirsync.model.tree.FileNode + +class CopyFileCmd extends AbstractSyncCmd { + FileNode src + DirectoryNode dstDir +} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteDirCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteDirCmd.groovy new file mode 100644 index 0000000..2103c7a --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteDirCmd.groovy @@ -0,0 +1,7 @@ +package dirsync.model.synccmd + +import dirsync.model.tree.DirectoryNode + +class DeleteDirCmd extends AbstractSyncCmd { + DirectoryNode dirNode +} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteFileCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteFileCmd.groovy new file mode 100644 index 0000000..66a87e2 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/synccmd/DeleteFileCmd.groovy @@ -0,0 +1,7 @@ +package dirsync.model.synccmd + +import dirsync.model.tree.FileNode + +class DeleteFileCmd extends AbstractSyncCmd { + FileNode node +} diff --git a/buildSrc/src/main/groovy/dirsync/model/synccmd/ReplaceFileCmd.groovy b/buildSrc/src/main/groovy/dirsync/model/synccmd/ReplaceFileCmd.groovy new file mode 100644 index 0000000..3da6dd0 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/synccmd/ReplaceFileCmd.groovy @@ -0,0 +1,8 @@ +package dirsync.model.synccmd + +import dirsync.model.tree.FileNode + +class ReplaceFileCmd extends AbstractSyncCmd { + FileNode src + FileNode dst +} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/AbstractFileTreeNode.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/AbstractFileTreeNode.groovy new file mode 100644 index 0000000..68ae342 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/tree/AbstractFileTreeNode.groovy @@ -0,0 +1,27 @@ +package dirsync.model.tree + +import groovy.transform.CompileStatic + +@CompileStatic +abstract class AbstractFileTreeNode { + DirectoryNode parent + String name + String fullPath + long lastModifiedDate + T data + + boolean equals(o) { + if (this.is(o)) return true + if (getClass() != o.class) return false + + AbstractFileTreeNode that = (AbstractFileTreeNode) o + + if (name != that.name) return false + + return true + } + + int hashCode() { + return (name != null ? name.hashCode() : 0) + } +} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/DirectoryNode.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/DirectoryNode.groovy new file mode 100644 index 0000000..2062c1d --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/tree/DirectoryNode.groovy @@ -0,0 +1,42 @@ +package dirsync.model.tree + +import groovy.transform.CompileStatic + +@CompileStatic +class DirectoryNode extends AbstractFileTreeNode { + Map> childNodes = new HashMap<>() + + AbstractFileTreeNode getChildren(String name) { + return childNodes[name]; + } + + AbstractFileTreeNode getChildren(String[] names, int idx) { + if (idx == names.length) + return this + + AbstractFileTreeNode c = childNodes[names[idx]] + if (c == null) + return null + + if (c instanceof DirectoryNode) { + def d = (DirectoryNode) c; + return d.getChildren(names, idx + 1) + } + + return null; + } + + AbstractFileTreeNode getByPath(String path) { + path = path.replace('\\', '/') + if (path.endsWith('/')) + path = path.substring(0, path.length() - 1) + + if (path.empty) { + return this + } + + String[] components = path.split('/') + return getChildren(components, 0) + } + +} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/FSMapper.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/FSMapper.groovy new file mode 100644 index 0000000..95cf3c0 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/tree/FSMapper.groovy @@ -0,0 +1,50 @@ +package dirsync.model.tree + +class FSMapper extends TreePhysMapper { + final File root + + FSMapper(File root) { + this.root = root + } + + @Override + InputStream fileContent(File file) { + return file.newDataInputStream() + } + + @Override + void createDirectory(String dir) { + def target = new File(root, dir) + if (!target.mkdirs()) { + throw new RuntimeException("Failed to create directory ${target.absolutePath}") + } + } + + @Override + void removeDirectory(String dir) { + def target = new File(root, dir) + if (!target.deleteDir()) { + throw new RuntimeException("Failed to delete directory ${target.absolutePath}") + } + } + + @Override + void removeFile(String path) { + def target = new File(root, path) + if (!target.delete()) { + throw new RuntimeException("Failed to delete file ${target.absolutePath}") + } + } + + @Override + OutputStream createFile(String path) { + def target = new File(root, path) + return target.newOutputStream() + } + + @Override + void setFileLastUpdatedDate(String path, long date) { + def target = new File(root, path) + target.setLastModified(date) + } +} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/FileNode.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/FileNode.groovy new file mode 100644 index 0000000..d34591e --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/tree/FileNode.groovy @@ -0,0 +1,8 @@ +package dirsync.model.tree + +import groovy.transform.CompileStatic + +@CompileStatic +class FileNode extends AbstractFileTreeNode { + long size +} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/TreePhysMapper.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/TreePhysMapper.groovy new file mode 100644 index 0000000..2c60d66 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/tree/TreePhysMapper.groovy @@ -0,0 +1,11 @@ +package dirsync.model.tree + +abstract class TreePhysMapper { + abstract InputStream fileContent(T file) + abstract void createDirectory(String dir) + abstract void removeDirectory(String dir) + abstract void removeFile(String path) + abstract OutputStream createFile(String path) + + abstract void setFileLastUpdatedDate(String path, long date) +} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/ZipData.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/ZipData.groovy new file mode 100644 index 0000000..6e89d34 --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/tree/ZipData.groovy @@ -0,0 +1,9 @@ +package dirsync.model.tree + +import groovy.transform.CompileStatic + +@CompileStatic +class ZipData { + String zipEntryName + String zipArchiveName +} diff --git a/buildSrc/src/main/groovy/dirsync/model/tree/ZipTreeMapper.groovy b/buildSrc/src/main/groovy/dirsync/model/tree/ZipTreeMapper.groovy new file mode 100644 index 0000000..9b0126c --- /dev/null +++ b/buildSrc/src/main/groovy/dirsync/model/tree/ZipTreeMapper.groovy @@ -0,0 +1,72 @@ +package dirsync.model.tree + +import dirsync.builder.FileTreeMerger +import dirsync.builder.ZipTreeBuilder +import sun.reflect.generics.reflectiveObjects.NotImplementedException + +import java.util.zip.ZipFile + +public class ZipTreeMapper extends TreePhysMapper implements Closeable { + Map zipArchives = [:] + + void addZipArchive(String zipArchive) { + zipArchives[zipArchive] = new ZipFile(zipArchive) + } + + DirectoryNode buildFileTree() { + def root = new DirectoryNode() + zipArchives.each { ze -> + def zipTree = ZipTreeBuilder.buildForZipArchive(ze.key, ze.value) + root = FileTreeMerger.mergeTrees(root, zipTree) + } + + return root + } + + @Override + void close() throws IOException { + zipArchives.each { ze -> + try { ze.value.close() } catch (Exception ignored) { } + } + } + + @Override + InputStream fileContent(ZipData file) { + def archive = zipArchives[file.zipArchiveName] + if (!archive) { + throw new RuntimeException("Archive ${file.zipArchiveName} is not loaded"); + } + + def zipEntry = archive.getEntry(file.zipEntryName) + if (!zipEntry) { + throw new RuntimeException("File ${file.zipEntryName} not found in archive ${file.zipArchiveName}"); + } + + return archive.getInputStream(zipEntry) + } + + @Override + void createDirectory(String dir) { + throw new NotImplementedException() + } + + @Override + void removeDirectory(String dir) { + throw new NotImplementedException() + } + + @Override + void removeFile(String path) { + throw new NotImplementedException() + } + + @Override + OutputStream createFile(String path) { + throw new NotImplementedException() + } + + @Override + void setFileLastUpdatedDate(String path, long date) { + throw new NotImplementedException() + } +} diff --git a/buildSrc/src/main/groovy/gradlecpp/CppUnitTestExtension.groovy b/buildSrc/src/main/groovy/gradlecpp/CppUnitTestExtension.groovy new file mode 100644 index 0000000..fe94d87 --- /dev/null +++ b/buildSrc/src/main/groovy/gradlecpp/CppUnitTestExtension.groovy @@ -0,0 +1,19 @@ +package gradlecpp + +import org.gradle.api.Project +import org.gradle.nativeplatform.NativeBinarySpec + +class CppUnitTestExtension { + Project _project + + CppUnitTestExtension(Project p) { + _project = p + } + + void eachTestExecutable(Closure action) { + _project.binaries.each { NativeBinarySpec bin -> + if (!bin.hasProperty('cppUnitTestsExecutable')) return + action(bin) + } + } +} diff --git a/buildSrc/src/main/groovy/gradlecpp/CppUnitTestPlugin.groovy b/buildSrc/src/main/groovy/gradlecpp/CppUnitTestPlugin.groovy new file mode 100644 index 0000000..394460e --- /dev/null +++ b/buildSrc/src/main/groovy/gradlecpp/CppUnitTestPlugin.groovy @@ -0,0 +1,242 @@ +package gradlecpp + +import gradlecpp.teamcity.TeamCityIntegration +import org.gradle.api.Action +import org.gradle.api.GradleException +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.internal.project.AbstractProject +import org.gradle.model.internal.core.DirectNodeModelAction +import org.gradle.model.internal.core.ModelActionRole +import org.gradle.model.internal.core.ModelPath +import org.gradle.model.internal.core.ModelReference +import org.gradle.model.internal.core.MutableModelNode +import org.gradle.model.internal.core.rule.describe.ModelRuleDescriptor +import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor +import org.gradle.model.internal.registry.ModelRegistry +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeLibrarySpec +import org.gradle.nativeplatform.internal.AbstractNativeBinarySpec + +import org.doomedsociety.gradlecpp.GradleCppUtils + +class CppUnitTestPlugin implements Plugin { + + private static class TestExecStatus { + boolean successful + int exitCode + String output + long durationMsec + String cmdLine + String execDir + } + + static void onBinariesCreated(Project p, String desc, Closure action) { + ModelRegistry mr = (p as AbstractProject).getModelRegistry() + def modelPath = ModelPath.path("binaries") + ModelRuleDescriptor ruleDescriptor = new SimpleModelRuleDescriptor(desc); + + mr.configure(ModelActionRole.Finalize, DirectNodeModelAction.of(ModelReference.of(modelPath), ruleDescriptor, new Action() { + @Override + void execute(MutableModelNode node) { + action() + } + })) + } + + @Override + void apply(Project project) { + project.extensions.create('cppUnitTest', CppUnitTestExtension, project) + onBinariesCreated(project, 'CppUnitTestPlugin::AttachUnitTest', { + processCppUnitTests(project) + }) + } + + + + /** + * Attaches test tasks to C/C++ libraries build tasks + */ + static void processCppUnitTests(Project p) { + //println "processCppUnitTests::afterEvaluate on ${p.name}: project type is ${p.projectType}" + + p.binaries.all { NativeBinarySpec bin -> + if (!(bin.component instanceof NativeLibrarySpec)) { + return + } + + def testComponentName = bin.component.name + '_tests' + Collection testCandidates = p.binaries.matching { it.component.name == testComponentName && bin.buildType == it.buildType && bin.flavor == it.flavor } + if (testCandidates.size() > 1) { + throw new GradleException("Found >1 test candidates for library ${bin.component.name} in project ${p}: ${testCandidates}") + } else if (!testCandidates.empty) { + def testBinary = testCandidates.first() + GradleCppUtils.onTasksCreated(p, 'CppUnitTestPlugin::AttachUnitTestTask', { + attachTestTaskToCppLibrary(bin, testBinary) + }) + String testTaskName = bin.namingScheme.getTaskName('unitTest') + bin.ext.cppUnitTestTask = testTaskName + } else { + throw new GradleException("No tests found for library ${bin.component.name} in project ${p}") + } + } + + } + + static TestExecStatus runTestExecutable(NativeBinarySpec testSubject, String executable, List params, String phase, int timeout) { + def execFile = new File(executable) + def outDir = new File(testSubject.buildTask.project.buildDir, "tests/${testSubject.name}/run") + outDir.mkdirs() + + def outPath = new File(outDir, "${phase}.log") + + def cmdParams = []; + cmdParams << execFile.absolutePath + cmdParams.addAll(params) + + def execDir = execFile.parentFile + def pb = new ProcessBuilder(cmdParams).redirectErrorStream(true).directory(execDir) + if (!GradleCppUtils.windows) { + pb.environment().put('LD_LIBRARY_PATH', '.') + } + + + def sout = new StringBuffer() + + long startTime = System.currentTimeMillis() + def p = pb.start() + p.consumeProcessOutput(sout, sout) + + p.waitForOrKill(timeout * 1000) + long endTime = System.currentTimeMillis() + + int exitVal = p.exitValue() + + outPath.withWriter('UTF-8') { writer -> + writer.write(sout.toString()) + } + + return new TestExecStatus( + exitCode: exitVal, + successful: (exitVal == 0), + output: sout.toString(), + durationMsec: endTime - startTime, + cmdLine: cmdParams.join(' '), + execDir: execDir.absolutePath + ) + } + + static void dumpTestExecStatus(TestExecStatus stat) { + if (!stat) { + println "Execution of test executable failed" + } + + println "Test executable command: ${stat.cmdLine}" + println "Test executable run directury: ${stat.execDir}" + println "Test executable exit code: ${stat.exitCode}" + println "Test executable output BEGIN" + println stat.output + println "Test executable output END" + } + + static void attachTestTaskToCppLibrary(NativeBinarySpec libBin, NativeBinarySpec testExecBin) { + Project p = libBin.buildTask.project + + def libBinImpl = libBin as AbstractNativeBinarySpec + def libLinkTask = GradleCppUtils.getLinkTask(libBin) + def testExecLinkTask = GradleCppUtils.getLinkTask(testExecBin) + + // collect all output files from library and test executable + def depFiles = [] + depFiles.addAll(libLinkTask.outputs.files.files) + depFiles.addAll(testExecLinkTask.outputs.files.files) + + //create 'tests' task + def testTaskName = libBinImpl.namingScheme.getTaskName('unitTest') + def testTask = p.task(testTaskName, { Task testTask -> + + //output dir + def testResDir = new File(p.buildDir, "tests/${libBin.name}") + + //inputs/outputs for up-to-date check + testTask.outputs.dir testResDir + testTask.inputs.files depFiles + + //dependencies on library and test executable + testTask.dependsOn libLinkTask + testTask.dependsOn testExecLinkTask + + // binary build depends on unit test + libBin.buildTask.dependsOn testTask + + // extra project-specific dependencies + def testDepsTask = p.tasks.findByName('testDeps') + if (testDepsTask != null) { + testTask.dependsOn testDepsTask + } + + // task actions + testTask.doLast { + + //temporary file that store info about all tests (XML) + File allTests = File.createTempFile('j4s-testinfo', 'data') + allTests.deleteOnExit() + + //fill file with test info + print "Fetching test info..." + def getTestsStatus = runTestExecutable(libBin, testExecBin.executableFile.absolutePath, ['-writeTestInfo', allTests.absolutePath], '__getTests', 5000) + if (!getTestsStatus.successful) { + println " Failed" + dumpTestExecStatus(getTestsStatus) + throw new GradleException("Unable to fetch test names") + } + println " OK" + getTestsStatus = null // allow GC to collect it + + // parse the test info file + def root = new XmlSlurper().parse(allTests) + + // run all tests + println "Running ${root.test.size()} tests..." + TeamCityIntegration.suiteStarted("unitTests.${libBin.name}") + int failCount = 0; + root.test.list().each { testInfo -> + def testName = '' + testInfo.@name.text() + def testGroup = '' + testInfo.@group.text() + def testTimeout = ('' + testInfo.@timeout.text()) as int + + if (!TeamCityIntegration.writeOutput) { + print " ${testGroup}-${testName}..." + System.out.flush() + } + + TeamCityIntegration.testStarted("${testGroup}-${testName}") + def testExecStatus = runTestExecutable(libBin, testExecBin.executableFile.absolutePath, ['-runTest', testGroup, testName], "${testGroup}-${testName}", testTimeout) + if (!testExecStatus.successful) { + if (!TeamCityIntegration.writeOutput) { + println " Failed" + } + + TeamCityIntegration.testFailed("${testGroup}-${testName}", "test executable return code is ${testExecStatus.exitCode}", "test executable return code is ${testExecStatus.exitCode}") + dumpTestExecStatus(testExecStatus) + failCount++ + } else { + if (!TeamCityIntegration.writeOutput) { + println " OK" + } + } + + TeamCityIntegration.testStdOut("${testGroup}-${testName}", testExecStatus.output) + TeamCityIntegration.testFinished("${testGroup}-${testName}", testExecStatus.durationMsec) + + } + TeamCityIntegration.suiteFinished("unitTests.${libBin.name}") + + if (failCount) { + throw new GradleException("CPP unit tests: ${failCount} tests failed"); + } + } + }) + } +} diff --git a/buildSrc/src/main/groovy/gradlecpp/RehldsPlayTestPlugin.groovy b/buildSrc/src/main/groovy/gradlecpp/RehldsPlayTestPlugin.groovy new file mode 100644 index 0000000..efc98ca --- /dev/null +++ b/buildSrc/src/main/groovy/gradlecpp/RehldsPlayTestPlugin.groovy @@ -0,0 +1,17 @@ +package gradlecpp + +import org.gradle.api.Plugin +import org.gradle.api.Project + +class RehldsPlayTestPlugin implements Plugin { + @Override + void apply(Project project) { + project.configurations { + rehlds_playtest_image + } + + project.dependencies { + rehlds_playtest_image 'rehlds.testimg:testimg:0.2' + } + } +} diff --git a/buildSrc/src/main/groovy/gradlecpp/RehldsPlayTestTask.groovy b/buildSrc/src/main/groovy/gradlecpp/RehldsPlayTestTask.groovy new file mode 100644 index 0000000..bc5d890 --- /dev/null +++ b/buildSrc/src/main/groovy/gradlecpp/RehldsPlayTestTask.groovy @@ -0,0 +1,80 @@ +package gradlecpp + +import gradlecpp.teamcity.TeamCityIntegration +import org.apache.commons.lang.SystemUtils +import org.gradle.api.DefaultTask +import org.gradle.api.file.FileCollection +import org.gradle.api.tasks.TaskAction +import org.gradle.nativeplatform.NativeBinarySpec +import rehlds.testdemo.RehldsDemoRunner +import rehlds.testdemo.RehldsTestParser + +class RehldsPlayTestTask extends DefaultTask { + + def FileCollection testDemos + def Closure postExtractAction + def File rehldsImageRoot + def File rehldsTestLogs + def NativeBinarySpec testFor + + @TaskAction + def doPlay() { + if (!SystemUtils.IS_OS_WINDOWS) { + return + } + + if (!testDemos) { + println 'RehldsPlayTestTask: no demos attached to the testDemos property' + } + + rehldsImageRoot.mkdirs() + rehldsTestLogs.mkdirs() + + def demoRunner = new RehldsDemoRunner(this.project.configurations.rehlds_playtest_image.getFiles(), rehldsImageRoot, postExtractAction) + + println "Preparing engine..." + demoRunner.prepareEngine() + + println "Running ${testDemos.getFiles().size()} ReHLDS test demos..." + + TeamCityIntegration.suiteStarted("rehldsDemo.${testFor.name}") + int failCount = 0; + testDemos.getFiles().each { f -> + def testInfo = RehldsTestParser.parseTestInfo(f) + TeamCityIntegration.testStarted(testInfo.testName) + + if (!TeamCityIntegration.writeOutput) { + print "Running ReHLDS test demo ${testInfo.testName} " + System.out.flush() + } + + + def testRes = demoRunner.runTest(testInfo, rehldsTestLogs) + + if (testRes.success) { + if (!TeamCityIntegration.writeOutput) { + println ' OK' + } + } else { + + TeamCityIntegration.testFailed(testInfo.testName, "Exit code: ${testRes.returnCode}", "Exit code: ${testRes.returnCode}") + if (!TeamCityIntegration.writeOutput) { + println ' Failed' + println "ReHLDS testdemo ${testInfo.testName} playback failed. Exit status is ${testRes.returnCode}." + println "Dumping console output:" + println testRes.hldsConsoleOutput + } + + failCount++ + } + + TeamCityIntegration.testStdOut(testInfo.testName, testRes.hldsConsoleOutput) + TeamCityIntegration.testFinished(testInfo.testName, testRes.duration) + } + TeamCityIntegration.suiteFinished("rehldsDemo.${testFor.name}") + + if (failCount) { + throw new RuntimeException("Rehlds testdemos: failed ${failCount} tests") + } + } +} diff --git a/buildSrc/src/main/groovy/gradlecpp/VelocityUtils.groovy b/buildSrc/src/main/groovy/gradlecpp/VelocityUtils.groovy new file mode 100644 index 0000000..38d0d56 --- /dev/null +++ b/buildSrc/src/main/groovy/gradlecpp/VelocityUtils.groovy @@ -0,0 +1,38 @@ +package gradlecpp + +import org.apache.velocity.Template +import org.apache.velocity.VelocityContext +import org.apache.velocity.app.Velocity +import org.joda.time.format.DateTimeFormat + +class VelocityUtils { + + static { + Properties p = new Properties(); + + p.setProperty("resource.loader", "class"); + p.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader"); + p.setProperty("class.resource.loader.path", ""); + + p.setProperty("input.encoding", "UTF-8"); + p.setProperty("output.encoding", "UTF-8"); + + Velocity.init(p); + } + + static String renderTemplate(File tplFile, Map ctx) { + Template tpl = Velocity.getTemplate(tplFile.absolutePath) + if (!tpl) { + throw new RuntimeException("Failed to load velocity template ${tplFile.absolutePath}: not found") + } + + + def velocityContext = new VelocityContext(ctx) + velocityContext.put("_DateTimeFormat", DateTimeFormat) + + def sw = new StringWriter() + tpl.merge(velocityContext, sw) + + return sw.toString() + } +} diff --git a/buildSrc/src/main/groovy/gradlecpp/teamcity/TeamCityIntegration.groovy b/buildSrc/src/main/groovy/gradlecpp/teamcity/TeamCityIntegration.groovy new file mode 100644 index 0000000..fd532c5 --- /dev/null +++ b/buildSrc/src/main/groovy/gradlecpp/teamcity/TeamCityIntegration.groovy @@ -0,0 +1,84 @@ +package gradlecpp.teamcity + +import groovy.transform.CompileStatic + + +class TeamCityIntegration { + + static final String flowId = System.getenv('TEAMCITY_PROCESS_FLOW_ID') + static final boolean underTeamcity = System.getenv('TEAMCITY_PROJECT_NAME') + static boolean writeOutput = underTeamcity + + @CompileStatic + private static String escape(String s) { + StringBuilder sb = new StringBuilder((int)(s.length() * 1.2)); + for (char c in s.chars) { + switch (c) { + case '\n': sb.append('|n'); break; + case '\r': sb.append('|r'); break; + case '\'': sb.append('|\''); break; + case '|': sb.append('||'); break; + case ']': sb.append('|]'); break; + default: sb.append(c); + } + } + + return sb.toString() + } + + @CompileStatic + static void writeMessage(String name, Map params) { + if (!writeOutput) return + StringBuilder sb = new StringBuilder() + sb.append('##teamcity[').append(name) + params.each { e -> + if (e.value != null) { + sb.append(' ').append('' + e.key).append('=\'').append(escape('' + e.value)).append('\'') + } + } + sb.append(']') + + println sb.toString() + } + + static void suiteStarted(String suiteName) { + writeMessage('testSuiteStarted', [name: suiteName, flowId: flowId ?: null]) + } + + static void suiteFinished(String suiteName) { + writeMessage('testSuiteFinished', [name: suiteName, flowId: flowId ?: null]) + } + + static void testStarted(String testName) { + writeMessage('testStarted', [name: testName, flowId: flowId ?: null]) + } + + static void testStdOut(String testName, String output) { + writeMessage('testStdOut', [name: testName, out: output, flowId: flowId ?: null]) + } + + static void testFinished(String testName, long durationMs) { + writeMessage('testFinished', [ + name: testName, + flowId: flowId ?: null, + duration: (durationMs >= 0) ? durationMs : null + ]) + } + + static void testFailed(String testName, String message, String details) { + writeMessage('testFailed', [ + name: testName, + flowId: flowId ?: null, + message: message, + details: details + ]) + } + + static void testIgnored(String testName, String message) { + writeMessage('testIgnored', [ + name: testName, + flowId: flowId ?: null, + message: message, + ]) + } +} diff --git a/buildSrc/src/main/groovy/rehlds/testdemo/RehldsDemoRunner.groovy b/buildSrc/src/main/groovy/rehlds/testdemo/RehldsDemoRunner.groovy new file mode 100644 index 0000000..213a3db --- /dev/null +++ b/buildSrc/src/main/groovy/rehlds/testdemo/RehldsDemoRunner.groovy @@ -0,0 +1,81 @@ +package rehlds.testdemo + +import dirsync.builder.FileSystemTreeBuilder +import dirsync.merger.FileTreeComparator +import dirsync.merger.FileTreeDiffApplier +import dirsync.model.tree.DirectoryNode +import dirsync.model.tree.FSMapper +import dirsync.model.tree.ZipData +import dirsync.model.tree.ZipTreeMapper + +class RehldsDemoRunner { + ZipTreeMapper rehldsImage = new ZipTreeMapper() + File rootDir + DirectoryNode engineImageTree + Closure postExtract + + static class TestResult { + boolean success + int returnCode + String hldsConsoleOutput + long duration + } + + RehldsDemoRunner(Collection engineImageZips, File rootDir, Closure postExtract) { + this.rootDir = rootDir + engineImageZips.each { f -> + rehldsImage.addZipArchive(f.absolutePath) + } + engineImageTree = rehldsImage.buildFileTree() + this.postExtract = postExtract + } + + void prepareEngine() { + def existingTree = FileSystemTreeBuilder.buildFileSystemTree(rootDir) + def cmds = FileTreeComparator.mergeTrees(engineImageTree, existingTree) + + FSMapper fsMapper = new FSMapper(rootDir) + FileTreeDiffApplier.applyDiffs(cmds, rehldsImage, fsMapper) + if (postExtract != null) { + postExtract.run() + } + } + + TestResult runTest(RehldsTestInfo info, File testLogDir) { + long startTime = System.currentTimeMillis() + prepareEngine() + + def outPath = new File(testLogDir, "${info.testName}_run.log") + + def cmdParams = [] + cmdParams << new File(rootDir, 'hlds.exe').absolutePath + cmdParams.addAll(info.hldsArgs) + if (info.rehldsExtraArgs) { + cmdParams.addAll(info.rehldsExtraArgs) + } + cmdParams << '--rehlds-test-play' << info.testBinFile.absolutePath + + def pb = new ProcessBuilder(cmdParams).redirectErrorStream(true).directory(rootDir) + def sout = new StringBuffer() + + + def p = pb.start() + p.consumeProcessOutput(sout, sout) + + p.waitForOrKill(info.timeoutSeconds * 1000) + int exitVal = p.exitValue() + + outPath.withWriter('UTF-8') { writer -> + writer.write(sout.toString()) + } + + long endTime = System.currentTimeMillis() + + return new TestResult( + success: (exitVal == 777), + returnCode: exitVal, + hldsConsoleOutput: sout.toString(), + duration: endTime - startTime + ) + } +} diff --git a/buildSrc/src/main/groovy/rehlds/testdemo/RehldsTestInfo.groovy b/buildSrc/src/main/groovy/rehlds/testdemo/RehldsTestInfo.groovy new file mode 100644 index 0000000..e4a218d --- /dev/null +++ b/buildSrc/src/main/groovy/rehlds/testdemo/RehldsTestInfo.groovy @@ -0,0 +1,9 @@ +package rehlds.testdemo + +class RehldsTestInfo { + String testName + List hldsArgs + String rehldsExtraArgs + int timeoutSeconds + File testBinFile +} diff --git a/buildSrc/src/main/groovy/rehlds/testdemo/RehldsTestParser.groovy b/buildSrc/src/main/groovy/rehlds/testdemo/RehldsTestParser.groovy new file mode 100644 index 0000000..74b24df --- /dev/null +++ b/buildSrc/src/main/groovy/rehlds/testdemo/RehldsTestParser.groovy @@ -0,0 +1,63 @@ +package rehlds.testdemo + +import groovy.util.slurpersupport.GPathResult +import org.apache.commons.io.IOUtils + +import java.util.zip.ZipFile + +class RehldsTestParser { + static final String REHLDS_TEST_METAINFO_FILE = 'rehlds_test_metainfo.xml' + + static RehldsTestInfo parseTestInfo(File testArchive) { + def zf = new ZipFile(testArchive); + try { + def metaInfoEntry = zf.getEntry(REHLDS_TEST_METAINFO_FILE) + if (metaInfoEntry == null) { + throw new RuntimeException("Unable to open ${REHLDS_TEST_METAINFO_FILE} in ${testArchive.absolutePath}") + } + + GPathResult metaInfo = null + zf.getInputStream(metaInfoEntry).withStream { InputStream ins -> + metaInfo = new XmlSlurper().parse(ins) + } + + RehldsTestInfo testInfo = new RehldsTestInfo( + testName: metaInfo.name.text(), + hldsArgs: metaInfo.runArgs.arg.list().collect { it.text().trim() }, + timeoutSeconds: metaInfo.timeout.text() as int + ) + + //validate testInfo + if (!testInfo.testName) { + throw new RuntimeException("Error parsing ${testArchive.absolutePath}: test name is not specified") + } + + if (!testInfo.hldsArgs) { + throw new RuntimeException("Error parsing ${testArchive.absolutePath}: run arguments are not specified") + } + + if (testInfo.timeoutSeconds <= 0) { + throw new RuntimeException("Error parsing ${testArchive.absolutePath}: bad timeout") + } + + def testBinName = testInfo.testName + '.bin' + def testBinEntry = zf.getEntry(testBinName) + if (testBinEntry == null) { + throw new RuntimeException("Error parsing ${testArchive.absolutePath}: test binary ${testBinName} not found inside archive") + } + + testInfo.testBinFile = File.createTempFile(testBinName, 'rehlds') + testInfo.testBinFile.deleteOnExit() + zf.getInputStream(testBinEntry).withStream { InputStream ins -> + testInfo.testBinFile.withOutputStream { OutputStream os -> + IOUtils.copy(ins, os) + } + } + + return testInfo + } finally { + try { zf.close() } catch (Exception ignored) { } + } + + } +} diff --git a/buildSrc/src/main/groovy/versioning/GitInfo.groovy b/buildSrc/src/main/groovy/versioning/GitInfo.groovy new file mode 100644 index 0000000..6514be6 --- /dev/null +++ b/buildSrc/src/main/groovy/versioning/GitInfo.groovy @@ -0,0 +1,12 @@ +package versioning + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.joda.time.DateTime + +@CompileStatic @TypeChecked +class GitInfo { + DateTime lastCommitDate + String branch + String tag +} diff --git a/buildSrc/src/main/groovy/versioning/GitVersioner.groovy b/buildSrc/src/main/groovy/versioning/GitVersioner.groovy new file mode 100644 index 0000000..fb7f480 --- /dev/null +++ b/buildSrc/src/main/groovy/versioning/GitVersioner.groovy @@ -0,0 +1,41 @@ +package versioning + +import groovy.transform.CompileStatic +import groovy.transform.TypeChecked +import org.eclipse.jgit.lib.ObjectId +import org.eclipse.jgit.lib.Repository +import org.eclipse.jgit.revwalk.RevWalk +import org.eclipse.jgit.storage.file.FileRepositoryBuilder +import org.joda.time.DateTime +import org.joda.time.DateTimeZone + +@CompileStatic @TypeChecked +class GitVersioner { + + static GitInfo versionForDir(String dir) { + versionForDir(new File(dir)) + } + + static GitInfo versionForDir(File dir) { + FileRepositoryBuilder builder = new FileRepositoryBuilder() + Repository repo = builder.setWorkTree(dir) + .findGitDir() + .build() + + ObjectId head = repo.resolve('HEAD') + if (!head) { + return null + } + + def commit = new RevWalk(repo).parseCommit(head) + def branch = repo.getBranch() + def commitDate = new DateTime(1000L * commit.commitTime, DateTimeZone.UTC) + String tag = repo.tags.find { kv -> kv.value.objectId == commit.id }?.key + + return new GitInfo( + lastCommitDate: commitDate, + branch: branch, + tag: tag + ) + } +} diff --git a/buildSrc/src/main/groovy/versioning/RehldsVersionInfo.groovy b/buildSrc/src/main/groovy/versioning/RehldsVersionInfo.groovy new file mode 100644 index 0000000..00630fc --- /dev/null +++ b/buildSrc/src/main/groovy/versioning/RehldsVersionInfo.groovy @@ -0,0 +1,35 @@ +package versioning + +import groovy.transform.CompileStatic +import groovy.transform.ToString +import groovy.transform.TypeChecked +import org.joda.time.DateTime + +@CompileStatic @TypeChecked +@ToString(includeNames = true) +class RehldsVersionInfo { + int majorVersion + int minorVersion + Integer maintenanceVersion + String suffix + + DateTime lastCommitDate + + String format(String versionSeparator, String suffixSeparator, boolean includeSuffix) { + StringBuilder sb = new StringBuilder() + sb.append(majorVersion).append(versionSeparator).append(minorVersion) + if (maintenanceVersion != null) { + sb.append(versionSeparator).append(maintenanceVersion) + } + + if (suffix && includeSuffix) { + sb.append(suffixSeparator).append(suffix) + } + + return sb.toString() + } + + String asMavenVersion() { + format('.', '-', true) + } +} diff --git a/buildSrc/src/test/groovy/dirsync/builder/ZipTreeBuilderTest.groovy b/buildSrc/src/test/groovy/dirsync/builder/ZipTreeBuilderTest.groovy new file mode 100644 index 0000000..a6d3c99 --- /dev/null +++ b/buildSrc/src/test/groovy/dirsync/builder/ZipTreeBuilderTest.groovy @@ -0,0 +1,44 @@ +package dirsync.builder + +import org.junit.Test + +import java.io.File + +import dirsync.builder.ZipTreeBuilder + +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipOutputStream; + +import static org.junit.Assert.*; + +class ZipTreeBuilderTest { + + @Test + void test1() { + File zipFile = File.createTempFile('ZipTreeBuilderTest', 'zip') + zipFile.deleteOnExit() + + new ZipOutputStream(zipFile.newDataOutputStream()).withStream { ZipOutputStream zos -> + zos.putNextEntry(new ZipEntry('aRootFile1.txt')) + zos.write(65) //'A' + + zos.putNextEntry(new ZipEntry('dir1/')) + zos.putNextEntry(new ZipEntry('dir1/dir2/')) + + zos.putNextEntry(new ZipEntry('dir1/dir2/d1d2f1.txt')) + zos.write(65); zos.write(66) //'AB' + + zos.putNextEntry(new ZipEntry('dir1/d1f1.txt')) + zos.write(65); zos.write(66); zos.write(67) //'ABC' + + zos.putNextEntry(new ZipEntry('zRootFile2.txt')) + zos.write(65); zos.write(66); zos.write(67); zos.write(68) //'ABCD' + } + + ZipFile zf = new ZipFile(zipFile.absolutePath) + def tree = ZipTreeBuilder.buildForZipArchive(zipFile.absolutePath, zf) + + assert tree.childNodes.size() == 3 + } +} \ No newline at end of file diff --git a/dep/bzip2/build.gradle b/dep/bzip2/build.gradle new file mode 100644 index 0000000..649ea6d --- /dev/null +++ b/dep/bzip2/build.gradle @@ -0,0 +1,75 @@ +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeLibrarySpec +import org.gradle.nativeplatform.toolchain.VisualCpp + + +apply plugin: 'c' +apply plugin: IccCompilerPlugin + +void setupToolchain(NativeBinarySpec b) { + def cfg = rootProject.createToolchainConfig(b) + if (cfg instanceof MsvcToolchainConfig) { + cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig( + enabled: true, + pchHeader: 'bzlib_private.h', + pchSourceSet: 'bz2_pch' + ) + } + + ToolchainConfigUtils.apply(project, cfg, b) +} + +model { + buildTypes { + debug + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + components { + bzip2(NativeLibrarySpec) { + targetPlatform 'x86' + + sources { + bz2_main(CSourceSet) { + source { + srcDir "src" + include "**/*.c" + exclude "precompiled.c" + } + exportedHeaders { + srcDir "include" + } + } + + bz2_pch(CSourceSet) { + source { + srcDir "src" + include "precompiled.c" + } + exportedHeaders { + srcDir "include" + } + } + } + + binaries.all { NativeBinarySpec b -> project.setupToolchain(b) } + } + } +} diff --git a/dep/bzip2/include/bzip2/bzlib.h b/dep/bzip2/include/bzip2/bzlib.h new file mode 100644 index 0000000..9bf05d0 --- /dev/null +++ b/dep/bzip2/include/bzip2/bzlib.h @@ -0,0 +1,282 @@ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_H +#define _BZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef + struct { + char *next_in; + unsigned int avail_in; + unsigned int total_in_lo32; + unsigned int total_in_hi32; + + char *next_out; + unsigned int avail_out; + unsigned int total_out_lo32; + unsigned int total_out_hi32; + + void *state; + + void *(*bzalloc)(void *,int,int); + void (*bzfree)(void *,void *); + void *opaque; + } + bz_stream; + + +#ifndef BZ_IMPORT +#define BZ_EXPORT +#endif + +#ifndef BZ_NO_STDIO +/* Need a definitition for FILE */ +#include +#endif + +#ifdef _WIN32 +# include +# ifdef small + /* windows.h define small to char */ +# undef small +# endif +# ifdef BZ_EXPORT +# define BZ_API(func) WINAPI func +# define BZ_EXTERN extern +# else + /* import windows dll dynamically */ +# define BZ_API(func) (WINAPI * func) +# define BZ_EXTERN +# endif +#else +# define BZ_API(func) func +# define BZ_EXTERN extern +#endif + + +/*-- Core (low-level) library functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( + bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompress) ( + bz_stream* strm, + int action + ); + +BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( + bz_stream *strm, + int verbosity, + int small + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( + bz_stream* strm + ); + +BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( + bz_stream *strm + ); + + + +/*-- High(er) level library functions --*/ + +#ifndef BZ_NO_STDIO +#define BZ_MAX_UNUSED 5000 + +typedef void BZFILE; + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( + int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( + int* bzerror, + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( + int* bzerror, + BZFILE* b, + void** unused, + int* nUnused + ); + +BZ_EXTERN int BZ_API(BZ2_bzRead) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( + int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN void BZ_API(BZ2_bzWrite) ( + int* bzerror, + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out + ); + +BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( + int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 + ); +#endif + + +/*-- Utility functions --*/ + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor + ); + +BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( + char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity + ); + + +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ + +BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( + void + ); + +#ifndef BZ_NO_STDIO +BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( + const char *path, + const char *mode + ); + +BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( + int fd, + const char *mode + ); + +BZ_EXTERN int BZ_API(BZ2_bzread) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzwrite) ( + BZFILE* b, + void* buf, + int len + ); + +BZ_EXTERN int BZ_API(BZ2_bzflush) ( + BZFILE* b + ); + +BZ_EXTERN void BZ_API(BZ2_bzclose) ( + BZFILE* b + ); + +BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( + BZFILE *b, + int *errnum + ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/bzip2/msvc/bzip2.vcxproj b/dep/bzip2/msvc/bzip2.vcxproj new file mode 100644 index 0000000..7b45de5 --- /dev/null +++ b/dep/bzip2/msvc/bzip2.vcxproj @@ -0,0 +1,157 @@ + + + + + Debug Swds Play + Win32 + + + Debug Swds + Win32 + + + Debug + Win32 + + + Release + Win32 + + + + {792DF067-9904-4579-99B9-46C17277ADE3} + Win32Proj + bzip2 + + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + + + Use + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + $(ProjectDir)..\include\ + MultiThreadedDebug + bzlib_private.h + + + Windows + true + + + + + Use + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + $(ProjectDir)..\include\ + MultiThreadedDebug + bzlib_private.h + + + Windows + true + + + + + Use + Level3 + Disabled + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + $(ProjectDir)..\include\ + MultiThreadedDebug + bzlib_private.h + + + Windows + true + + + + + Level3 + Use + MaxSpeed + true + true + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + $(ProjectDir)..\include\ + MultiThreaded + bzlib_private.h + + + Windows + true + true + true + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + \ No newline at end of file diff --git a/dep/bzip2/msvc/bzip2.vcxproj.filters b/dep/bzip2/msvc/bzip2.vcxproj.filters new file mode 100644 index 0000000..d395a6b --- /dev/null +++ b/dep/bzip2/msvc/bzip2.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/dep/bzip2/src/blocksort.c b/dep/bzip2/src/blocksort.c new file mode 100644 index 0000000..72d4a31 --- /dev/null +++ b/dep/bzip2/src/blocksort.c @@ -0,0 +1,1094 @@ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +void fallbackSimpleSort ( UInt32* fmap, + UInt32* eclass, + Int32 lo, + Int32 hi ) +{ + Int32 i, j, tmp; + UInt32 ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for ( i = hi-4; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for ( i = hi-1; i >= lo; i-- ) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define fvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + fswap(fmap[yyp1], fmap[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + + +#define fmin(a,b) ((a) < (b)) ? (a) : (b) + +#define fpush(lz,hz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; } + +#define fpop(lz,hz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; } + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + + +static +void fallbackQSort3 ( UInt32* fmap, + UInt32* eclass, + Int32 loSt, + Int32 hiSt ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m; + Int32 sp, lo, hi; + UInt32 med, r, r3; + Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; + Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush ( loSt, hiSt ); + + while (sp > 0) { + + AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); + + fpop ( lo, hi ); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort ( fmap, eclass, lo, hi ); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + avoid bad cases. Median of 9 seems to help but + looks rather expensive. This too seems to work but + is cheaper. Guidance for the magic constants + 7621 and 32768 is taken from Sedgewick's algorithms + book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) med = eclass[fmap[lo]]; else + if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unLo]] - (Int32)med; + if (n == 0) { + fswap(fmap[unLo], fmap[ltLo]); + ltLo++; unLo++; + continue; + }; + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (Int32)eclass[fmap[unHi]] - (Int32)med; + if (n == 0) { + fswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); + + if (gtHi < ltLo) continue; + + n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); + m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush ( lo, n ); + fpush ( m, hi ); + } else { + fpush ( m, hi ); + fpush ( lo, n ); + } + } +} + +#undef fmin +#undef fpush +#undef fpop +#undef fswap +#undef fvswap +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + eclass exists for [0 .. nblock-1] + ((UChar*)eclass) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)eclass) [0 .. nblock-1] holds block + All other areas of eclass destroyed + fmap [0 .. nblock-1] holds sorted order + bhtab [ 0 .. 2+(nblock/32) ] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort ( UInt32* fmap, + UInt32* eclass, + UInt32* bhtab, + Int32 nblock, + Int32 verb ) +{ + Int32 ftab[257]; + Int32 ftabCopy[256]; + Int32 H, i, j, k, l, r, cc, cc1; + Int32 nNotDone; + Int32 nBhtab; + UChar* eclass8 = (UChar*)eclass; + + /*-- + Initial 1-char radix sort to generate + initial fmap and initial BH bits. + --*/ + if (verb >= 4) + VPrintf0 ( " bucket sorting ...\n" ); + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + (nblock / 32); + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /*-- + Inductively refine the buckets. Kind-of an + "exponential radix sort" (!), inspired by the + Manber-Myers suffix array construction algorithm. + --*/ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + + if (verb >= 4) + VPrintf1 ( " depth %6d has ", H ); + + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) j = i; + k = fmap[i] - H; if (k < 0) k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3 ( fmap, eclass, l, r ); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { SET_BH(i); cc = cc1; }; + } + } + } + + if (verb >= 4) + VPrintf1 ( "%6d unresolved strings\n", nNotDone ); + + H *= 2; + if (H > nblock || nNotDone == 0) break; + } + + /*-- + Reconstruct the original block in + eclass8 [0 .. nblock-1], since the + previous phase destroyed it. + --*/ + if (verb >= 4) + VPrintf0 ( " reconstructing block ...\n" ); + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (UChar)j; + } + AssertH ( j < 256, 1005 ); +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +__inline__ +Bool mainGtU ( UInt32 i1, + UInt32 i2, + UChar* block, + UInt16* quadrant, + UInt32 nblock, + Int32* budget ) +{ + Int32 k; + UChar c1, c2; + UInt16 s1, s2; + + AssertD ( i1 != i2, "mainGtU" ); + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 9 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 10 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 11 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + /* 12 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + + k = nblock + 8; + + do { + /* 1 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 2 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 3 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 4 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 5 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 6 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 7 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + /* 8 */ + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + k -= 8; + (*budget)--; + } + while (k >= 0); + + return False; +} + + +/*---------------------------------------------*/ +/*-- + Knuth's increments seem to work better + than Incerpi-Sedgewick here. Possibly + because the number of elems to sort is + usually small, typically <= 20. +--*/ +static +Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 }; + +static +void mainSimpleSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 lo, + Int32 hi, + Int32 d, + Int32* budget ) +{ + Int32 i, j, h, bigN, hp; + UInt32 v; + + bigN = hi - lo + 1; + if (bigN < 2) return; + + hp = 0; + while (incs[hp] < bigN) hp++; + hp--; + + for (; hp >= 0; hp--) { + h = incs[hp]; + + i = lo + h; + while (True) { + + /*-- copy 1 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while ( mainGtU ( + ptr[j-h]+d, v+d, block, quadrant, nblock, budget + ) ) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + + if (*budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/*-- + The following is an implementation of + an elegant 3-way quicksort for strings, + described in a paper "Fast Algorithms for + Sorting and Searching Strings", by Robert + Sedgewick and Jon L. Bentley. +--*/ + +#define mswap(zz1, zz2) \ + { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } + +#define mvswap(zzp1, zzp2, zzn) \ +{ \ + Int32 yyp1 = (zzp1); \ + Int32 yyp2 = (zzp2); \ + Int32 yyn = (zzn); \ + while (yyn > 0) { \ + mswap(ptr[yyp1], ptr[yyp2]); \ + yyp1++; yyp2++; yyn--; \ + } \ +} + +static +__inline__ +UChar mmed3 ( UChar a, UChar b, UChar c ) +{ + UChar t; + if (a > b) { t = a; a = b; b = t; }; + if (b > c) { + b = c; + if (a > b) b = a; + } + return b; +} + +#define mmin(a,b) ((a) < (b)) ? (a) : (b) + +#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; } + +#define mpop(lz,hz,dz) { sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; } + + +#define mnextsize(az) (nextHi[az]-nextLo[az]) + +#define mnextswap(az,bz) \ + { Int32 tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } + + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static +void mainQSort3 ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + Int32 nblock, + Int32 loSt, + Int32 hiSt, + Int32 dSt, + Int32* budget ) +{ + Int32 unLo, unHi, ltLo, gtHi, n, m, med; + Int32 sp, lo, hi, d; + + Int32 stackLo[MAIN_QSORT_STACK_SIZE]; + Int32 stackHi[MAIN_QSORT_STACK_SIZE]; + Int32 stackD [MAIN_QSORT_STACK_SIZE]; + + Int32 nextLo[3]; + Int32 nextHi[3]; + Int32 nextD [3]; + + sp = 0; + mpush ( loSt, hiSt, dSt ); + + while (sp > 0) { + + AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); + + mpop ( lo, hi, d ); + if (hi - lo < MAIN_QSORT_SMALL_THRESH || + d > MAIN_QSORT_DEPTH_THRESH) { + mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); + if (*budget < 0) return; + continue; + } + + med = (Int32) + mmed3 ( block[ptr[ lo ]+d], + block[ptr[ hi ]+d], + block[ptr[ (lo+hi)>>1 ]+d] ); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (True) { + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; unLo++; continue; + }; + if (n > 0) break; + unLo++; + } + while (True) { + if (unLo > unHi) break; + n = ((Int32)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; unHi--; continue; + }; + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; + } + + AssertD ( unHi == unLo-1, "mainQSort3(2)" ); + + if (gtHi < ltLo) { + mpush(lo, hi, d+1 ); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); + + mpush (nextLo[0], nextHi[0], nextD[0]); + mpush (nextLo[1], nextHi[1], nextD[1]); + mpush (nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mswap +#undef mvswap +#undef mpush +#undef mpop +#undef mmin +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + nblock > N_OVERSHOOT + block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)block32) [0 .. nblock-1] holds block + ptr exists for [0 .. nblock-1] + + Post: + ((UChar*)block32) [0 .. nblock-1] holds block + All other areas of block32 destroyed + ftab [0 .. 65536 ] destroyed + ptr [0 .. nblock-1] holds sorted order + if (*budget < 0), sorting was abandoned +*/ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static +void mainSort ( UInt32* ptr, + UChar* block, + UInt16* quadrant, + UInt32* ftab, + Int32 nblock, + Int32 verb, + Int32* budget ) +{ + Int32 i, j, k, ss, sb; + Int32 runningOrder[256]; + Bool bigDone[256]; + Int32 copyStart[256]; + Int32 copyEnd [256]; + UChar c1; + Int32 numQSorted; + UInt16 s; + if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); + + /*-- set up the 2-byte frequency table --*/ + for (i = 65536; i >= 0; i--) ftab[i] = 0; + + j = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); + ftab[j]++; + } + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | ( ((UInt16)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); + + /*-- Complete the initial radix sort --*/ + for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; + + s = block[0] << 8; + i = nblock-1; + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i-3; + } + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] -1; + ftab[s] = j; + ptr[j] = i; + } + + /*-- + Now ftab contains the first loc of every small bucket. + Calculate the running order, from smallest to largest + big bucket. + --*/ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + Int32 vv; + Int32 h = 1; + do h = 3 * h + 1; while (h <= 256); + do { + h = h / 3; + for (i = h; i <= 255; i++) { + vv = runningOrder[i]; + j = i; + while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { + runningOrder[j] = runningOrder[j-h]; + j = j - h; + if (j <= (h - 1)) goto zero; + } + zero: + runningOrder[j] = vv; + } + } while (h != 1); + } + + /*-- + The main sorting loop. + --*/ + + numQSorted = 0; + + for (i = 0; i <= 255; i++) { + + /*-- + Process big buckets, starting with the least full. + Basically this is a 3-step process in which we call + mainQSort3 to sort the small buckets [ss, j], but + also make a big effort to avoid the calls if we can. + --*/ + ss = runningOrder[i]; + + /*-- + Step 1: + Complete the big bucket [ss] by quicksorting + any unsorted small buckets [ss, j], for j != ss. + Hopefully previous pointer-scanning phases have already + completed many of the small buckets [ss, j], so + we don't have to sort them at all. + --*/ + for (j = 0; j <= 255; j++) { + if (j != ss) { + sb = (ss << 8) + j; + if ( ! (ftab[sb] & SETMASK) ) { + Int32 lo = ftab[sb] & CLEARMASK; + Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + if (verb >= 4) + VPrintf4 ( " qsort [0x%x, 0x%x] " + "done %d this %d\n", + ss, j, numQSorted, hi - lo + 1 ); + mainQSort3 ( + ptr, block, quadrant, nblock, + lo, hi, BZ_N_RADIX, budget + ); + numQSorted += (hi - lo + 1); + if (*budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH ( !bigDone[ss], 1006 ); + + /*-- + Step 2: + Now scan this big bucket [ss] so as to synthesise the + sorted order for small buckets [t, ss] for all t, + including, magically, the bucket [ss,ss] too. + This will avoid doing Real Work in subsequent Step 1's. + --*/ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyStart[c1]++ ] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + k = ptr[j]-1; if (k < 0) k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[ copyEnd[c1]-- ] = k; + } + } + + AssertH ( (copyStart[ss]-1 == copyEnd[ss]) + || + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + Necessity for this case is demonstrated by compressing + a sequence of approximately 48.5 million of character + 251; 1.0.0/1.0.1 will then die here. */ + (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), + 1007 ) + + for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; + + /*-- + Step 3: + The [ss] big bucket is now done. Record this fact, + and update the quadrant descriptors. Remember to + update quadrants in the overshoot area too, if + necessary. The "if (i < 255)" test merely skips + this updating for the last bucket processed, since + updating for the last bucket is pointless. + + The quadrant array provides a way to incrementally + cache sort orderings, as they appear, so as to + make subsequent comparisons in fullGtU() complete + faster. For repetitive blocks this makes a big + difference (but not big enough to be able to avoid + the fallback sorting mechanism, exponential radix sort). + + The precise meaning is: at all times: + + for 0 <= i < nblock and 0 <= j <= nblock + + if block[i] != block[j], + + then the relative values of quadrant[i] and + quadrant[j] are meaningless. + + else { + if quadrant[i] < quadrant[j] + then the string starting at i lexicographically + precedes the string starting at j + + else if quadrant[i] > quadrant[j] + then the string starting at j lexicographically + precedes the string starting at i + + else + the relative ordering of the strings starting + at i and j has not yet been determined. + } + --*/ + bigDone[ss] = True; + + if (i < 255) { + Int32 bbStart = ftab[ss << 8] & CLEARMASK; + Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + Int32 shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + Int32 a2update = ptr[bbStart + j]; + UInt16 qVal = (UInt16)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); + } + + } + + if (verb >= 4) + VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", + nblock, numQSorted, nblock - numQSorted ); +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + nblock > 0 + arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + ((UChar*)arr2) [0 .. nblock-1] holds block + arr1 exists for [0 .. nblock-1] + + Post: + ((UChar*)arr2) [0 .. nblock-1] holds block + All other areas of block destroyed + ftab [ 0 .. 65536 ] destroyed + arr1 [0 .. nblock-1] holds sorted order +*/ +void BZ2_blockSort ( EState* s ) +{ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt32* ftab = s->ftab; + Int32 nblock = s->nblock; + Int32 verb = s->verbosity; + Int32 wfact = s->workFactor; + UInt16* quadrant; + Int32 budget; + Int32 budgetInit; + Int32 i; + + if (nblock < 10000) { + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } else { + /* Calculate the location for quadrant, remembering to get + the alignment right. Assumes that &(block[0]) is at least + 2-byte aligned -- this should be ok since block is really + the first section of arr2. + */ + i = nblock+BZ_N_OVERSHOOT; + if (i & 1) i++; + quadrant = (UInt16*)(&(block[i])); + + /* (wfact-1) / 3 puts the default-factor-30 + transition point at very roughly the same place as + with v0.1 and v0.9.0. + Not that it particularly matters any more, since the + resulting compressed stream is now the same regardless + of whether or not we use the main sort or fallback sort. + */ + if (wfact < 1 ) wfact = 1; + if (wfact > 100) wfact = 100; + budgetInit = nblock * ((wfact-1) / 3); + budget = budgetInit; + + mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); + if (verb >= 3) + VPrintf3 ( " %d work, %d block, ratio %5.2f\n", + budgetInit - budget, + nblock, + (float)(budgetInit - budget) / + (float)(nblock==0 ? 1 : nblock) ); + if (budget < 0) { + if (verb >= 2) + VPrintf0 ( " too repetitive; using fallback" + " sorting algorithm\n" ); + fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); + } + } + + s->origPtr = -1; + for (i = 0; i < s->nblock; i++) + if (ptr[i] == 0) + { s->origPtr = i; break; }; + + AssertH( s->origPtr != -1, 1003 ); +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/bzip2/src/bzlib.c b/dep/bzip2/src/bzlib.c new file mode 100644 index 0000000..6d28d13 --- /dev/null +++ b/dep/bzip2/src/bzlib.c @@ -0,0 +1,1580 @@ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + fixed bzWrite/bzRead to ignore zero-length requests. + fixed bzread to correctly handle read requests after EOF. + wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + + +/*---------------------------------------------------*/ +#ifndef BZ_NO_STDIO +void BZ2_bz__AssertH__fail ( int errcode ) +{ + fprintf(stderr, + "\n\nbzip2/libbzip2: internal error number %d.\n" + "This is a bug in bzip2/libbzip2, %s.\n" + "Please report it to me at: jseward@bzip.org. If this happened\n" + "when you were using some program which uses libbzip2 as a\n" + "component, you should also report this bug to the author(s)\n" + "of that program. Please make an effort to report this bug;\n" + "timely and accurate bug reports eventually lead to higher\n" + "quality software. Thanks. Julian Seward, 10 December 2007.\n\n", + errcode, + BZ2_bzlibVersion() + ); + + if (errcode == 1007) { + fprintf(stderr, + "\n*** A special note about internal error number 1007 ***\n" + "\n" + "Experience suggests that a common cause of i.e. 1007\n" + "is unreliable memory or other hardware. The 1007 assertion\n" + "just happens to cross-check the results of huge numbers of\n" + "memory reads/writes, and so acts (unintendedly) as a stress\n" + "test of your memory system.\n" + "\n" + "I suggest the following: try compressing the file again,\n" + "possibly monitoring progress in detail with the -vv flag.\n" + "\n" + "* If the error cannot be reproduced, and/or happens at different\n" + " points in compression, you may have a flaky memory system.\n" + " Try a memory-test program. I have used Memtest86\n" + " (www.memtest86.com). At the time of writing it is free (GPLd).\n" + " Memtest86 tests memory much more thorougly than your BIOSs\n" + " power-on test, and may find failures that the BIOS doesn't.\n" + "\n" + "* If the error can be repeatably reproduced, this is a bug in\n" + " bzip2, and I would very much like to hear about it. Please\n" + " let me know, and, ideally, save a copy of the file causing the\n" + " problem -- without which I will be unable to investigate it.\n" + "\n" + ); + } + + exit(3); +} +#endif + + +/*---------------------------------------------------*/ +static +int bz_config_ok ( void ) +{ + if (sizeof(int) != 4) return 0; + if (sizeof(short) != 2) return 0; + if (sizeof(char) != 1) return 0; + return 1; +} + + +/*---------------------------------------------------*/ +static +void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) +{ + void* v = malloc ( items * size ); + return v; +} + +static +void default_bzfree ( void* opaque, void* addr ) +{ + if (addr != NULL) free ( addr ); +} + + +/*---------------------------------------------------*/ +static +void prepare_new_block ( EState* s ) +{ + Int32 i; + s->nblock = 0; + s->numZ = 0; + s->state_out_pos = 0; + BZ_INITIALISE_CRC ( s->blockCRC ); + for (i = 0; i < 256; i++) s->inUse[i] = False; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +void init_RL ( EState* s ) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +Bool isempty_RL ( EState* s ) +{ + if (s->state_in_ch < 256 && s->state_in_len > 0) + return False; else + return True; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressInit) + ( bz_stream* strm, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 n; + EState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL || + blockSize100k < 1 || blockSize100k > 9 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(EState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + + s->arr1 = NULL; + s->arr2 = NULL; + s->ftab = NULL; + + n = 100000 * blockSize100k; + s->arr1 = BZALLOC( n * sizeof(UInt32) ); + s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); + s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); + + if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + if (s != NULL) BZFREE(s); + return BZ_MEM_ERROR; + } + + s->blockNo = 0; + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->combinedCRC = 0; + s->blockSize100k = blockSize100k; + s->nblockMAX = 100000 * blockSize100k - 19; + s->verbosity = verbosity; + s->workFactor = workFactor; + + s->block = (UChar*)s->arr2; + s->mtfv = (UInt16*)s->arr1; + s->zbits = NULL; + s->ptr = (UInt32*)s->arr1; + + strm->state = s; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + init_RL ( s ); + prepare_new_block ( s ); + return BZ_OK; +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block ( EState* s ) +{ + Int32 i; + UChar ch = (UChar)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC( s->blockCRC, ch ); + } + s->inUse[s->state_in_ch] = True; + switch (s->state_in_len) { + case 1: + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 2: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + case 3: + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len-4] = True; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = (UChar)ch; s->nblock++; + s->block[s->nblock] = ((UChar)(s->state_in_len-4)); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL ( EState* s ) +{ + if (s->state_in_ch < 256) add_pair_to_block ( s ); + init_RL ( s ); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ +{ \ + UInt32 zchh = (UInt32)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && \ + zs->state_in_len == 1) { \ + UChar ch = (UChar)(zs->state_in_ch); \ + BZ_UPDATE_CRC( zs->blockCRC, ch ); \ + zs->inUse[zs->state_in_ch] = True; \ + zs->block[zs->nblock] = (UChar)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || \ + zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block ( zs ); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +Bool copy_input_until_stop ( EState* s ) +{ + Bool progress_in = False; + + if (s->mode == BZ_M_RUNNING) { + + /*-- fast track the common case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + } + + } else { + + /*-- general, uncommon case --*/ + while (True) { + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- flush/finish end? --*/ + if (s->avail_in_expect == 0) break; + progress_in = True; + ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); + s->strm->next_in++; + s->strm->avail_in--; + s->strm->total_in_lo32++; + if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; + s->avail_in_expect--; + } + } + return progress_in; +} + + +/*---------------------------------------------------*/ +static +Bool copy_output_until_stop ( EState* s ) +{ + Bool progress_out = False; + + while (True) { + + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->numZ) break; + + progress_out = True; + *(s->strm->next_out) = s->zbits[s->state_out_pos]; + s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + return progress_out; +} + + +/*---------------------------------------------------*/ +static +Bool handle_compress ( bz_stream* strm ) +{ + Bool progress_in = False; + Bool progress_out = False; + EState* s = strm->state; + + while (True) { + + if (s->state == BZ_S_OUTPUT) { + progress_out |= copy_output_until_stop ( s ); + if (s->state_out_pos < s->numZ) break; + if (s->mode == BZ_M_FINISHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + prepare_new_block ( s ); + s->state = BZ_S_INPUT; + if (s->mode == BZ_M_FLUSHING && + s->avail_in_expect == 0 && + isempty_RL(s)) break; + } + + if (s->state == BZ_S_INPUT) { + progress_in |= copy_input_until_stop ( s ); + if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + flush_RL ( s ); + BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); + s->state = BZ_S_OUTPUT; + } + else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock ( s, False ); + s->state = BZ_S_OUTPUT; + } + else + if (s->strm->avail_in == 0) { + break; + } + } + + } + + return progress_in || progress_out; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) +{ + Bool progress; + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + preswitch: + switch (s->mode) { + + case BZ_M_IDLE: + return BZ_SEQUENCE_ERROR; + + case BZ_M_RUNNING: + if (action == BZ_RUN) { + progress = handle_compress ( strm ); + return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; + } + else + if (action == BZ_FLUSH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto preswitch; + } + else + if (action == BZ_FINISH) { + s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto preswitch; + } + else + return BZ_PARAM_ERROR; + + case BZ_M_FLUSHING: + if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; + + case BZ_M_FINISHING: + if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR; + progress = handle_compress ( strm ); + if (!progress) return BZ_SEQUENCE_ERROR; + if (s->avail_in_expect > 0 || !isempty_RL(s) || + s->state_out_pos < s->numZ) return BZ_FINISH_OK; + s->mode = BZ_M_IDLE; + return BZ_STREAM_END; + } + return BZ_OK; /*--not reached--*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) +{ + EState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->arr1 != NULL) BZFREE(s->arr1); + if (s->arr2 != NULL) BZFREE(s->arr2); + if (s->ftab != NULL) BZFREE(s->ftab); + BZFREE(strm->state); + + strm->state = NULL; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/*--- Decompression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressInit) + ( bz_stream* strm, + int verbosity, + int small ) +{ + DState* s; + + if (!bz_config_ok()) return BZ_CONFIG_ERROR; + + if (strm == NULL) return BZ_PARAM_ERROR; + if (small != 0 && small != 1) return BZ_PARAM_ERROR; + if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; + + if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; + if (strm->bzfree == NULL) strm->bzfree = default_bzfree; + + s = BZALLOC( sizeof(DState) ); + if (s == NULL) return BZ_MEM_ERROR; + s->strm = strm; + strm->state = s; + s->state = BZ_X_MAGIC_1; + s->bsLive = 0; + s->bsBuff = 0; + s->calculatedCombinedCRC = 0; + strm->total_in_lo32 = 0; + strm->total_in_hi32 = 0; + strm->total_out_lo32 = 0; + strm->total_out_hi32 = 0; + s->smallDecompress = (Bool)small; + s->ll4 = NULL; + s->ll16 = NULL; + s->tt = NULL; + s->currBlockNo = 0; + s->verbosity = verbosity; + + return BZ_OK; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_FAST ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + /* restore */ + UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; + UChar c_state_out_ch = s->state_out_ch; + Int32 c_state_out_len = s->state_out_len; + Int32 c_nblock_used = s->nblock_used; + Int32 c_k0 = s->k0; + UInt32* c_tt = s->tt; + UInt32 c_tPos = s->tPos; + char* cs_next_out = s->strm->next_out; + unsigned int cs_avail_out = s->strm->avail_out; + Int32 ro_blockSize100k = s->blockSize100k; + /* end restore */ + + UInt32 avail_out_INIT = cs_avail_out; + Int32 s_save_nblockPP = s->save_nblock+1; + unsigned int total_out_lo32_old; + + while (True) { + + /* try to finish existing run */ + if (c_state_out_len > 0) { + while (True) { + if (cs_avail_out == 0) goto return_notr; + if (c_state_out_len == 1) break; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + c_state_out_len--; + cs_next_out++; + cs_avail_out--; + } + s_state_out_len_eq_one: + { + if (cs_avail_out == 0) { + c_state_out_len = 1; goto return_notr; + }; + *( (UChar*)(cs_next_out) ) = c_state_out_ch; + BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); + cs_next_out++; + cs_avail_out--; + } + } + /* Only caused by corrupt data stream? */ + if (c_nblock_used > s_save_nblockPP) + return True; + + /* can a new run be started? */ + if (c_nblock_used == s_save_nblockPP) { + c_state_out_len = 0; goto return_notr; + }; + c_state_out_ch = c_k0; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (k1 != c_k0) { + c_k0 = k1; goto s_state_out_len_eq_one; + }; + if (c_nblock_used == s_save_nblockPP) + goto s_state_out_len_eq_one; + + c_state_out_len = 2; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + c_state_out_len = 3; + BZ_GET_FAST_C(k1); c_nblock_used++; + if (c_nblock_used == s_save_nblockPP) continue; + if (k1 != c_k0) { c_k0 = k1; continue; }; + + BZ_GET_FAST_C(k1); c_nblock_used++; + c_state_out_len = ((Int32)k1) + 4; + BZ_GET_FAST_C(c_k0); c_nblock_used++; + } + + return_notr: + total_out_lo32_old = s->strm->total_out_lo32; + s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); + if (s->strm->total_out_lo32 < total_out_lo32_old) + s->strm->total_out_hi32++; + + /* save */ + s->calculatedBlockCRC = c_calculatedBlockCRC; + s->state_out_ch = c_state_out_ch; + s->state_out_len = c_state_out_len; + s->nblock_used = c_nblock_used; + s->k0 = c_k0; + s->tt = c_tt; + s->tPos = c_tPos; + s->strm->next_out = cs_next_out; + s->strm->avail_out = cs_avail_out; + /* end save */ + } + return False; +} + + + +/*---------------------------------------------------*/ +__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) +{ + Int32 nb, na, mid; + nb = 0; + na = 256; + do { + mid = (nb + na) >> 1; + if (indx >= cftab[mid]) nb = mid; else na = mid; + } + while (na - nb != 1); + return nb; +} + + +/*---------------------------------------------------*/ +/* Return True iff data corruption is discovered. + Returns False if there is no problem. +*/ +static +Bool unRLE_obuf_to_output_SMALL ( DState* s ) +{ + UChar k1; + + if (s->blockRandomised) { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; + k1 ^= BZ_RAND_MASK; s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; + s->k0 ^= BZ_RAND_MASK; s->nblock_used++; + } + + } else { + + while (True) { + /* try to finish existing run */ + while (True) { + if (s->strm->avail_out == 0) return False; + if (s->state_out_len == 0) break; + *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; + BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); + s->state_out_len--; + s->strm->next_out++; + s->strm->avail_out--; + s->strm->total_out_lo32++; + if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; + } + + /* can a new run be started? */ + if (s->nblock_used == s->save_nblock+1) return False; + + /* Only caused by corrupt data stream? */ + if (s->nblock_used > s->save_nblock+1) + return True; + + s->state_out_len = 1; + s->state_out_ch = s->k0; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 2; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + s->state_out_len = 3; + BZ_GET_SMALL(k1); s->nblock_used++; + if (s->nblock_used == s->save_nblock+1) continue; + if (k1 != s->k0) { s->k0 = k1; continue; }; + + BZ_GET_SMALL(k1); s->nblock_used++; + s->state_out_len = ((Int32)k1) + 4; + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) +{ + Bool corrupt; + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + while (True) { + if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; + if (s->state == BZ_X_OUTPUT) { + if (s->smallDecompress) + corrupt = unRLE_obuf_to_output_SMALL ( s ); else + corrupt = unRLE_obuf_to_output_FAST ( s ); + if (corrupt) return BZ_DATA_ERROR; + if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { + BZ_FINALISE_CRC ( s->calculatedBlockCRC ); + if (s->verbosity >= 3) + VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, + s->calculatedBlockCRC ); + if (s->verbosity >= 2) VPrintf0 ( "]" ); + if (s->calculatedBlockCRC != s->storedBlockCRC) + return BZ_DATA_ERROR; + s->calculatedCombinedCRC + = (s->calculatedCombinedCRC << 1) | + (s->calculatedCombinedCRC >> 31); + s->calculatedCombinedCRC ^= s->calculatedBlockCRC; + s->state = BZ_X_BLKHDR_1; + } else { + return BZ_OK; + } + } + if (s->state >= BZ_X_MAGIC_1) { + Int32 r = BZ2_decompress ( s ); + if (r == BZ_STREAM_END) { + if (s->verbosity >= 3) + VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", + s->storedCombinedCRC, s->calculatedCombinedCRC ); + if (s->calculatedCombinedCRC != s->storedCombinedCRC) + return BZ_DATA_ERROR; + return r; + } + if (s->state != BZ_X_OUTPUT) return r; + } + } + + AssertH ( 0, 6001 ); + + return 0; /*NOTREACHED*/ +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) +{ + DState* s; + if (strm == NULL) return BZ_PARAM_ERROR; + s = strm->state; + if (s == NULL) return BZ_PARAM_ERROR; + if (s->strm != strm) return BZ_PARAM_ERROR; + + if (s->tt != NULL) BZFREE(s->tt); + if (s->ll16 != NULL) BZFREE(s->ll16); + if (s->ll4 != NULL) BZFREE(s->ll4); + + BZFREE(strm->state); + strm->state = NULL; + + return BZ_OK; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ +/*--- File I/O stuff ---*/ +/*---------------------------------------------------*/ + +#define BZ_SETERR(eee) \ +{ \ + if (bzerror != NULL) *bzerror = eee; \ + if (bzf != NULL) bzf->lastErr = eee; \ +} + +typedef + struct { + FILE* handle; + Char buf[BZ_MAX_UNUSED]; + Int32 bufN; + Bool writing; + bz_stream strm; + Int32 lastErr; + Bool initialisedOk; + } + bzFile; + + +/*---------------------------------------------*/ +static Bool myfeof ( FILE* f ) +{ + Int32 c = fgetc ( f ); + if (c == EOF) return True; + ungetc ( c, f ); + return False; +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzWriteOpen) + ( int* bzerror, + FILE* f, + int blockSize100k, + int verbosity, + int workFactor ) +{ + Int32 ret; + bzFile* bzf = NULL; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (blockSize100k < 1 || blockSize100k > 9) || + (workFactor < 0 || workFactor > 250) || + (verbosity < 0 || verbosity > 4)) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + bzf->initialisedOk = False; + bzf->bufN = 0; + bzf->handle = f; + bzf->writing = True; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + if (workFactor == 0) workFactor = 30; + ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = 0; + bzf->initialisedOk = True; + return bzf; +} + + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWrite) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return; }; + + bzf->strm.avail_in = len; + bzf->strm.next_in = buf; + + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); + if (ret != BZ_RUN_OK) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (bzf->strm.avail_in == 0) + { BZ_SETERR(BZ_OK); return; }; + } +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzWriteClose) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in, + unsigned int* nbytes_out ) +{ + BZ2_bzWriteClose64 ( bzerror, b, abandon, + nbytes_in, NULL, nbytes_out, NULL ); +} + + +void BZ_API(BZ2_bzWriteClose64) + ( int* bzerror, + BZFILE* b, + int abandon, + unsigned int* nbytes_in_lo32, + unsigned int* nbytes_in_hi32, + unsigned int* nbytes_out_lo32, + unsigned int* nbytes_out_hi32 ) +{ + Int32 n, n2, ret; + bzFile* bzf = (bzFile*)b; + + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + if (!(bzf->writing)) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + + if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; + if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; + if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; + if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; + + if ((!abandon) && bzf->lastErr == BZ_OK) { + while (True) { + bzf->strm.avail_out = BZ_MAX_UNUSED; + bzf->strm.next_out = bzf->buf; + ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); + if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return; }; + + if (bzf->strm.avail_out < BZ_MAX_UNUSED) { + n = BZ_MAX_UNUSED - bzf->strm.avail_out; + n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), + n, bzf->handle ); + if (n != n2 || ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (ret == BZ_STREAM_END) break; + } + } + + if ( !abandon && !ferror ( bzf->handle ) ) { + fflush ( bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return; }; + } + + if (nbytes_in_lo32 != NULL) + *nbytes_in_lo32 = bzf->strm.total_in_lo32; + if (nbytes_in_hi32 != NULL) + *nbytes_in_hi32 = bzf->strm.total_in_hi32; + if (nbytes_out_lo32 != NULL) + *nbytes_out_lo32 = bzf->strm.total_out_lo32; + if (nbytes_out_hi32 != NULL) + *nbytes_out_hi32 = bzf->strm.total_out_hi32; + + BZ_SETERR(BZ_OK); + BZ2_bzCompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +BZFILE* BZ_API(BZ2_bzReadOpen) + ( int* bzerror, + FILE* f, + int verbosity, + int small, + void* unused, + int nUnused ) +{ + bzFile* bzf = NULL; + int ret; + + BZ_SETERR(BZ_OK); + + if (f == NULL || + (small != 0 && small != 1) || + (verbosity < 0 || verbosity > 4) || + (unused == NULL && nUnused != 0) || + (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) + { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; + + if (ferror(f)) + { BZ_SETERR(BZ_IO_ERROR); return NULL; }; + + bzf = malloc ( sizeof(bzFile) ); + if (bzf == NULL) + { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; + + BZ_SETERR(BZ_OK); + + bzf->initialisedOk = False; + bzf->handle = f; + bzf->bufN = 0; + bzf->writing = False; + bzf->strm.bzalloc = NULL; + bzf->strm.bzfree = NULL; + bzf->strm.opaque = NULL; + + while (nUnused > 0) { + bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; + unused = ((void*)( 1 + ((UChar*)(unused)) )); + nUnused--; + } + + ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); + if (ret != BZ_OK) + { BZ_SETERR(ret); free(bzf); return NULL; }; + + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + + bzf->initialisedOk = True; + return bzf; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) +{ + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + if (bzf == NULL) + { BZ_SETERR(BZ_OK); return; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + + if (bzf->initialisedOk) + (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); + free ( bzf ); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzRead) + ( int* bzerror, + BZFILE* b, + void* buf, + int len ) +{ + Int32 n, ret; + bzFile* bzf = (bzFile*)b; + + BZ_SETERR(BZ_OK); + + if (bzf == NULL || buf == NULL || len < 0) + { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; + + if (bzf->writing) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; + + if (len == 0) + { BZ_SETERR(BZ_OK); return 0; }; + + bzf->strm.avail_out = len; + bzf->strm.next_out = buf; + + while (True) { + + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + + if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { + n = fread ( bzf->buf, sizeof(UChar), + BZ_MAX_UNUSED, bzf->handle ); + if (ferror(bzf->handle)) + { BZ_SETERR(BZ_IO_ERROR); return 0; }; + bzf->bufN = n; + bzf->strm.avail_in = bzf->bufN; + bzf->strm.next_in = bzf->buf; + } + + ret = BZ2_bzDecompress ( &(bzf->strm) ); + + if (ret != BZ_OK && ret != BZ_STREAM_END) + { BZ_SETERR(ret); return 0; }; + + if (ret == BZ_OK && myfeof(bzf->handle) && + bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) + { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; + + if (ret == BZ_STREAM_END) + { BZ_SETERR(BZ_STREAM_END); + return len - bzf->strm.avail_out; }; + if (bzf->strm.avail_out == 0) + { BZ_SETERR(BZ_OK); return len; }; + + } + + return 0; /*not reached*/ +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzReadGetUnused) + ( int* bzerror, + BZFILE* b, + void** unused, + int* nUnused ) +{ + bzFile* bzf = (bzFile*)b; + if (bzf == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + if (bzf->lastErr != BZ_STREAM_END) + { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; + if (unused == NULL || nUnused == NULL) + { BZ_SETERR(BZ_PARAM_ERROR); return; }; + + BZ_SETERR(BZ_OK); + *nUnused = bzf->strm.avail_in; + *unused = bzf->strm.next_in; +} +#endif + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffCompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k, + int verbosity, + int workFactor ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + blockSize100k < 1 || blockSize100k > 9 || + verbosity < 0 || verbosity > 4 || + workFactor < 0 || workFactor > 250) + return BZ_PARAM_ERROR; + + if (workFactor == 0) workFactor = 30; + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzCompressInit ( &strm, blockSize100k, + verbosity, workFactor ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress ( &strm, BZ_FINISH ); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd ( &strm ); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzBuffToBuffDecompress) + ( char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int small, + int verbosity ) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL || + source == NULL || + (small != 0 && small != 1) || + verbosity < 0 || verbosity > 4) + return BZ_PARAM_ERROR; + + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); + if (ret != BZ_OK) return ret; + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzDecompress ( &strm ); + if (ret == BZ_OK) goto output_overflow_or_eof; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzDecompressEnd ( &strm ); + return BZ_OK; + + output_overflow_or_eof: + if (strm.avail_out > 0) { + BZ2_bzDecompressEnd ( &strm ); + return BZ_UNEXPECTED_EOF; + } else { + BZ2_bzDecompressEnd ( &strm ); + return BZ_OUTBUFF_FULL; + }; + + errhandler: + BZ2_bzDecompressEnd ( &strm ); + return ret; +} + + +/*---------------------------------------------------*/ +/*-- + Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) + to support better zlib compatibility. + This code is not _officially_ part of libbzip2 (yet); + I haven't tested it, documented it, or considered the + threading-safeness of it. + If this code breaks, please contact both Yoshioka and me. +--*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +/*-- + return version like "0.9.5d, 4-Sept-1999". +--*/ +const char * BZ_API(BZ2_bzlibVersion)(void) +{ + return BZ_VERSION; +} + + +#ifndef BZ_NO_STDIO +/*---------------------------------------------------*/ + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +# include +# include +# if defined(_MSC_VER) +# define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY) +# else +# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) +# endif +#else +# define SET_BINARY_MODE(file) +#endif +static +BZFILE * bzopen_or_bzdopen + ( const char *path, /* no use when bzdopen */ + int fd, /* no use when bzdopen */ + const char *mode, + int open_mode) /* bzopen: 0, bzdopen:1 */ +{ + int bzerr; + char unused[BZ_MAX_UNUSED]; + int blockSize100k = 9; + int writing = 0; + char mode2[10] = ""; + FILE *fp = NULL; + BZFILE *bzfp = NULL; + int verbosity = 0; + int workFactor = 30; + int smallMode = 0; + int nUnused = 0; + + if (mode == NULL) return NULL; + while (*mode) { + switch (*mode) { + case 'r': + writing = 0; break; + case 'w': + writing = 1; break; + case 's': + smallMode = 1; break; + default: + if (isdigit((int)(*mode))) { + blockSize100k = *mode-BZ_HDR_0; + } + } + mode++; + } + strcat(mode2, writing ? "w" : "r" ); + strcat(mode2,"b"); /* binary mode */ + + if (open_mode==0) { + if (path==NULL || strcmp(path,"")==0) { + fp = (writing ? stdout : stdin); + SET_BINARY_MODE(fp); + } else { + fp = fopen(path,mode2); + } + } else { +#ifdef BZ_STRICT_ANSI + fp = NULL; +#else +# if defined(_MSC_VER) + fp = _fdopen(fd,mode2); +# else + fp = fdopen(fd,mode2); +# endif +#endif + } + if (fp == NULL) return NULL; + + if (writing) { + /* Guard against total chaos and anarchy -- JRS */ + if (blockSize100k < 1) blockSize100k = 1; + if (blockSize100k > 9) blockSize100k = 9; + bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, + verbosity,workFactor); + } else { + bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, + unused,nUnused); + } + if (bzfp == NULL) { + if (fp != stdin && fp != stdout) fclose(fp); + return NULL; + } + return bzfp; +} + + +/*---------------------------------------------------*/ +/*-- + open file for read or write. + ex) bzopen("file","w9") + case path="" or NULL => use stdin or stdout. +--*/ +BZFILE * BZ_API(BZ2_bzopen) + ( const char *path, + const char *mode ) +{ + return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); +} + + +/*---------------------------------------------------*/ +BZFILE * BZ_API(BZ2_bzdopen) + ( int fd, + const char *mode ) +{ + return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) +{ + int bzerr, nread; + if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; + nread = BZ2_bzRead(&bzerr,b,buf,len); + if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { + return nread; + } else { + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) +{ + int bzerr; + + BZ2_bzWrite(&bzerr,b,buf,len); + if(bzerr == BZ_OK){ + return len; + }else{ + return -1; + } +} + + +/*---------------------------------------------------*/ +int BZ_API(BZ2_bzflush) (BZFILE *b) +{ + /* do nothing now... */ + return 0; +} + + +/*---------------------------------------------------*/ +void BZ_API(BZ2_bzclose) (BZFILE* b) +{ + int bzerr; + FILE *fp; + + if (b==NULL) {return;} + fp = ((bzFile *)b)->handle; + if(((bzFile*)b)->writing){ + BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); + if(bzerr != BZ_OK){ + BZ2_bzWriteClose(NULL,b,1,NULL,NULL); + } + }else{ + BZ2_bzReadClose(&bzerr,b); + } + if(fp!=stdin && fp!=stdout){ + fclose(fp); + } +} + + +/*---------------------------------------------------*/ +/*-- + return last error code +--*/ +static const char *bzerrorstrings[] = { + "OK" + ,"SEQUENCE_ERROR" + ,"PARAM_ERROR" + ,"MEM_ERROR" + ,"DATA_ERROR" + ,"DATA_ERROR_MAGIC" + ,"IO_ERROR" + ,"UNEXPECTED_EOF" + ,"OUTBUFF_FULL" + ,"CONFIG_ERROR" + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ + ,"???" /* for future */ +}; + + +const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) +{ + int err = ((bzFile *)b)->lastErr; + + if(err>0) err = 0; + *errnum = err; + return bzerrorstrings[err*-1]; +} +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/bzip2/src/bzlib_private.h b/dep/bzip2/src/bzlib_private.h new file mode 100644 index 0000000..e20ac7a --- /dev/null +++ b/dep/bzip2/src/bzlib_private.h @@ -0,0 +1,509 @@ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#ifndef _BZLIB_PRIVATE_H +#define _BZLIB_PRIVATE_H + +#include + +#ifndef BZ_NO_STDIO +#include +#include +#include +#endif + +#include "bzip2/bzlib.h" + + + +/*-- General stuff. --*/ + +#define BZ_VERSION "1.0.6, 6-Sept-2010" + +typedef char Char; +typedef unsigned char Bool; +typedef unsigned char UChar; +typedef int Int32; +typedef unsigned int UInt32; +typedef short Int16; +typedef unsigned short UInt16; + +#define True ((Bool)1) +#define False ((Bool)0) + +#ifndef __GNUC__ +#define __inline__ /* */ +#endif + +#ifndef BZ_NO_STDIO + +extern void BZ2_bz__AssertH__fail ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } + +#if BZ_DEBUG +#define AssertD(cond,msg) \ + { if (!(cond)) { \ + fprintf ( stderr, \ + "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ + exit(1); \ + }} +#else +#define AssertD(cond,msg) /* */ +#endif + +#define VPrintf0(zf) \ + fprintf(stderr,zf) +#define VPrintf1(zf,za1) \ + fprintf(stderr,zf,za1) +#define VPrintf2(zf,za1,za2) \ + fprintf(stderr,zf,za1,za2) +#define VPrintf3(zf,za1,za2,za3) \ + fprintf(stderr,zf,za1,za2,za3) +#define VPrintf4(zf,za1,za2,za3,za4) \ + fprintf(stderr,zf,za1,za2,za3,za4) +#define VPrintf5(zf,za1,za2,za3,za4,za5) \ + fprintf(stderr,zf,za1,za2,za3,za4,za5) + +#else + +extern void bz_internal_error ( int errcode ); +#define AssertH(cond,errcode) \ + { if (!(cond)) bz_internal_error ( errcode ); } +#define AssertD(cond,msg) do { } while (0) +#define VPrintf0(zf) do { } while (0) +#define VPrintf1(zf,za1) do { } while (0) +#define VPrintf2(zf,za1,za2) do { } while (0) +#define VPrintf3(zf,za1,za2,za3) do { } while (0) +#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) +#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) + +#endif + + +#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) +#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + + +/*-- Stuff for randomising repetitive blocks. --*/ + +extern Int32 BZ2_rNums[512]; + +#define BZ_RAND_DECLS \ + Int32 rNToGo; \ + Int32 rTPos \ + +#define BZ_RAND_INIT_MASK \ + s->rNToGo = 0; \ + s->rTPos = 0 \ + +#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) + +#define BZ_RAND_UPD_MASK \ + if (s->rNToGo == 0) { \ + s->rNToGo = BZ2_rNums[s->rTPos]; \ + s->rTPos++; \ + if (s->rTPos == 512) s->rTPos = 0; \ + } \ + s->rNToGo--; + + + +/*-- Stuff for doing CRCs. --*/ + +extern UInt32 BZ2_crc32Table[256]; + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(crcVar,cha) \ +{ \ + crcVar = (crcVar << 8) ^ \ + BZ2_crc32Table[(crcVar >> 24) ^ \ + ((UChar)cha)]; \ +} + + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + Int32 mode; + Int32 state; + + /* remembers avail_in when flush/finish requested */ + UInt32 avail_in_expect; + + /* for doing the block sorting */ + UInt32* arr1; + UInt32* arr2; + UInt32* ftab; + Int32 origPtr; + + /* aliases for arr1 and arr2 */ + UInt32* ptr; + UChar* block; + UInt16* mtfv; + UChar* zbits; + + /* for deciding when to use the fallback sorting algorithm */ + Int32 workFactor; + + /* run-length-encoding of the input */ + UInt32 state_in_ch; + Int32 state_in_len; + BZ_RAND_DECLS; + + /* input and output limits and current posns */ + Int32 nblock; + Int32 nblockMAX; + Int32 numZ; + Int32 state_out_pos; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + UChar unseqToSeq[256]; + + /* the buffer for bit stream creation */ + UInt32 bsBuff; + Int32 bsLive; + + /* block and combined CRCs */ + UInt32 blockCRC; + UInt32 combinedCRC; + + /* misc administratium */ + Int32 verbosity; + Int32 blockNo; + Int32 blockSize100k; + + /* stuff for coding the MTF values */ + Int32 nMTF; + Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + /* second dimension: only 3 needed; 4 makes index calculations faster */ + UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; + + } + EState; + + + +/*-- externs for compression. --*/ + +extern void +BZ2_blockSort ( EState* ); + +extern void +BZ2_compressBlock ( EState*, Bool ); + +extern void +BZ2_bsInitWrite ( EState* ); + +extern void +BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); + +extern void +BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); + + + +/*-- states for decompression. --*/ + +#define BZ_X_IDLE 1 +#define BZ_X_OUTPUT 2 + +#define BZ_X_MAGIC_1 10 +#define BZ_X_MAGIC_2 11 +#define BZ_X_MAGIC_3 12 +#define BZ_X_MAGIC_4 13 +#define BZ_X_BLKHDR_1 14 +#define BZ_X_BLKHDR_2 15 +#define BZ_X_BLKHDR_3 16 +#define BZ_X_BLKHDR_4 17 +#define BZ_X_BLKHDR_5 18 +#define BZ_X_BLKHDR_6 19 +#define BZ_X_BCRC_1 20 +#define BZ_X_BCRC_2 21 +#define BZ_X_BCRC_3 22 +#define BZ_X_BCRC_4 23 +#define BZ_X_RANDBIT 24 +#define BZ_X_ORIGPTR_1 25 +#define BZ_X_ORIGPTR_2 26 +#define BZ_X_ORIGPTR_3 27 +#define BZ_X_MAPPING_1 28 +#define BZ_X_MAPPING_2 29 +#define BZ_X_SELECTOR_1 30 +#define BZ_X_SELECTOR_2 31 +#define BZ_X_SELECTOR_3 32 +#define BZ_X_CODING_1 33 +#define BZ_X_CODING_2 34 +#define BZ_X_CODING_3 35 +#define BZ_X_MTF_1 36 +#define BZ_X_MTF_2 37 +#define BZ_X_MTF_3 38 +#define BZ_X_MTF_4 39 +#define BZ_X_MTF_5 40 +#define BZ_X_MTF_6 41 +#define BZ_X_ENDHDR_2 42 +#define BZ_X_ENDHDR_3 43 +#define BZ_X_ENDHDR_4 44 +#define BZ_X_ENDHDR_5 45 +#define BZ_X_ENDHDR_6 46 +#define BZ_X_CCRC_1 47 +#define BZ_X_CCRC_2 48 +#define BZ_X_CCRC_3 49 +#define BZ_X_CCRC_4 50 + + + +/*-- Constants for the fast MTF decoder. --*/ + +#define MTFA_SIZE 4096 +#define MTFL_SIZE 16 + + + +/*-- Structure holding all the decompression-side stuff. --*/ + +typedef + struct { + /* pointer back to the struct bz_stream */ + bz_stream* strm; + + /* state indicator for this stream */ + Int32 state; + + /* for doing the final run-length decoding */ + UChar state_out_ch; + Int32 state_out_len; + Bool blockRandomised; + BZ_RAND_DECLS; + + /* the buffer for bit stream reading */ + UInt32 bsBuff; + Int32 bsLive; + + /* misc administratium */ + Int32 blockSize100k; + Bool smallDecompress; + Int32 currBlockNo; + Int32 verbosity; + + /* for undoing the Burrows-Wheeler transform */ + Int32 origPtr; + UInt32 tPos; + Int32 k0; + Int32 unzftab[256]; + Int32 nblock_used; + Int32 cftab[257]; + Int32 cftabCopy[257]; + + /* for undoing the Burrows-Wheeler transform (FAST) */ + UInt32 *tt; + + /* for undoing the Burrows-Wheeler transform (SMALL) */ + UInt16 *ll16; + UChar *ll4; + + /* stored and calculated CRCs */ + UInt32 storedBlockCRC; + UInt32 storedCombinedCRC; + UInt32 calculatedBlockCRC; + UInt32 calculatedCombinedCRC; + + /* map of bytes used in block */ + Int32 nInUse; + Bool inUse[256]; + Bool inUse16[16]; + UChar seqToUnseq[256]; + + /* for decoding the MTF values */ + UChar mtfa [MTFA_SIZE]; + Int32 mtfbase[256 / MTFL_SIZE]; + UChar selector [BZ_MAX_SELECTORS]; + UChar selectorMtf[BZ_MAX_SELECTORS]; + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 minLens[BZ_N_GROUPS]; + + /* save area for scalars in the main decompress code */ + Int32 save_i; + Int32 save_j; + Int32 save_t; + Int32 save_alphaSize; + Int32 save_nGroups; + Int32 save_nSelectors; + Int32 save_EOB; + Int32 save_groupNo; + Int32 save_groupPos; + Int32 save_nextSym; + Int32 save_nblockMAX; + Int32 save_nblock; + Int32 save_es; + Int32 save_N; + Int32 save_curr; + Int32 save_zt; + Int32 save_zn; + Int32 save_zvec; + Int32 save_zj; + Int32 save_gSel; + Int32 save_gMinlen; + Int32* save_gLimit; + Int32* save_gBase; + Int32* save_gPerm; + + } + DState; + + + +/*-- Macros for decompression. --*/ + +#define BZ_GET_FAST(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + s->tPos = s->tt[s->tPos]; \ + cccc = (UChar)(s->tPos & 0xff); \ + s->tPos >>= 8; + +#define BZ_GET_FAST_C(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \ + c_tPos = c_tt[c_tPos]; \ + cccc = (UChar)(c_tPos & 0xff); \ + c_tPos >>= 8; + +#define SET_LL4(i,n) \ + { if (((i) & 0x1) == 0) \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ + s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ + } + +#define GET_LL4(i) \ + ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) + +#define SET_LL(i,n) \ + { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ + SET_LL4(i, n >> 16); \ + } + +#define GET_LL(i) \ + (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) + +#define BZ_GET_SMALL(cccc) \ + /* c_tPos is unsigned, hence test < 0 is pointless. */ \ + if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ + cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ + s->tPos = GET_LL(s->tPos); + + +/*-- externs for decompression. --*/ + +extern Int32 +BZ2_indexIntoF ( Int32, Int32* ); + +extern Int32 +BZ2_decompress ( DState* ); + +extern void +BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, + Int32, Int32, Int32 ); + + +#endif + + +/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ + +#ifdef BZ_NO_STDIO +#ifndef NULL +#define NULL 0 +#endif +#endif + + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/bzip2/src/compress.c b/dep/bzip2/src/compress.c new file mode 100644 index 0000000..0187324 --- /dev/null +++ b/dep/bzip2/src/compress.c @@ -0,0 +1,672 @@ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +/* CHANGES + 0.9.0 -- original version. + 0.9.0a/b -- no changes in this file. + 0.9.0c -- changed setting of nGroups in sendMTFValues() + so as to do a bit better on small files +*/ + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +void BZ2_bsInitWrite ( EState* s ) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static +void bsFinishWrite ( EState* s ) +{ + while (s->bsLive > 0) { + s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); + s->numZ++; + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +#define bsNEEDW(nz) \ +{ \ + while (s->bsLive >= 8) { \ + s->zbits[s->numZ] \ + = (UChar)(s->bsBuff >> 24); \ + s->numZ++; \ + s->bsBuff <<= 8; \ + s->bsLive -= 8; \ + } \ +} + + +/*---------------------------------------------------*/ +static +__inline__ +void bsW ( EState* s, Int32 n, UInt32 v ) +{ + bsNEEDW ( n ); + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} + + +/*---------------------------------------------------*/ +static +void bsPutUInt32 ( EState* s, UInt32 u ) +{ + bsW ( s, 8, (u >> 24) & 0xffL ); + bsW ( s, 8, (u >> 16) & 0xffL ); + bsW ( s, 8, (u >> 8) & 0xffL ); + bsW ( s, 8, u & 0xffL ); +} + + +/*---------------------------------------------------*/ +static +void bsPutUChar ( EState* s, UChar c ) +{ + bsW( s, 8, (UInt32)c ); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e ( EState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->unseqToSeq[i] = s->nInUse; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +static +void generateMTFValues ( EState* s ) +{ + UChar yy[256]; + Int32 i, j; + Int32 zPend; + Int32 wr; + Int32 EOB; + + /* + After sorting (eg, here), + s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, + and + ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] + holds the original block data. + + The first thing to do is generate the MTF values, + and put them in + ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. + Because there are strictly fewer or equal MTF values + than block values, ptr values in this area are overwritten + with MTF values only when they are no longer needed. + + The final compressed bitstream is generated into the + area starting at + (UChar*) (&((UChar*)s->arr2)[s->nblock]) + + These storage aliases are set up in bzCompressInit(), + except for the last one, which is arranged in + compressBlock(). + */ + UInt32* ptr = s->ptr; + UChar* block = s->block; + UInt16* mtfv = s->mtfv; + + makeMaps_e ( s ); + EOB = s->nInUse+1; + + for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; + + wr = 0; + zPend = 0; + for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; + + for (i = 0; i < s->nblock; i++) { + UChar ll_i; + AssertD ( wr <= i, "generateMTFValues(1)" ); + j = ptr[i]-1; if (j < 0) j += s->nblock; + ll_i = s->unseqToSeq[block[j]]; + AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); + + if (yy[0] == ll_i) { + zPend++; + } else { + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + { + register UChar rtmp; + register UChar* ryy_j; + register UChar rll_i; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + rll_i = ll_i; + while ( rll_i != rtmp ) { + register UChar rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + }; + yy[0] = rtmp; + j = ryy_j - &(yy[0]); + mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; + } + + } + } + + if (zPend > 0) { + zPend--; + while (True) { + if (zPend & 1) { + mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } + if (zPend < 2) break; + zPend = (zPend - 2) / 2; + }; + zPend = 0; + } + + mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static +void sendMTFValues ( EState* s ) +{ + Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; + Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; + Int32 nGroups, nBytes; + + /*-- + UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + is a global since the decoder also needs it. + + Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + are also globals only used in this proc. + Made global to keep stack frame size small. + --*/ + + + UInt16 cost[BZ_N_GROUPS]; + Int32 fave[BZ_N_GROUPS]; + + UInt16* mtfv = s->mtfv; + + if (s->verbosity >= 3) + VPrintf3( " %d in block, %d after MTF & 1-2 coding, " + "%d+2 syms in use\n", + s->nblock, s->nMTF, s->nInUse ); + + alphaSize = s->nInUse+2; + for (t = 0; t < BZ_N_GROUPS; t++) + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + + /*--- Decide how many coding tables to use ---*/ + AssertH ( s->nMTF > 0, 3001 ); + if (s->nMTF < 200) nGroups = 2; else + if (s->nMTF < 600) nGroups = 3; else + if (s->nMTF < 1200) nGroups = 4; else + if (s->nMTF < 2400) nGroups = 5; else + nGroups = 6; + + /*--- Generate an initial set of coding tables ---*/ + { + Int32 nPart, remF, tFreq, aFreq; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + tFreq = remF / nPart; + ge = gs-1; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize-1) { + ge++; + aFreq += s->mtfFreq[ge]; + } + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups-nPart) % 2 == 1)) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + if (s->verbosity >= 3) + VPrintf5( " initial group %d, [%d .. %d], " + "has %d syms (%4.1f%%)\n", + nPart, gs, ge, aFreq, + (100.0 * (float)aFreq) / (float)(s->nMTF) ); + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge+1; + remF -= aFreq; + } + } + + /*--- + Iterate up to BZ_N_ITERS times to improve the tables. + ---*/ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + + for (t = 0; t < nGroups; t++) fave[t] = 0; + + for (t = 0; t < nGroups; t++) + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + + /*--- + Set up an auxiliary length table which is used to fast-track + the common case (nGroups == 6). + ---*/ + if (nGroups == 6) { + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } + + nSelectors = 0; + totc = 0; + gs = 0; + while (True) { + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + + /*-- + Calculate the cost of this group as coded + by each of the coding tables. + --*/ + for (t = 0; t < nGroups; t++) cost[t] = 0; + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register UInt32 cost01, cost23, cost45; + register UInt16 icv; + cost01 = cost23 = cost45 = 0; + +# define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; \ + + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); + +# undef BZ_ITER + + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + UInt16 icv = mtfv[i]; + for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; + } + } + + /*-- + Find the coding table which is best for this group, + and record its identity in the selector table. + --*/ + bc = 999999999; bt = -1; + for (t = 0; t < nGroups; t++) + if (cost[t] < bc) { bc = cost[t]; bt = t; }; + totc += bc; + fave[bt]++; + s->selector[nSelectors] = bt; + nSelectors++; + + /*-- + Increment the symbol frequencies for the selected table. + --*/ + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + +# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ + + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); + +# undef BZ_ITUR + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) + s->rfreq[bt][ mtfv[i] ]++; + } + + gs = ge+1; + } + if (s->verbosity >= 3) { + VPrintf2 ( " pass %d: size is %d, grp uses are ", + iter+1, totc/8 ); + for (t = 0; t < nGroups; t++) + VPrintf1 ( "%d ", fave[t] ); + VPrintf0 ( "\n" ); + } + + /*-- + Recompute the tables based on the accumulated frequencies. + --*/ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), + alphaSize, 17 /*20*/ ); + } + + + AssertH( nGroups < 8, 3002 ); + AssertH( nSelectors < 32768 && + nSelectors <= (2 + (900000 / BZ_G_SIZE)), + 3003 ); + + + /*--- Compute MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + for (i = 0; i < nGroups; i++) pos[i] = i; + for (i = 0; i < nSelectors; i++) { + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while ( ll_i != tmp ) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + }; + pos[0] = tmp; + s->selectorMtf[i] = j; + } + }; + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); + AssertH ( !(minLen < 1), 3005 ); + BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), + minLen, maxLen, alphaSize ); + } + + /*--- Transmit the mapping table. ---*/ + { + Bool inUse16[16]; + for (i = 0; i < 16; i++) { + inUse16[i] = False; + for (j = 0; j < 16; j++) + if (s->inUse[i * 16 + j]) inUse16[i] = True; + } + + nBytes = s->numZ; + for (i = 0; i < 16; i++) + if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); + + for (i = 0; i < 16; i++) + if (inUse16[i]) + for (j = 0; j < 16; j++) { + if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); + } + + if (s->verbosity >= 3) + VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); + } + + /*--- Now the selectors. ---*/ + nBytes = s->numZ; + bsW ( s, 3, nGroups ); + bsW ( s, 15, nSelectors ); + for (i = 0; i < nSelectors; i++) { + for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); + bsW(s,1,0); + } + if (s->verbosity >= 3) + VPrintf1( "selectors %d, ", s->numZ-nBytes ); + + /*--- Now the coding tables. ---*/ + nBytes = s->numZ; + + for (t = 0; t < nGroups; t++) { + Int32 curr = s->len[t][0]; + bsW ( s, 5, curr ); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; + while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; + bsW ( s, 1, 0 ); + } + } + + if (s->verbosity >= 3) + VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); + + /*--- And finally, the block data proper ---*/ + nBytes = s->numZ; + selCtr = 0; + gs = 0; + while (True) { + if (gs >= s->nMTF) break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) ge = s->nMTF-1; + AssertH ( s->selector[selCtr] < nGroups, 3006 ); + + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + UInt16 mtfv_i; + UChar* s_len_sel_selCtr + = &(s->len[s->selector[selCtr]][0]); + Int32* s_code_sel_selCtr + = &(s->code[s->selector[selCtr]][0]); + +# define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW ( s, \ + s_len_sel_selCtr[mtfv_i], \ + s_code_sel_selCtr[mtfv_i] ) + + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); + +# undef BZ_ITAH + + } else { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + bsW ( s, + s->len [s->selector[selCtr]] [mtfv[i]], + s->code [s->selector[selCtr]] [mtfv[i]] ); + } + } + + + gs = ge+1; + selCtr++; + } + AssertH( selCtr == nSelectors, 3007 ); + + if (s->verbosity >= 3) + VPrintf1( "codes %d\n", s->numZ-nBytes ); +} + + +/*---------------------------------------------------*/ +void BZ2_compressBlock ( EState* s, Bool is_last_block ) +{ + if (s->nblock > 0) { + + BZ_FINALISE_CRC ( s->blockCRC ); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) s->numZ = 0; + + if (s->verbosity >= 2) + VPrintf4( " block %d: crc = 0x%08x, " + "combined CRC = 0x%08x, size = %d\n", + s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); + + BZ2_blockSort ( s ); + } + + s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite ( s ); + bsPutUChar ( s, BZ_HDR_B ); + bsPutUChar ( s, BZ_HDR_Z ); + bsPutUChar ( s, BZ_HDR_h ); + bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); + } + + if (s->nblock > 0) { + + bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); + bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); + bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutUInt32 ( s, s->blockCRC ); + + /*-- + Now a single bit indicating (non-)randomisation. + As of version 0.9.5, we use a better sorting algorithm + which makes randomisation unnecessary. So always set + the randomised bit to 'no'. Of course, the decoder + still needs to be able to handle randomised blocks + so as to maintain backwards compatibility with + older versions of bzip2. + --*/ + bsW(s,1,0); + + bsW ( s, 24, s->origPtr ); + generateMTFValues ( s ); + sendMTFValues ( s ); + } + + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + + bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); + bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); + bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); + bsPutUInt32 ( s, s->combinedCRC ); + if (s->verbosity >= 2) + VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); + bsFinishWrite ( s ); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/bzip2/src/crctable.c b/dep/bzip2/src/crctable.c new file mode 100644 index 0000000..00a2a9b --- /dev/null +++ b/dep/bzip2/src/crctable.c @@ -0,0 +1,104 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for doing CRCs ---*/ +/*--- crctable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*-- + I think this is an implementation of the AUTODIN-II, + Ethernet & FDDI 32-bit CRC standard. Vaguely derived + from code by Rob Warnock, in Section 51 of the + comp.compression FAQ. +--*/ + +UInt32 BZ2_crc32Table[256] = { + + /*-- Ugly, innit? --*/ + + 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, + 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, + 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, + 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, + 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, + 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, + 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, + 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, + 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, + 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, + 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, + 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, + 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, + 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, + 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, + 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, + 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, + 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, + 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, + 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, + 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, + 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, + 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, + 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, + 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, + 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, + 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, + 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, + 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, + 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, + 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, + 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, + 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, + 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, + 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, + 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, + 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, + 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, + 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, + 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, + 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, + 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, + 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, + 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, + 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, + 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, + 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, + 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, + 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, + 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, + 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, + 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, + 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, + 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, + 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, + 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, + 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, + 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, + 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, + 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, + 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, + 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, + 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, + 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L +}; + + +/*-------------------------------------------------------------*/ +/*--- end crctable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/bzip2/src/decompress.c b/dep/bzip2/src/decompress.c new file mode 100644 index 0000000..fd17c39 --- /dev/null +++ b/dep/bzip2/src/decompress.c @@ -0,0 +1,646 @@ + +/*-------------------------------------------------------------*/ +/*--- Decompression machinery ---*/ +/*--- decompress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------------*/ +static +void makeMaps_d ( DState* s ) +{ + Int32 i; + s->nInUse = 0; + for (i = 0; i < 256; i++) + if (s->inUse[i]) { + s->seqToUnseq[s->nInUse] = i; + s->nInUse++; + } +} + + +/*---------------------------------------------------*/ +#define RETURN(rrr) \ + { retVal = rrr; goto save_state_and_return; }; + +#define GET_BITS(lll,vvv,nnn) \ + case lll: s->state = lll; \ + while (True) { \ + if (s->bsLive >= nnn) { \ + UInt32 v; \ + v = (s->bsBuff >> \ + (s->bsLive-nnn)) & ((1 << nnn)-1); \ + s->bsLive -= nnn; \ + vvv = v; \ + break; \ + } \ + if (s->strm->avail_in == 0) RETURN(BZ_OK); \ + s->bsBuff \ + = (s->bsBuff << 8) | \ + ((UInt32) \ + (*((UChar*)(s->strm->next_in)))); \ + s->bsLive += 8; \ + s->strm->next_in++; \ + s->strm->avail_in--; \ + s->strm->total_in_lo32++; \ + if (s->strm->total_in_lo32 == 0) \ + s->strm->total_in_hi32++; \ + } + +#define GET_UCHAR(lll,uuu) \ + GET_BITS(lll,uuu,8) + +#define GET_BIT(lll,uuu) \ + GET_BITS(lll,uuu,1) + +/*---------------------------------------------------*/ +#define GET_MTF_VAL(label1,label2,lval) \ +{ \ + if (groupPos == 0) { \ + groupNo++; \ + if (groupNo >= nSelectors) \ + RETURN(BZ_DATA_ERROR); \ + groupPos = BZ_G_SIZE; \ + gSel = s->selector[groupNo]; \ + gMinlen = s->minLens[gSel]; \ + gLimit = &(s->limit[gSel][0]); \ + gPerm = &(s->perm[gSel][0]); \ + gBase = &(s->base[gSel][0]); \ + } \ + groupPos--; \ + zn = gMinlen; \ + GET_BITS(label1, zvec, zn); \ + while (1) { \ + if (zn > 20 /* the longest code */) \ + RETURN(BZ_DATA_ERROR); \ + if (zvec <= gLimit[zn]) break; \ + zn++; \ + GET_BIT(label2, zj); \ + zvec = (zvec << 1) | zj; \ + }; \ + if (zvec - gBase[zn] < 0 \ + || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ + RETURN(BZ_DATA_ERROR); \ + lval = gPerm[zvec - gBase[zn]]; \ +} + + +/*---------------------------------------------------*/ +Int32 BZ2_decompress ( DState* s ) +{ + UChar uc; + Int32 retVal; + Int32 minLen, maxLen; + bz_stream* strm = s->strm; + + /* stuff that needs to be saved/restored */ + Int32 i; + Int32 j; + Int32 t; + Int32 alphaSize; + Int32 nGroups; + Int32 nSelectors; + Int32 EOB; + Int32 groupNo; + Int32 groupPos; + Int32 nextSym; + Int32 nblockMAX; + Int32 nblock; + Int32 es; + Int32 N; + Int32 curr; + Int32 zt; + Int32 zn; + Int32 zvec; + Int32 zj; + Int32 gSel; + Int32 gMinlen; + Int32* gLimit; + Int32* gBase; + Int32* gPerm; + + if (s->state == BZ_X_MAGIC_1) { + /*initialise the save area*/ + s->save_i = 0; + s->save_j = 0; + s->save_t = 0; + s->save_alphaSize = 0; + s->save_nGroups = 0; + s->save_nSelectors = 0; + s->save_EOB = 0; + s->save_groupNo = 0; + s->save_groupPos = 0; + s->save_nextSym = 0; + s->save_nblockMAX = 0; + s->save_nblock = 0; + s->save_es = 0; + s->save_N = 0; + s->save_curr = 0; + s->save_zt = 0; + s->save_zn = 0; + s->save_zvec = 0; + s->save_zj = 0; + s->save_gSel = 0; + s->save_gMinlen = 0; + s->save_gLimit = NULL; + s->save_gBase = NULL; + s->save_gPerm = NULL; + } + + /*restore from the save area*/ + i = s->save_i; + j = s->save_j; + t = s->save_t; + alphaSize = s->save_alphaSize; + nGroups = s->save_nGroups; + nSelectors = s->save_nSelectors; + EOB = s->save_EOB; + groupNo = s->save_groupNo; + groupPos = s->save_groupPos; + nextSym = s->save_nextSym; + nblockMAX = s->save_nblockMAX; + nblock = s->save_nblock; + es = s->save_es; + N = s->save_N; + curr = s->save_curr; + zt = s->save_zt; + zn = s->save_zn; + zvec = s->save_zvec; + zj = s->save_zj; + gSel = s->save_gSel; + gMinlen = s->save_gMinlen; + gLimit = s->save_gLimit; + gBase = s->save_gBase; + gPerm = s->save_gPerm; + + retVal = BZ_OK; + + switch (s->state) { + + GET_UCHAR(BZ_X_MAGIC_1, uc); + if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_2, uc); + if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_UCHAR(BZ_X_MAGIC_3, uc) + if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); + + GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) + if (s->blockSize100k < (BZ_HDR_0 + 1) || + s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); + s->blockSize100k -= BZ_HDR_0; + + if (s->smallDecompress) { + s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); + s->ll4 = BZALLOC( + ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) + ); + if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); + } else { + s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); + if (s->tt == NULL) RETURN(BZ_MEM_ERROR); + } + + GET_UCHAR(BZ_X_BLKHDR_1, uc); + + if (uc == 0x17) goto endhdr_2; + if (uc != 0x31) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_2, uc); + if (uc != 0x41) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_3, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_4, uc); + if (uc != 0x26) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_5, uc); + if (uc != 0x53) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_BLKHDR_6, uc); + if (uc != 0x59) RETURN(BZ_DATA_ERROR); + + s->currBlockNo++; + if (s->verbosity >= 2) + VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); + + s->storedBlockCRC = 0; + GET_UCHAR(BZ_X_BCRC_1, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_2, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_3, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_BCRC_4, uc); + s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); + + GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); + + s->origPtr = 0; + GET_UCHAR(BZ_X_ORIGPTR_1, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_2, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + GET_UCHAR(BZ_X_ORIGPTR_3, uc); + s->origPtr = (s->origPtr << 8) | ((Int32)uc); + + if (s->origPtr < 0) + RETURN(BZ_DATA_ERROR); + if (s->origPtr > 10 + 100000*s->blockSize100k) + RETURN(BZ_DATA_ERROR); + + /*--- Receive the mapping table ---*/ + for (i = 0; i < 16; i++) { + GET_BIT(BZ_X_MAPPING_1, uc); + if (uc == 1) + s->inUse16[i] = True; else + s->inUse16[i] = False; + } + + for (i = 0; i < 256; i++) s->inUse[i] = False; + + for (i = 0; i < 16; i++) + if (s->inUse16[i]) + for (j = 0; j < 16; j++) { + GET_BIT(BZ_X_MAPPING_2, uc); + if (uc == 1) s->inUse[i * 16 + j] = True; + } + makeMaps_d ( s ); + if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); + alphaSize = s->nInUse+2; + + /*--- Now the selectors ---*/ + GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); + if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); + GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); + if (nSelectors < 1) RETURN(BZ_DATA_ERROR); + for (i = 0; i < nSelectors; i++) { + j = 0; + while (True) { + GET_BIT(BZ_X_SELECTOR_3, uc); + if (uc == 0) break; + j++; + if (j >= nGroups) RETURN(BZ_DATA_ERROR); + } + s->selectorMtf[i] = j; + } + + /*--- Undo the MTF values for the selectors. ---*/ + { + UChar pos[BZ_N_GROUPS], tmp, v; + for (v = 0; v < nGroups; v++) pos[v] = v; + + for (i = 0; i < nSelectors; i++) { + v = s->selectorMtf[i]; + tmp = pos[v]; + while (v > 0) { pos[v] = pos[v-1]; v--; } + pos[0] = tmp; + s->selector[i] = tmp; + } + } + + /*--- Now the coding tables ---*/ + for (t = 0; t < nGroups; t++) { + GET_BITS(BZ_X_CODING_1, curr, 5); + for (i = 0; i < alphaSize; i++) { + while (True) { + if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); + GET_BIT(BZ_X_CODING_2, uc); + if (uc == 0) break; + GET_BIT(BZ_X_CODING_3, uc); + if (uc == 0) curr++; else curr--; + } + s->len[t][i] = curr; + } + } + + /*--- Create the Huffman decoding tables ---*/ + for (t = 0; t < nGroups; t++) { + minLen = 32; + maxLen = 0; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + BZ2_hbCreateDecodeTables ( + &(s->limit[t][0]), + &(s->base[t][0]), + &(s->perm[t][0]), + &(s->len[t][0]), + minLen, maxLen, alphaSize + ); + s->minLens[t] = minLen; + } + + /*--- Now the MTF values ---*/ + + EOB = s->nInUse+1; + nblockMAX = 100000 * s->blockSize100k; + groupNo = -1; + groupPos = 0; + + for (i = 0; i <= 255; i++) s->unzftab[i] = 0; + + /*-- MTF init --*/ + { + Int32 ii, jj, kk; + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + /*-- end MTF init --*/ + + nblock = 0; + GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); + + while (True) { + + if (nextSym == EOB) break; + + if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { + + es = -1; + N = 1; + do { + /* Check that N doesn't get too big, so that es doesn't + go negative. The maximum value that can be + RUNA/RUNB encoded is equal to the block size (post + the initial RLE), viz, 900k, so bounding N at 2 + million should guard against overflow without + rejecting any legitimate inputs. */ + if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR); + if (nextSym == BZ_RUNA) es = es + (0+1) * N; else + if (nextSym == BZ_RUNB) es = es + (1+1) * N; + N = N * 2; + GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); + } + while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); + + es++; + uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; + s->unzftab[uc] += es; + + if (s->smallDecompress) + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->ll16[nblock] = (UInt16)uc; + nblock++; + es--; + } + else + while (es > 0) { + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + s->tt[nblock] = (UInt32)uc; + nblock++; + es--; + }; + + continue; + + } else { + + if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); + + /*-- uc = MTF ( nextSym-1 ) --*/ + { + Int32 ii, jj, kk, pp, lno, off; + UInt32 nn; + nn = (UInt32)(nextSym - 1); + + if (nn < MTFL_SIZE) { + /* avoid general-case expense */ + pp = s->mtfbase[0]; + uc = s->mtfa[pp+nn]; + while (nn > 3) { + Int32 z = pp+nn; + s->mtfa[(z) ] = s->mtfa[(z)-1]; + s->mtfa[(z)-1] = s->mtfa[(z)-2]; + s->mtfa[(z)-2] = s->mtfa[(z)-3]; + s->mtfa[(z)-3] = s->mtfa[(z)-4]; + nn -= 4; + } + while (nn > 0) { + s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; + }; + s->mtfa[pp] = uc; + } else { + /* general case */ + lno = nn / MTFL_SIZE; + off = nn % MTFL_SIZE; + pp = s->mtfbase[lno] + off; + uc = s->mtfa[pp]; + while (pp > s->mtfbase[lno]) { + s->mtfa[pp] = s->mtfa[pp-1]; pp--; + }; + s->mtfbase[lno]++; + while (lno > 0) { + s->mtfbase[lno]--; + s->mtfa[s->mtfbase[lno]] + = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; + lno--; + } + s->mtfbase[0]--; + s->mtfa[s->mtfbase[0]] = uc; + if (s->mtfbase[0] == 0) { + kk = MTFA_SIZE-1; + for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { + for (jj = MTFL_SIZE-1; jj >= 0; jj--) { + s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; + kk--; + } + s->mtfbase[ii] = kk + 1; + } + } + } + } + /*-- end uc = MTF ( nextSym-1 ) --*/ + + s->unzftab[s->seqToUnseq[uc]]++; + if (s->smallDecompress) + s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else + s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); + nblock++; + + GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); + continue; + } + } + + /* Now we know what nblock is, we can do a better sanity + check on s->origPtr. + */ + if (s->origPtr < 0 || s->origPtr >= nblock) + RETURN(BZ_DATA_ERROR); + + /*-- Set up cftab to facilitate generation of T^(-1) --*/ + /* Check: unzftab entries in range. */ + for (i = 0; i <= 255; i++) { + if (s->unzftab[i] < 0 || s->unzftab[i] > nblock) + RETURN(BZ_DATA_ERROR); + } + /* Actually generate cftab. */ + s->cftab[0] = 0; + for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; + for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; + /* Check: cftab entries in range. */ + for (i = 0; i <= 256; i++) { + if (s->cftab[i] < 0 || s->cftab[i] > nblock) { + /* s->cftab[i] can legitimately be == nblock */ + RETURN(BZ_DATA_ERROR); + } + } + /* Check: cftab entries non-descending. */ + for (i = 1; i <= 256; i++) { + if (s->cftab[i-1] > s->cftab[i]) { + RETURN(BZ_DATA_ERROR); + } + } + + s->state_out_len = 0; + s->state_out_ch = 0; + BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); + s->state = BZ_X_OUTPUT; + if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); + + if (s->smallDecompress) { + + /*-- Make a copy of cftab, used in generation of T --*/ + for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; + + /*-- compute the T vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->ll16[i]); + SET_LL(i, s->cftabCopy[uc]); + s->cftabCopy[uc]++; + } + + /*-- Compute T^(-1) by pointer reversal on T --*/ + i = s->origPtr; + j = GET_LL(i); + do { + Int32 tmp = GET_LL(j); + SET_LL(j, i); + i = j; + j = tmp; + } + while (i != s->origPtr); + + s->tPos = s->origPtr; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_SMALL(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_SMALL(s->k0); s->nblock_used++; + } + + } else { + + /*-- compute the T^(-1) vector --*/ + for (i = 0; i < nblock; i++) { + uc = (UChar)(s->tt[i] & 0xff); + s->tt[s->cftab[uc]] |= (i << 8); + s->cftab[uc]++; + } + + s->tPos = s->tt[s->origPtr] >> 8; + s->nblock_used = 0; + if (s->blockRandomised) { + BZ_RAND_INIT_MASK; + BZ_GET_FAST(s->k0); s->nblock_used++; + BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; + } else { + BZ_GET_FAST(s->k0); s->nblock_used++; + } + + } + + RETURN(BZ_OK); + + + + endhdr_2: + + GET_UCHAR(BZ_X_ENDHDR_2, uc); + if (uc != 0x72) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_3, uc); + if (uc != 0x45) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_4, uc); + if (uc != 0x38) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_5, uc); + if (uc != 0x50) RETURN(BZ_DATA_ERROR); + GET_UCHAR(BZ_X_ENDHDR_6, uc); + if (uc != 0x90) RETURN(BZ_DATA_ERROR); + + s->storedCombinedCRC = 0; + GET_UCHAR(BZ_X_CCRC_1, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_2, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_3, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + GET_UCHAR(BZ_X_CCRC_4, uc); + s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); + + s->state = BZ_X_IDLE; + RETURN(BZ_STREAM_END); + + default: AssertH ( False, 4001 ); + } + + AssertH ( False, 4002 ); + + save_state_and_return: + + s->save_i = i; + s->save_j = j; + s->save_t = t; + s->save_alphaSize = alphaSize; + s->save_nGroups = nGroups; + s->save_nSelectors = nSelectors; + s->save_EOB = EOB; + s->save_groupNo = groupNo; + s->save_groupPos = groupPos; + s->save_nextSym = nextSym; + s->save_nblockMAX = nblockMAX; + s->save_nblock = nblock; + s->save_es = es; + s->save_N = N; + s->save_curr = curr; + s->save_zt = zt; + s->save_zn = zn; + s->save_zvec = zvec; + s->save_zj = zj; + s->save_gSel = gSel; + s->save_gMinlen = gMinlen; + s->save_gLimit = gLimit; + s->save_gBase = gBase; + s->save_gPerm = gPerm; + + return retVal; +} + + +/*-------------------------------------------------------------*/ +/*--- end decompress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/bzip2/src/huffman.c b/dep/bzip2/src/huffman.c new file mode 100644 index 0000000..5371d1c --- /dev/null +++ b/dep/bzip2/src/huffman.c @@ -0,0 +1,205 @@ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + Int32 zz, tmp; \ + zz = z; tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + +#define DOWNHEAP(z) \ +{ \ + Int32 zz, yy, tmp; \ + zz = z; tmp = heap[zz]; \ + while (True) { \ + yy = zz << 1; \ + if (yy > nHeap) break; \ + if (yy < nHeap && \ + weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + + +/*---------------------------------------------------*/ +void BZ2_hbMakeCodeLengths ( UChar *len, + Int32 *freq, + Int32 alphaSize, + Int32 maxLen ) +{ + /*-- + Nodes and heap entries run from 1. Entry 0 + for both the heap and nodes is a sentinel. + --*/ + Int32 nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; + Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; + Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (True) { + + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { k = parent[k]; j++; } + len[i-1] = j; + if (j > maxLen) tooLong = True; + } + + if (! tooLong) break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbAssignCodes ( Int32 *code, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) + if (length[i] == n) { code[i] = vec; vec++; }; + vec <<= 1; + } +} + + +/*---------------------------------------------------*/ +void BZ2_hbCreateDecodeTables ( Int32 *limit, + Int32 *base, + Int32 *perm, + UChar *length, + Int32 minLen, + Int32 maxLen, + Int32 alphaSize ) +{ + Int32 pp, i, j, vec; + + pp = 0; + for (i = minLen; i <= maxLen; i++) + for (j = 0; j < alphaSize; j++) + if (length[j] == i) { perm[pp] = j; pp++; }; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; + for (i = 0; i < alphaSize; i++) base[length[i]+1]++; + + for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; + + for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; + vec = 0; + + for (i = minLen; i <= maxLen; i++) { + vec += (base[i+1] - base[i]); + limit[i] = vec-1; + vec <<= 1; + } + for (i = minLen + 1; i <= maxLen; i++) + base[i] = ((limit[i-1] + 1) << 1) - base[i]; +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/bzip2/src/precompiled.c b/dep/bzip2/src/precompiled.c new file mode 100644 index 0000000..b5c4ec1 --- /dev/null +++ b/dep/bzip2/src/precompiled.c @@ -0,0 +1 @@ +#include "bzlib_private.h" diff --git a/dep/bzip2/src/randtable.c b/dep/bzip2/src/randtable.c new file mode 100644 index 0000000..a739c6e --- /dev/null +++ b/dep/bzip2/src/randtable.c @@ -0,0 +1,84 @@ + +/*-------------------------------------------------------------*/ +/*--- Table for randomising repetitive blocks ---*/ +/*--- randtable.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ */ + + +#include "bzlib_private.h" + + +/*---------------------------------------------*/ +Int32 BZ2_rNums[512] = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 +}; + + +/*-------------------------------------------------------------*/ +/*--- end randtable.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/dep/cppunitlite/build.gradle b/dep/cppunitlite/build.gradle new file mode 100644 index 0000000..6fc4523 --- /dev/null +++ b/dep/cppunitlite/build.gradle @@ -0,0 +1,60 @@ +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeLibrarySpec + +apply plugin: 'cpp' +apply plugin: IccCompilerPlugin + +void setupToolchain(NativeBinarySpec b) { + def cfg = rootProject.createToolchainConfig(b) + + ToolchainConfigUtils.apply(project, cfg, b) +} + +model { + buildTypes { + debug + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + components { + cppunitlite(NativeLibrarySpec) { + targetPlatform 'x86' + + sources { + cppul_main(CppSourceSet) { + source { + srcDir "src" + include "**/*.cpp" + } + + exportedHeaders { + srcDir "include" + } + } + } + + + binaries.all { NativeBinarySpec b -> + project.setupToolchain(b) + } + } + } +} + diff --git a/dep/cppunitlite/include/cppunitlite/Assertions.h b/dep/cppunitlite/include/cppunitlite/Assertions.h new file mode 100644 index 0000000..b191559 --- /dev/null +++ b/dep/cppunitlite/include/cppunitlite/Assertions.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Failure.h" + +class Assertions { +public: + static void StringEquals(std::string message, std::string expected, std::string actual, const char* fileName, long lineNumber); + + static void StringEquals(std::string message, const char* expected, const char* actual, const char* fileName, long lineNumber); + + static void ConditionFailed(std::string message, std::string condition, const char* fileName, long lineNumber); + + static void LongEquals(std::string message, long expected, long actual, const char* fileName, long lineNumber); + + static void UInt32Equals(std::string message, unsigned int expected, unsigned int actual, const char* fileName, long lineNumber); + + static void CharEquals(std::string message, char expected, char actual, const char* fileName, long lineNumber); +}; diff --git a/dep/cppunitlite/include/cppunitlite/Failure.h b/dep/cppunitlite/include/cppunitlite/Failure.h new file mode 100644 index 0000000..1c3260e --- /dev/null +++ b/dep/cppunitlite/include/cppunitlite/Failure.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +class TestFailException : public std::exception { +public: + + TestFailException(std::string message, std::string fileName, long lineNumber) { + std::stringstream ss; + ss << message << " at " << fileName << " line " << lineNumber; + this->message = ss.str(); + this->fileName = fileName; + this->lineNumber = lineNumber; + } + + virtual ~TestFailException() throw() { + + } + + std::string message; + std::string fileName; + long lineNumber; + + virtual const char * what() const throw() { + return message.c_str(); + } +}; + +class Failure { + +public: + Failure (TestFailException &e, std::string testName) { + this->testName = testName; + this->message = e.message; + this->fileName = e.fileName; + this->lineNumber = e.lineNumber; + } + + Failure (std::string message, std::string testName) { + this->testName = testName; + this->message = message; + } + + std::string testName; + std::string message; + std::string fileName; + long lineNumber; +}; + + + + diff --git a/dep/cppunitlite/include/cppunitlite/GradleAdapter.h b/dep/cppunitlite/include/cppunitlite/GradleAdapter.h new file mode 100644 index 0000000..1e26c65 --- /dev/null +++ b/dep/cppunitlite/include/cppunitlite/GradleAdapter.h @@ -0,0 +1,9 @@ +#pragma once + +class GradleAdapter { +public: + int writeAllTestsInfoToFile(const char* fname); + int runTest(const char* groupName, const char* testName); + int runAllTests(); + int testsEntryPoint(int argc, char* argv[]); +}; diff --git a/dep/cppunitlite/include/cppunitlite/Test.h b/dep/cppunitlite/include/cppunitlite/Test.h new file mode 100644 index 0000000..9f18329 --- /dev/null +++ b/dep/cppunitlite/include/cppunitlite/Test.h @@ -0,0 +1,84 @@ +#pragma once + + +#include "Failure.h" +#include "TestResult.h" +#include "Assertions.h" + +#include +#include +#include + +class Test +{ +public: + Test (const char* testName, const char* group, int timeout); + + virtual void runInternal () = 0; + + + void setNext(Test *test); + Test *getNext () const; + void run(TestResult& result); + + const char* getName() { + return name_.c_str(); + } + + const char* getGroup() { + return group_.c_str(); + } + + int getTimeout() { + return timeout_; + } + +protected: + + std::string name_; + std::string group_; + Test *next_; + int timeout_; + +}; + +#define TEST(testName, testGroup, testTimeout)\ + class testGroup##testName##Test : public Test \ + { public: testGroup##testName##Test () : Test (#testName , #testGroup , testTimeout) {} \ + void runInternal (); } \ + testGroup##testName##Instance; \ + void testGroup##testName##Test::runInternal() + + + +#define CHECK(msg, condition) { if (!(condition)) { Assertions::ConditionFailed(msg,#condition, __FILE__, __LINE__); \ + } \ +} + + +#define ZSTR_EQUAL(msg,expected,actual) { \ + Assertions::StringEquals((msg), (expected), (actual), __FILE__, __LINE__); \ +} + +#define LONGS_EQUAL(msg,expected,actual)\ +{ Assertions::LongEquals(msg,expected, actual, __FILE__, __LINE__); } + +#define UINT32_EQUALS(msg,expected,actual)\ +{ Assertions::UInt32Equals(msg,expected, actual, __FILE__, __LINE__); } + +#define CHARS_EQUAL(msg,expected,actual)\ +{ Assertions::CharEquals(msg,expected, actual, __FILE__, __LINE__); } + + +#define DOUBLES_EQUAL(expected,actual,threshold)\ +{ double actualTemp = actual; \ + double expectedTemp = expected; \ + if (fabs ((expectedTemp)-(actualTemp)) > threshold) \ +{ result_.addFailure (Failure (name_, __FILE__, __LINE__, \ +StringFrom((double)expectedTemp), StringFrom((double)actualTemp))); return; } } + + + +#define FAIL(text) \ +{ throw TestFailException(text, std::string(__FILE__), __LINE__);} + diff --git a/dep/cppunitlite/include/cppunitlite/TestHarness.h b/dep/cppunitlite/include/cppunitlite/TestHarness.h new file mode 100644 index 0000000..67ddd7d --- /dev/null +++ b/dep/cppunitlite/include/cppunitlite/TestHarness.h @@ -0,0 +1,18 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// TESTHARNESS.H +// +// The primary include file for the framework. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef TESTHARNESS_H +#define TESTHARNESS_H + +#include "Test.h" +#include "TestResult.h" +#include "Failure.h" +#include "TestRegistry.h" + +#endif + diff --git a/dep/cppunitlite/include/cppunitlite/TestRegistry.h b/dep/cppunitlite/include/cppunitlite/TestRegistry.h new file mode 100644 index 0000000..258f7d5 --- /dev/null +++ b/dep/cppunitlite/include/cppunitlite/TestRegistry.h @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// TESTREGISTRY.H +// +// TestRegistry is a singleton collection of all the tests to run in a system. +// +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +class Test; +class TestResult; + + + +class TestRegistry +{ +public: + static void addTest (Test *test); + static void runAllTests (TestResult& result); + + static Test* getFirstTest(); +private: + + static TestRegistry& instance (); + void add (Test *test); + void run (TestResult& result); + + + Test *tests; + +}; diff --git a/dep/cppunitlite/include/cppunitlite/TestResult.h b/dep/cppunitlite/include/cppunitlite/TestResult.h new file mode 100644 index 0000000..86a9646 --- /dev/null +++ b/dep/cppunitlite/include/cppunitlite/TestResult.h @@ -0,0 +1,18 @@ +#pragma once + +class Failure; + +class TestResult +{ +public: + TestResult (); + virtual void testsStarted (); + virtual void addFailure (const Failure& failure); + virtual void testsEnded (); + + int getFailureCount() { + return failureCount; + } +private: + int failureCount; +}; diff --git a/dep/cppunitlite/msvc/cppunitlite.vcxproj b/dep/cppunitlite/msvc/cppunitlite.vcxproj new file mode 100644 index 0000000..490c3de --- /dev/null +++ b/dep/cppunitlite/msvc/cppunitlite.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug Swds Play + Win32 + + + Debug Swds + Win32 + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + {CEB94F7C-E459-4673-AABB-36E2074396C0} + Win32Proj + cppunitlite + + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + true + v120 + MultiByte + + + StaticLibrary + false + v120 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + $(ProjectDir)..\include\ + CompileAsCpp + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + $(ProjectDir)..\include\ + CompileAsCpp + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreadedDebug + $(ProjectDir)..\include\ + CompileAsCpp + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_LIB;%(PreprocessorDefinitions) + MultiThreaded + $(ProjectDir)..\include\ + false + + + Windows + true + true + true + + + + + + \ No newline at end of file diff --git a/dep/cppunitlite/msvc/cppunitlite.vcxproj.filters b/dep/cppunitlite/msvc/cppunitlite.vcxproj.filters new file mode 100644 index 0000000..47c9cd0 --- /dev/null +++ b/dep/cppunitlite/msvc/cppunitlite.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {f9e9a344-81ba-4669-a9a5-a9abe81561f8} + + + {93df47a7-64d0-4a1a-8fcc-4f5dfa6d9086} + + + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + + + src + + + src + + + src + + + src + + + src + + + \ No newline at end of file diff --git a/dep/cppunitlite/src/Assertions.cpp b/dep/cppunitlite/src/Assertions.cpp new file mode 100644 index 0000000..e856de7 --- /dev/null +++ b/dep/cppunitlite/src/Assertions.cpp @@ -0,0 +1,56 @@ +#include "cppunitlite/Assertions.h" + +#include +#include +#include + +void Assertions::StringEquals(std::string message, std::string expected, std::string actual, const char* fileName, long lineNumber) { + if (expected != actual) { + std::stringstream ss; + ss << message << " (expected '" << expected << "', got '" << actual << "')"; + throw TestFailException(ss.str(), std::string(fileName), lineNumber); + } +} + +void Assertions::StringEquals(std::string message, const char* expected, const char* actual, const char* fileName, long lineNumber) { + if (expected == NULL) { + std::stringstream ss; + ss << message << " (expected '" << expected << "', got NULL"; + throw TestFailException(ss.str(), std::string(fileName), lineNumber); + } + if (strcmp(expected, actual)) { + std::stringstream ss; + ss << message << " (expected '" << expected << "', got '" << actual << "')"; + throw TestFailException(ss.str(), std::string(fileName), lineNumber); + } +} + +void Assertions::ConditionFailed(std::string message, std::string condition, const char* fileName, long lineNumber) { + std::stringstream ss; + ss << message << " (condition failed: " << condition << ")"; + throw TestFailException(ss.str(), std::string(fileName), lineNumber); +} + +void Assertions::LongEquals(std::string message, long expected, long actual, const char* fileName, long lineNumber) { + if (expected != actual) { + std::stringstream ss; + ss << message << " (expected '" << expected << "', got '" << actual << "')"; + throw TestFailException(ss.str(), std::string(fileName), lineNumber); + } +} + +void Assertions::UInt32Equals(std::string message, unsigned int expected, unsigned int actual, const char* fileName, long lineNumber) { + if (expected != actual) { + std::stringstream ss; + ss << message << " (expected '" << expected << "', got '" << actual << "')"; + throw TestFailException(ss.str(), std::string(fileName), lineNumber); + } +} + +void Assertions::CharEquals(std::string message, char expected, char actual, const char* fileName, long lineNumber) { + if (expected != actual) { + std::stringstream ss; + ss << message << " (expected '" << expected << "', got '" << actual << "')"; + throw TestFailException(ss.str(), std::string(fileName), lineNumber); + } +} \ No newline at end of file diff --git a/dep/cppunitlite/src/GradleAdapter.cpp b/dep/cppunitlite/src/GradleAdapter.cpp new file mode 100644 index 0000000..2055fb2 --- /dev/null +++ b/dep/cppunitlite/src/GradleAdapter.cpp @@ -0,0 +1,98 @@ +#include +#include +#include + +#include "cppunitlite/GradleAdapter.h" +#include "cppunitlite/Test.h" +#include "cppunitlite/TestRegistry.h" + +int GradleAdapter::writeAllTestsInfoToFile(const char* fname) { + FILE* outFile = fopen(fname, "w"); + if (outFile == NULL) { + return 1; + } + + fprintf(outFile, "\n"); + + fprintf(outFile, "\n"); + + Test* curTest = TestRegistry::getFirstTest(); + while (curTest != NULL) { + fprintf(outFile, "getName()); + fprintf(outFile, " group=\"%s\" ", curTest->getGroup()); + fprintf(outFile, " timeout=\"%d\" ", curTest->getTimeout()); + + fprintf(outFile, "/>\n"); + curTest = curTest->getNext(); + } + + fprintf(outFile, "\n"); + fclose(outFile); + return 0; +} + +int GradleAdapter::runTest(const char* groupName, const char* testName) { + Test* curTest = TestRegistry::getFirstTest(); + while (curTest != NULL && strcmp(groupName, curTest->getGroup()) && strcmp(testName, curTest->getGroup())) { + curTest = curTest->getNext(); + } + + if (curTest == NULL) { + printf("Test group='%s' name='%s' not found\n", groupName, testName); + return 2; + } + + TestResult result; + curTest->run(result); + + if (result.getFailureCount()) { + return 1; + } + else { + return 0; + } +} + +int GradleAdapter::runAllTests() { + Test* curTest = TestRegistry::getFirstTest(); + while (curTest != NULL) { + TestResult result; + curTest->run(result); + + if (result.getFailureCount()) { + return 1; + } + + curTest = curTest->getNext(); + } + + printf("There were no test failures\n"); + return 0; +} + +int GradleAdapter::testsEntryPoint(int argc, char* argv[]) { + if (argc < 2 || !strcmp(argv[1], "-all")) { + return runAllTests(); + } + + if (!strcmp(argv[1], "-writeTestInfo")) { + if (argc != 3) { + printf("-writeTestInfo requires file name\n"); + } + + return writeAllTestsInfoToFile(argv[2]); + } + + if (!strcmp(argv[1], "-runTest")) { + if (argc != 4) { + printf("-runTest requires group name and test name\n"); + } + + return runTest(argv[2], argv[3]); + } + + printf("Bad argument specified\n"); + return 1; +} diff --git a/dep/cppunitlite/src/Test.cpp b/dep/cppunitlite/src/Test.cpp new file mode 100644 index 0000000..90d8c50 --- /dev/null +++ b/dep/cppunitlite/src/Test.cpp @@ -0,0 +1,41 @@ + + +#include "cppunitlite/Test.h" +#include "cppunitlite/TestRegistry.h" +#include "cppunitlite/Failure.h" + +#include +#include + + +Test::Test (const char* testName, const char* testGroup, int timeout) + : name_ (testName), group_ (testGroup), timeout_(timeout) +{ + TestRegistry::addTest (this); +} + + +Test *Test::getNext() const +{ + return next_; +} + + +void Test::setNext(Test *test) +{ + next_ = test; +} + +void Test::run(TestResult &result) { + try { + runInternal(); + } catch (TestFailException *e) { + result.addFailure(Failure(*e, name_)); + } catch (std::exception &e) { + std::stringstream ss; + ss << "unexpected exception " << e.what(); + result.addFailure(Failure(ss.str(), name_)); + } catch (...) { + result.addFailure(Failure("unknown exception", name_)); + } +} diff --git a/dep/cppunitlite/src/TestRegistry.cpp b/dep/cppunitlite/src/TestRegistry.cpp new file mode 100644 index 0000000..2d0edee --- /dev/null +++ b/dep/cppunitlite/src/TestRegistry.cpp @@ -0,0 +1,50 @@ + + +#include "cppunitlite/Test.h" +#include "cppunitlite/TestResult.h" +#include "cppunitlite/TestRegistry.h" + + +void TestRegistry::addTest (Test *test) +{ + instance ().add (test); +} + + +void TestRegistry::runAllTests (TestResult& result) +{ + instance ().run (result); +} + +Test* TestRegistry::getFirstTest() { + return instance().tests; +} + +TestRegistry& TestRegistry::instance () +{ + static TestRegistry registry; + return registry; +} + + +void TestRegistry::add (Test *test) +{ + if (tests == 0) { + tests = test; + return; + } + + test->setNext (tests); + tests = test; +} + + +void TestRegistry::run (TestResult& result) +{ + result.testsStarted (); + + for (Test *test = tests; test != 0; test = test->getNext ()) + test->run (result); + result.testsEnded (); +} + diff --git a/dep/cppunitlite/src/TestResult.cpp b/dep/cppunitlite/src/TestResult.cpp new file mode 100644 index 0000000..d902124 --- /dev/null +++ b/dep/cppunitlite/src/TestResult.cpp @@ -0,0 +1,36 @@ + +#include "cppunitlite/TestResult.h" +#include "cppunitlite/Failure.h" + +#include +#include + + +TestResult::TestResult () + : failureCount (0) +{ +} + + +void TestResult::testsStarted () +{ +} + + +void TestResult::addFailure (const Failure& failure) { + std::stringstream ss; + ss << "Failure in test '" << failure.testName << "' :" << failure.message; + std::cout << ss.str() << std::endl; + failureCount++; +} + + +void TestResult::testsEnded () { + std::stringstream ss; + if (failureCount > 0) { + ss << "There were " << failureCount << " failures"; + } else { + ss << "There were no test failures"; + } + std::cout << ss.str() << std::endl; +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..5bf150a --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +majorVersion=0 +minorVersion=2 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..175c642d9d335ec83dba0b6fa44b04fc18d7768b GIT binary patch literal 52279 zcmaI7W0WRA)-GDMZR0K5wrzCTwr$(CZC96VcGcAu~J1Q|6A8f@r&pg8*zr?wBx_1KpkGKAP(Z4l}8G9rcUTCi!;xG@C5u7%|d5IPXk^9tFB*g#83RrO}WBJLFqqd8vkp70S& z`_#W4LKBG${=_m8_G#ltpYp9FH|%PyT~J56l->e2Y-8zc>tnqDWLMK+QG|rLM$u5h z(0N{p{*W2-_pgot5_Vz~?~29Pkx`K3!C4yw_;sl=+e1AHB)DKB@%fY!hRl<|35#Pv z5QfJN!MoDo`~HWPM|MJ2(f*>q;jfDS=O6!%mj9{2|D~3H%~8eE*~QdW(aHX=vRo`p zo&SzJJcV3cEKKcOER79a?4AChgi;k-dlVrgKMX+l*up`jL2c^Bs+a0LGM4s>iJ zG?QGFoUDMYA*gwsyNP|`L;X{g~|%74PFTFHiUD;py5f(4>bI zNo)`_EI6n&)fRhWTr3*9istGKKB`WKH3`Dl&$d8sxCu3WHg* z1jpHgiMB2EB8B^7{Fa0mp0`0UNXGpRvSZK6WK8hapa}0GJ^`-BV8f^Xkm>lBIu~%w zYz~l!o8Xh@yi>R@*5XHA*!BmUj=V3em=uGBT9kh{R-T;HZwV_mW^oc#O>1YZ)THEy z5Eb4krlax}&Z_fEy-Y{hngx9`A%Dl=r`knQ?V?qZ(a5&A6X%b}^HDl(@K- zhD)tSVbG*>8#)6sz_zXl{;(Po8%L!|!{`|u@)*CC8UEd(oL*@i`DKe;;ol+V`soXGmSA-PChBJ6)%+M+Q>m?<+gDmE|_(UaK z&_NNhGXz6-%2vkpdi}}f_NPDSzt0q`(ra7y@A^{uyT0iD`%ESNUxTIQZ0aOwZ)+-R zZ*T4D@Q+Eys^}=-2%&w8C;nJ{R;~fGwprHN~ZR$CgLs)|&FB7#;h35Bks?>5o0 z`K{4QW@WWF#{VS2#y6x)GalSM(K+MZ=X^3feJdc~2ckJx6{Ivh;Zd|ll_wQJ1!bTo zuKN~=B;G)@-x-tu)QjY$B(7{BHz)%w1DCAx@$w-=t-mo*XJ7iXC?r3Z=C+jY66SER z&dJ6))ljWH>nzvZHOaUgOJmw}9+NkNDdX*xXlSw2h?{5V4L)S$bkHBV_6p0-+F`a) z_L^8IkOyD{W6y;lk13JOzU8nE-MUlCE3N$4Y3 zmV?RL68>n19KVT(GdV?)lF=3&PgRBIt$qL#g zPpm_}>1PZ#UqN1>f{7IneIdc=3EU!sZxC7;YoR2fa3tyxZgBBZvqWK?mxCx60E!p# zrHlT$bSfPm6%8nKhJp~t%5SdaJETZwIR9|kmqEKLa$%=3HMf`lSde%JKQ>3efq*{# z(gT+N4pT7?V;fgzOE*(-OB+)mV`EciXE{SVLvz!ATK!aY83$BTyg#;C6qa4K#Dc_% zHb9{*ia`L3rJ%HRBMa>U_)>86_6hbMUE8tQax%U|{1>0DcW1f9%%pUhkfYcV5@W&K zhk^HlBiIaiSPTTiyY1O&efS9P1b5y=n;f+>+kuyNuJvv{yes?32qBFudjf-wTn zSb$AJvv5S|!l)C69FTBkHH^Tz2#fu&{4!8hOX4WG=UmBDu1~!bTwTaM$wQP+Q<=!i zXvFDPt#z^ztrHbf8DoQLvE1^DFx8;Z+t{nJ#Ja1Agrub_X0yBUSZ!8tR9u9fTCKv& z2-6e^(KT3CD0 z8slUZnO273%K*CQdD~d0qd(sEJlTwwGV+Oa+_Gn|;*pc>%*4r-JCh*b&BM@#6rY0* z0}W#$WGf%{nOI;ABj!^;W|sdT5re=BjZoxZyR_5U3^1p?ro=x5200&nN1wr5Z{IBW4IA|?d4l5xv_M!=R4n(5!c0^ zYJ(d}rbdc#XJ$ftTFa_B`9yEtt9W5LGHu!MoU(yNL%dMVl9sh3EHn&;+sxuvn)O;O z%%#k$^;@pqp-nM>2WEmndF<{6l^|XLX>5j{NezzoCiqlVUh1tTXa-XNqnPVPjk%a{ zEX)u9{dmUDXulq^L(?7-!zF34^u5MWQ{CZeKi#Bz9KH0!pDKPm#D{XSP5L+QH&i%A zKBrB@h0ND+&ck?7PLzuaq&GQYHZ07duZ~r{*TQ~d z@$RNQ;jdqBf}`Q%pZAF|@rmYn=~SU1WuIA&2tx;XNs1WgZ1t0sFVJF73YJzy@X_IO z3W;{6DbvpjVaEjA`FHjvktZ~YT+3Y%D6pXjkQhqq5xbs-))opgzNr1y^EZq?(lhom4HDEf(55^wlgpeZ6 zFT%(xHcEq&vtCH#E1zd(jd8!3LF`9aB2GDEOg-Xyrv&^Vqta8ph*W>tMsB0)hbqP3o7z5X zIdiYD>iN5&=!S8)hMF*dS67_0S<%IUQc7Ku_r~Y2Zno}1m!vVTY;9s!Y?er1Q!^2r zcksRt{yTXwt`F=o_)A`pApWo9MdKg7lZd^YnWed_lc9^Hz1=^_OVXy@k|0u;c`~Ow zKF4e!9o?y5VVuqdL z+(_8D>DgIO`peI61(en+5LI9rgb?p!C&xb1${`K_y6-9=jP`vAcRJoZ4> zZS#4{B3w|r9v^x9>YcA=EvwGFAKUM0eSoKW$(-eP-HJdHNP1qf2?e*S2uN!gA!iw? zW^bRZA41K*PlV~i_1pIy$Te&Tj1fWFna1L;N)Fl!wr~8_1P1E!CAO5-!PY2!Tf;3o zFZ@(R)t-t!Iy6@Jw^6sq=IAxP0(vzl@&pIjCA2xbEnkN7t@+(9(KJPBw#xMAlZpfI zy%yIu9JrL>*W#B)#{-vPFpr8vi~>7sU(1CsIB2Q>WtAcdMC!oSKfhTykBv|vb6L7^ zh0y=Vfd4UoR&K!-r{d1=q`My(PS2PFEgZMNymN{14EoNx2aQmYk0r8AVIfV>%rR~J z9Xo-!K)+8UXb3?HPH%W=8l!#(j5mv8=!VUA14mCOBK!0t&)g?+bLrVkE2Ec-By)N| zlMz3{qnTT@GWr4Kgb9F|+7XpYb=8cjPC{UvY_0=Ktb-L?s)qK*Hrr&#ZK_yNS~?U8#PTB|0Nn`s7ua1In;#1hP?$H zJ^xMoYY;AONQ0j%cnIs~?6~_Mz_U9?;Y{>~nb%G4sq5T(uJhd0?w{Z9m;qmJT0`_P z6&@lYsN$?S!xd2+Y;WX`DG=z!4~+EgsMHi{IqLUmVd^npj^cIDQnS)d^1*SHM6=c& zxJ!#y!mv97BN)1a-AO%^3_O&jx7Lh|q*BU5v>~c_)8SFwjT!D@FD=H8ds!s@iwyv`0~q%55FHw|1{P+wUma${vOMfYW}-daF0>tH6zq0K z7MQHHA(v33)kLbLJXXgrc2c5jp@FRoQxcTnm`Nn3S#4rkkLZm6=lc@uA?XndGi|D< z<(hqpr9myXo9(NJ6wSS_Jjqc5&Pri*O}p0giOeaIbLAbAz5)Z8&|oDE&M<44&F9Wz z7t>`ERr8vH(wfHc5L09;=r;o-EEA5|Nm zB*(@&3J*~6^MkZ}!scA@eqvJhEjy|>^$o63_buGh^)21=`6)WejK#l63AtP&W(F?5 z^n>)G$RJ=gZ=K`OV`}DX)FpsQP}Cc2MpZnp$-w(F8=sc4V8@AV_euITyR0=%N{(4S zO)muz(;_boi|6>sm4;Lo z(xMzo3!_twNR3xRej3b*OHiz1naWj+*67ZcU~v4mULX1Lt$sV0|13E> z;dX*Agfgu_fuS&U<8qT7tuc|F9erW-6)8Kv#nvAf1YXG_v zHu3lt_C5NH*67oK2n|qliSQBv(npeqt14oJ%yU!JOIh+FU7M@w6XU=#yZia7H0R5T zn&^9G4)W!(pd-ThH+-N-B9tM_bB<8ffr^VXN^ub$u|+TaiX2A(vN-pQeW|VZrwkrNj}2VJTW6NM51d0seqvhrm2h_zhizbMQd-;B{50N7}zW6;^Z6E4SNN zFEQTPeQ*>059Gg_%u-LrF7>~=JJ4UhkMO^nOj&#LfBAQz$)EO%ifCi~>0{LOOrs96 z8K}81Vj5xgOcY@z(8z?)W)z>bDcN;0mW61sf1>NS53)14(zF3EZrpPzt6M{Sm<M4-=v*y>K)Ls`&w0 zpkbp%KA)EW+q&gK2~>OMd4VZ|q2F zmW>qXw&bH9?2jzzM^ep7^tyz?_J1p@R&v}Adl`@;)77pOmF-& z`*{{4nC@<_sS~OJtw$=k9X#c?j+ckHC%jp@Lz34fp}j2QLD!SM2)Ag(9lFQ{D8XKo z3FSub-MTw?`2+m#keqe8j6#P50@Wv9eoPNYXw2}{17{k~?X#Mb=n$mX`oIYmu zF4B26laI`a{n%YDRv+%z>z(g_BV`!j@SO;kCuLMO3_^@%w6^28gYKp#pfk*rTG6?z zax++L#?eJ$AW?!&c zev9nbimbajO_~e%Ck4e=J|02N4tHz4f%SV4|KZt-skIiX4@+38?;zlU71?u(5&pF( zXjJvJCTPAOwS40nd1!e|dJ49Sua*wY^`2qRoNY6~wE^2H9j@pGuklKF)jhS>)S8B- zD>rw3tJF`tRaP!L4xz-Y3&Z{swyT?k@UhaXE$`l3+ab)Az zjSlWQv+P`N!-HFg08qp_ zEVNY**T8&EB@#d$a~>Gn_-JxfA=GnqUAkYyWA42IOot^I&jw9?a$UkDWOrrfW=>zD zG?h4y(%U6^sAP|7Xu5$r;@}&E_FTE&|k^Pe7w%Iw*~J z@)C^1tHK?QQRfY@p*wqMkEmcBitX5GjVRnjMS;^kNUs%P0kB7U?5f`?&wj%Rn2R@2 z`w>^ezLiGlM?P8i6zxrSn|G|g$)WYDF$I=ubtTKckjbp+iZS&$i0Hc%zvV{l9wPR< z6^q1+-%FtT59X`Y9IB!F59p(}cu1t3)AJahIh9pof<0RoIRMwg9yA37yJi#=)OPV` zG5;{u+I=zqEKs99NiI94NSE9yF|143DpAPgZ~S2>4%iynRoxm3i|UsVzlrWX*?_1# zfbWrV0?UoZY#ugSOXs)(5LCQ{qn&|#OWDD&%#us>mh6+soWPd3MjIsAryGHn@9fKw zcd5G5u_3OubO6UY&{cM!)vM**S>PjUnCS`K@^tM1_m}+WTvc@-?zZZ(#}{e-1~(dd zV1j@p6!G8g>uDZadu-_4tlm^<4o=Djkgm~Xhp5~IawqEHR~|cj@!!w?u{85LobZf4 zAu;Cd^%i%(4r4lJ_7j0C?J6Y~m!|QYDeZK)xCju%nSk6Osm$qj2BcQQvj4a>t+)Zce1$MQlPirYwKDuKTRDV^o zly!J9<%dFP6OHDu<_63hefWEad(ysJyyf7_1FnWz1Ag4W*KV^bUBFF!lIf;#!Ra@V zM!bVMXZR92px&#B@Br%+&V^|Bw%Jd*sy+l5&ItolBruS&f~w1rDPguJF03lmHw2u_ z@|g3bV5!+q6mt zmwfnzr&E#|d<14D2C9bQCCp`Jqsc_yR%#nn6oPmGR zJ>{91Q>2iD=J1CX>kAF}lFy#iXM|rxclk_cJZ`&E$oG5>SkH5j>+*jcy^|tZCGg9X z@k`XNX$E`d5XD`D;%^9ZhxjN0Z}a%$-#%)Ng{QXqpiTbyk2G&#JD(ONA`p-*F%S^Z zf8SW8?3`T;ZEXG#yvfyq_CZ_o{KJ3ERJ}rEAS4;hg^?iGK5Pq%t%GTXDrFGz6BdGZ zF|K5wI`{dihTM?S4FzS>@qmn#&tZeY^>C5G4i|+qb3Eh8Y3WHedB<*PHFC2|&cF9I z?00|W_KLJN+(Uf+j`!ovYu~5G?nCRX|2rGW#w=zKS~-Wwn=|&eaF~6n(VGnRw>1AB zZb?Hgl|p;(i2nCfqSQtAqboY>Zwg6&8Gp=@+r?eTbLbC9?7s4O0SGG5KV$`eYUcY> z7Wx}`P(1n%RhmAFGx)9_H=@$R65>Z7tC7Ec- zr!;68nNpYP(lxH(8Nsa_NeWrI*_J{qgBBiddR65tzSTte%R>?9fu7Fw(4kPqju!QN zJb9DF(c%wa(n5DQ#LIJ+{Iq4f9qlN?v(9tyg2#4TsiB=Ym#!DvBQI|$yBW7_CJOs> z?6u6aR~)Hc0T%ue9SJtPDDY`RI!D=Nxc6B*uWKgKnU*?$X`>to@J;YgTHP%NESgIMDEu!60ti%AG6G2>}Hpyso(FdFfnAYT@aq z;?jME!X4pxN!FI3-5Kh!7jDE&q-D_CZL6~q&72k(l`Tz*blYBD>&(h^5j!1*LM`Yw z@Hv#)Uck{j)+gPAs??_liQo;_kCoTy<1!s2pw1@1?XJ;Oo)UQHy;-JeLm`xyPPcMr zQg{w2mBT-aTz+E7S-FiaV$v8Be~?V8mAZDDD-+JHlgt@z<8UlmE^y@-5Vsi%qd=;? zf6Y#hN7$X;lXhXa7qi=r&A?qLD+zuCSjJknT?2WbMlkP5!4n&!VO=(uO8<5@iwTL2 zRAGEK0^(YDJR1;xQruB^IiA_yil7i$oGh{7(}O~B@qH=aLg1a+il=w>(Ul=#tLiY+ z_9Y5o1v|z$KNLsFL{;{-x|A0bWZABtm|5(|n2w;6}=9^x4NwY4-S_#fj;;rkb9RT}5TV1o-QOD--7B z75#Mbx&4UOnDUhA+9S(<+)?;vp6JN~nP|Vz%!040wKa{3{lZiB)QXHeA$f8wvrW3; z7+&SIaFs{dTq1Q=_aiuWxJ5XTl|FaTAV}U&>*H#NU1ow)hZ}TVS?L}(le=fT?oPXj z2%48S!b%?bBXK(9bPQWfH$k=8eipcFY4lT%w1$OtX@0rB;<@pYV=6&eh%`j5+PS5d zc&S7OE^GQzNTLiMb!LjPWsagcVucSOp(-c!W4Edw$7|KrSg(i7mTrnw2R3w-Un=6g z;hi2JYw)$&Cxky~-4YweLL{=D!LZ!2-I3-gzH@(xC1wikC2>ot@fcAFU) zskRf0K^nhJb`o$FDPJ;`&)I#1t+;ps4CzM+yA5R-$>yVj$_yaW`3Vs|ccg6+)JGMI zQ1u;)(45;XT=x!b321e$t91fAQj} zsPzCbX{K6F!v~V``3&_UFY@+s02nVXyIql$$IH!5ZPTbokg4V|=MXC?b$rxbD(vks zlQ@J6?&49DJsF#ZFDYr+3Wkzr41DSw2$R6H2n?kvfw>ETbrhxnE1DQ{sdt%ElH5K6 z`4H)&ODe-WwNA|7Rjt$-*+|ei-uiFh>Lxk^+?~Ev<`wtMOwldJh9^2vu^Zl;`BqlE z;h1q$9bV#KsEjBq(nKm2)J(xOQvL+s7``%zrf*iP&`&C}F0RO?8VB)X2~XjDsnqhf zoXPn6L(V*h=#I(T{nx7BU;>p7pToe^QEBu5N##K{zy3i&#rGc08OV1Lu2zPsW@-U) z3@>fQIvtBlkw+K@HN!Uyf=H!2WL#g(QvD)*^*60lfx&GUf7RpDH)Cr59DzW_e$TR> zIuz}s#1K>0njfHi=5}Lc;9 zJ4*T}+CM8F>!w(EG`@lZrrH4u?z;0Qmx3u5YfW<_aYeWMW9JD};Vc+>32ri&07Lr1A|s_Nij=xyjLqE9l;p>S&#pEsK_iIX4}!8>on? z(q>YjQHBd?-@6X~lL*Ln>w^-Oio_lC2&-z+ZU99(FdJt{hPG8Uc;;be0tG zZ-E^UOBWkOPIZ-Z4~p)>z!YtG=P;S;nv*+#oBnV{wpSC*cZ)MD18Z-E&pZvez_jq?M zS>3N?9%{tsib6E|Kxt~aR4jEMmrOasm5KA-9#=P&_xtcDI4H<~B{8`<6aM7Z?g{41 zvU|@!A7QALaN&e9idh0GSU!#l6SGAnm(Tr|>UPm=fxqlDpp92Cs?7av)s&uqc9_aa zKV@ZZrOpn=ksUglO870!1u(fi`BBi%maZ+o4iUTi142$^dn(ASsZ>XM+#b#PTDq|4 zJ^9FG7jCLZ+6w^pl$BhRJYx2J&{IggfVVVi(QJUcA<2W`vSmny_`RC2FI#Y@zc3)!Q)7rV^>w9RcB(;hXO~ruW}^p7qwT$+GR(IbEovp)*U%EugSQG!MjgH~t=qt{nKx4(S1}nBJ>EaQDlz@&mu` zmzFQqj#5xIR=j-@ZaJ}-$29&O`=THX&gRC1q zzw^=dp-I-ibhn6&{ue#%)Rw7&|I($ZhUD*`!Us-RU5L?B3B5sjCHbZD=HDo;<|4YeU1y?ISV5x{Kwo4n-?Zxa;vIdG3P792XQYJX3E^^EIlID`;K9f#MeGZ_wSo28Ue;LCEb;CTE<%ApR zu_FIh|oQms`J}M{RSbYapOd{%FlnFPM)P3#Fa}|A93pio`jV_K+Wj*Wq zY>ZZ=N@ATHa~x-uL;NYz&m_at@fNw>(~Ql{C4$)YemSJ~iyQrAZr;-Il_lLG^YYDn zaPnD(gP%&2Fli>B83wXWKTNb-k%`v9T!@Bw%72>wIO7!C+^y9WNGfsb&%>NjAsj0B{wK>R#=9D)x^*b@56I&VGP~C3!6K4ma@>wWEtBFyo)b%!!5P% z%47%DlTR-ox;yh3q^YlC8>Zuf%?myYanQC-L}$k*^=z1HCmo^_j+* z2L9jM8c_h*pV%kvFK$g*i5~xziE>X24X`tgGixn|8{inoX64<0$*SoU)&5|IS`o&B zpm}>UXzC{&tz5vcHI;IM05O5N${$f!+>rj&PCC^jbi_lRQ0|#LN3QY6xBXCjML@ zifLlRaW_Qj>bny3kNNmk61WT!!LC@DxclDE1;qbws<(g2Mh^eYIj8=up8vnpb_(0u zyEwc2t&xy3w6s%kF?4eI{}RqxI-BZ9e1lEkRVY7gn7|xB(6UG5RitqXSfN83u#ybY zxJ#lN7{o=>Driy9(&#NeaX&WF``8)6>V4#PKN&uj{TJNoOoBNcRuKP^BOd43>0aZn z_c?n8;GRH2(>F&AaRxK89tJ~oahem8t)ZTnzrjUAsW3<;>?zItp)W7qy`=DG%~Ygx zMzUgLYm`+}8v~U=$Y)6hj`+8Rk?^tSH^otjH_buHXT^6X9dXPg6lD+}m8`;FOCY?3 zcVR$|qq0oEu}m`tG@aAz&8y3{xn$oNnX1q5D~oS^L}=GP=xB)WSZZBZZ7ZpA#qzZ; zzWJMr+~t;LH(IpR*+}iG(`IUvx$=q~cB7m2Oc@Hp7XtIP27;{^Aa9vsYs)jn2L=h*6pRc$ch4985*#q_ z=e^}DHV2eO=%{t(S&iC71)%G-jY%;@)2i4Iqoy@F-c(DnHlp2LmWeMgxk0P)-4I1U zt-x8I^b1in8e8?&p%D^|^oK(fM^I8%-LCv4bAah^K@S2{cj$T zdZ@L6rLMbgNa2;4@+gBq?MCvgI!CkW3)wfd*uzONZmW$fM+5#s9-nH~81LPwK{U~Q ztHgl5D0b!Gl4Pi^Jl#25LxApz3>isp(F25T-gh&_wklOI3-(G`xFEr%Rp|>d@)i>v za}|*$X*?TLo><+v59r$2pH;-~N5MV1*wM?D=tbK3D}3&-yC4kLv*LwQD4uzR;sYE5 zp!y}*cvRx1gYZ8TJdr0eg^9+?wK;>yNdDm&cQGgXGeejHfhiJSOgI$7sN=v)@oOMO z`V)tXAsl42fD$)!l0IH1CV=!E*&TN%DLqX zgTdT`#yuP}FaAbOxz}WmcFAkQ`2*?>`LrYPcC@6^azyWfcHIuP-Vy&jc{d_54r5=~By5jN)g0Z_m^O{Od|lEN0e zAZ2=*^2*_D=UQFsm?pWLxy)yhIu@FAwo;h$;P~fu7Lo8Bf-;-)i@mS(+urkX@4oKl z=Owy}cj3F;uR9$6yB-RDR}+u~AP#jXFo&y*dguey#T5hAgB^5H+ITU-1JGck62jybj%+=u4{MuM0FAH0}7;!MK0J!51a-XIB*H&L+sm_3yyU)C6j;&p&Ye%d<= zGv1GYu{*8AhfYR*LNSIuBI!P?k@P!LrfV7{A9VfbgUdH@uwB)Lo^l2@?!~oM(-wOR zhq1K8Z~P%rk)dAFVq+MiukMy@ZFBW0IhQh=PpbNiJhu^$6bFu*^u zm3#T2W!hiiZzW?9VxQFWRh!`Lae8?(YA?vL+NXQ$eue2NHVn7cTj2hh-CyLltzl5H zWp83_+9_q7me-2L^k$`z2oH;L>$6A~<*KurJbl&`$90D~EuYzvHx?eq@>|L}%V}tl zRlnUbwj^ufZtrw%7g1?p-DGq&v0As(X0=GqYx9PSF1EZ@aS*dEMIWG6C@FWZ&!bny zQVZ#tfy38Xwm*6rI9Tqmi-qY1n~}BtRhwlxzOjk6&TEZETkM+mbDuir#GcV9tXFA( zJg`lj)E5u2jam^ zoV{qH(=IK~C25nlSr*hKtEK6?y39P(Cu++@#R}dYk!W0czM(3G>iOX`t>o_Qi?wUE zOzE;24>_ekM~!SpIOMZgFHzL-iEQ?XlGc1TmALr8`;9-k`sz-S$sAY3s}cvj#hZO( zYVeT9Qnu%~Mp%Z|*eR3cx}z`seP=+FVG0K)Jq=?NQS~>H07|HUS!J%tWc7MnwQ7t} zbX4tn*}*R?6~p3+!JqW#0s{(_w1+fJ^tA=mZ`cGH_fA_C2d71KK}MR*lxn|)0e)2B z7p>y_Vi~UK&l*m5mrrya|PJw?burF#xuen@fCa<#j0=*Q6Z)){7o zVU|)1f;DGVu_}zYv$PivnbyV?@4QkvN4oS%UMii(dK9U8Sk(V$+He`Xz` z1v)a>!JqA`^i?bR*fHDH`O!kE3NM^e4@}Fg;Z;`@p-Ad5h)w-yYrApDuiZ#*nZ;qh zL%k0Y(S4$aBN?(5q^7o1yrNc=WU2WoWyI)HyyN04bFN=L7jdh8Guu%omTyfH>(VA`BiQwXQeLIQ(bhn=ozYy zT>3exJ#aIioj3ZBw?p*x=fFX85(%EyP#Nkt{!WJ-%Ajbx<~7U36Zi$W!DI;2bsD6{ z-BNA91FVbxR#)vrXnt3I2=e{2ZpaDFAfcML&MM)^YrS1>^f|Tf`CK>tZFNSs+~-m) zV#0LlHe;)OcA91_(-YNMPcnCIzYwf(hNfWM#*WGPp1{}9FazCQyO0DRwoZruve6x=t4Q(z=7x| z@-T|6#C(Dzfsiq7Y#09L=Ekjv%7GrioWTTZ8h3u9DYKmMJDj@gp{jfRuWg<4tK5^D z+?$(`++LQgUbUN@%-Nj_5eq#`CtiWg=N>s;eS$2ZsiD{TgXW{up@rv8*z$4zA4r2% zw1b`&!|!l+;GFQ7Nhc&^4QcwA#fXk-`z69eZUBn~WT!ejE2 zBp4Y#OM=(85!|94$s?5yeW0Tr-)1S#uuZg>V$Kgc{yad>Rn!dgg7u{u^QyFoE=V7R0{j zjrLC=5_1Eblelz5iZ2#K2PsBdE73yG!BADz#%Qa|eT-uqP*2UOP(cq7mT6>KyB8+} zEU{x*-4RQtGh5UBeSAD^k9cQMCL?q-d{^Kr_h8+Joz(_fJp#ve&+pe@{MjB``A;@b z9$_P^qNUQrWmqCxyEp1JF{Rt+%r^us^Qx}AnHsm^M?9n|flBdCCh12Xzv9xcsPry| z$-~n3xgW$WU!K9pRY3#~=JH|lKreF_!3HDQL*+_0LN9&LG3cq_4k0L)+2s8l!J$V{ z3@j~}FdW7V9spL!;hS7-gz}7#-jjpd4m&^Zw#Io5DcXv4<^wbsOWM;OVvD3<6rRy0 z*W`XDu|_sR!*j3hDnFR5ccW+JmaXewvW+w*sL<`yDjpx$@?&Pp;AHc~!qlRCXz+vo zI}r`RDXDJyOGJgSfPkp~I}!cInah9D(f{$y|C#pIg!DigL;r@9-&nFzmf&xg^<`%*iKzfR@8a`72893XM|U z-RpMdyqD+Q+})LXn@(824{_$Y$MdV#^A=u#|M9LEXf-;Px^15x9rup8vqzV{Uhz&E z9UMhBK!b|&aIE^vBX+CzuaR?TCwzUo_X4+9RHA5{yc75IsE^{=Qk2?0q4|=WE3`MNa3~PoVP*fuA+zLmeeoG)k ztg09ZS1Vy6?x#3@NYEvCF`kT%ueduz?(|n3;6f)HF{UOM8&mbc%U8UY;w{`$f#I(; zV#!mz$M#u`pOea(`@9DS*H6jUPYPF<7-EnSS9rfipE#@b^N|}^E2VRvIL7tcqWAAV zA8S|j!QEB5`ytRr8QEWd0Qpv^>sN9x_7)kHe_#&dS677Ck5sYYSBedyqCKNdLD z?bXGD@OpK5dG(71>5RK9e}0IGk00fx6=mUV93wD^oh7g3se`RxOgT&t5Z}{VT;JMU zUCcLBJ}CBUclXyqdLVr^_zWra7EY{0tt|-bdlXWIh<^R-%uL)J--QT;%2 z*YF3qw$jT;dTVS5dleza@Bm&TZ4{# ziL7sp+&XiTv^aJwW1~-R4XkeYu_EGP$Si(AF=PX#onXD?$!Sb&45ZZ2LYu7Eo`91M zbkpCwq8mklfx1V{~7t;)Vxr#C2;jCM*=Rs{XZ;tyXo~B~|^({C|;6MT9yJr6{ zXG^v^5x!nbF5dp=2?0pXo3L zp}Mbk>a|wVF}TWw;4*+EA)$VAXblNC(5G8N-A#iA%=#Is1I*qfxl(Ugm#WSX>)W!aR;tADm~U(tT> zr!an1aiZlhH$^DJ5f-Og84*|cwyT_76=i1JHPFt%PrzBX&?xK?%Zx0Nl$kFVztmDx zVoq{Yjca@gg)g6JQUsN=jm&QqYQ08glVee4HJ@Z6F|s%U)1)E;XJwp*h6%UD*+spt zcdRX-L(gDt`IJqJOMX-wT3!RLE;SlKUA9O9*g$$S(WA*(vRKjLnm|tCZ zdsOS(eH4(|f7Xp8AWnNN_2e8Y(zRU9{`7unx*-t9JVu}n)#s!%Y0zK>An++#sQc>% z8n0_C5J&VjkEw<(#qrJec8AfQ9^CivPD8*G(7E(nGf*hWA&8^T%)ly!zj&EhwC3;G zxv~^dwPesQH$I*_n=Ye_dCFy!$dF8i%(~sfl&mpn@(QYCf8zkNOSv3rN?O&nMXH6p zEWgjz=J)%W601*QoriFGpmY)4#f&F7(UHNLe7li8?sk&;UOn$I1|zAUpH;=l%E?RL zVKe4m6dc>8nl2FKB3&KuyKbpl`IG*)zF_yM9}1lIoLhBy-Fc@*o@TanAa1LOy z`8M=XRO?4g9qPO4*cYG3bkqrt#wI7kXIO%FqGJiBx#wM<9Rh+c`K%iX6&@vS>=b?w z4ejHL0^5y4+0>X5<8X}z6HcMDegONrs010(A1t{?sDnjyj(-QSyu%i~v|v6!j-p31 z7@|r=YUU*?+$glj0P~8o2-S+FP+TkyO%sZtP?Ss+v!sh8%10jYx=cB;4d5= zZ+g4Bvf*>(Fi1K{Qif5U3lY}GB|A+M{=ODu$fAly=ni96dr4S>;5x1l+FL9gyX!b! z0+JnNUf+Z}Zf=NISxZnD zvo_b4HFNN;p}iP49qIkKB9}^{h4!GoQwl?B z^ps36EXRn;)Zi>7A$ZP`@!OSU@iaPac}|`qk-8lrNI^F_HF~i_I1cgk0t1L*F|^By1Lo=?eDARo{ahw@9X-3a5j!| zCo7zcvL>r}KdPVELnlRJ(0WesEIOdNi|gKq)#OZ$W!K2IxH{_#yiu2^o~zuNS*y@` zZma3)3cGq&*3H2zfd)g6P?w_QuUR}Ha>X@X0f^?knv;ou=+nghTG9t}BT>!i%9m&eMQOB)zo z5#7Q4Ey}D zqt~GCcA)2*W|RE4=cPxfda8>xud*`Rx0AKGP%zzI4z@ZxRZdPJcg%P zhNng9ha@X#a=Ai5&IJ3J1C?`UFpp6{VJDMT_59>a_{lB>?|FU`h7qBQ# zgWQcayGOZX2Xiaa?XyGvsm8_XVu zb-%V8dT*H#@A%7({G|r}i*G*y3NQPzz@;J|7IIVGc6xqY1AKOU?#Fk(Z-X~tXr2~f zyk$MG{4`m-7Df8X$8{Eh8^Pzf{*@8o=74EF-t!hJA%W$T3N>sJB&8A&5b0HPcYwus zU;x+LelqNoYZz}3PK;G+c*mj~K5m#s44orA6=P(c;OVp&qsqsBIeds$hpX7Qf=y`T zyBJcz=eZeT0scN5ZBUYl?KrXQfTUKP{2=zQ`p^5jUZLvy>*ijaFT|@0Z2#Vy+ zJ+%x>R+ACEVal$#vDMJ^R*NAm;2a%{`pgIW{9xlNRFc_iC8O}83ff0)ZskL*T*^z4 z<#e*_7mm1Q(LrdiTPEeTmFKnwb0;17E0v-65^9_&*~q(fn<3^iAr@wQ5iTrw-`!YN ziO5RwrLo{yaBlg$G6{snVAtsyePPTH+3S&a(-$8yttYt>FwJ^HGpb~MpFm?b+;k&j zn)XJonfA^d!JqU+b%4wKLX9??_RQJ1-qVjxuR-OmGgrL!y6KNq)=RzpBJi+BicNTk zid}HPid}FBi`bufi{AgZmmKS`KHm|!&}6OYwqj1XOqVLL#3O#yKm3$hU~t%)F4Y)2 zrDvBz_WUJ-|5;gI zqexKJK^De_29aok9S>d5N|3RKTs~>AMmhPG%gWS1S<3lpGQwO~Xp0+>)j72;pk_TJ z6^k54J;jxlW1$Z#>)ub(6j!y&dAu`Vxr)e!Tk7`WGURbs}IFD0(`!fgK0cB7`V zj#VbkUPUDXqegNU?Z^$T%j_zV*Ttgog@e-YoZlf?{MUr<-d>bJENkcEAJ|MK zyqV8>X2m}xYAG+_*=!`CWvpu9R^vp$*J4Y^uy7)1wTR;tk}7j<1orMI zssRPHTafI*ZwRh$$rxUAKPdz3jq`fGJPq#6Q%MiIfbE2=G0khgEK<>CM3pjs;`nhP zuceI*Dc4rY4hu$`jUdgqg2zxO37lxXG7gdI2On+fu}2@aynf^R`JFa(EZP5&JE%;1 z^v;ZoB0Y7?c~RyNLDFEbcfn1q8_78ruu&k&8dS}IQio)jOjG(xi~1~SYoVTG)5NflX%*cFMg3+C{FG#y3i&g zR-D%MNmiqahB!e@+TLw!u!f89KLFSt3>TBJK240Iza$XJ!ETZ?=vlr8{Np&DHIa2< z>lY9Z4KNT8uK!s``ESSZ$mASMjBLfMfQ|<%W4Hf{f=E-*mBj^etme!CE3P$8ZS9-7 ztzMBfzcvqaWrb0|iCe=k2z{yKl8F_%H{es`V?JdDm2Qdz2ME>qSi=`9k$l&)T;3R5 z)~CN?27vUA)^N`l)tZ6)^3dMHi50X!katy!dZd)5_o6 znXp#^KPyhw)d)WQW>jo|)sJgg`~c*a+Z{t9pII^MF)u>3>br!{zVnA$=^vA}_lbL} z&Fy4#Y-%)u@ILZY-=QH)fMBPvv7O1FvNfP(mv zdwRi(*XheBsY|N#fUEG}9V+r*4*nGT3ju>JB1?H@*=!k+j#xN~*38_54&x;xE;ikS zw8XxZz{so?{a)U8UhI@A_Ydilt+MXWp0}Z#l&3G{dLOhv7udyK6u;&M{qyBW9_Bkr zH|T$t)RIkPaIv94KxBbuNPtI3{{Jw6|5DPzG@}C0EU^8}TY6Y|;kYqSw5Srx;cc%- zV3J#x$r9bS*aqpK^_85Oc{k_)Gqx7y&}w#l)xYiA2-Hgr&~+2i+ij^94%F57bm}y8 z-!b1Ymrrv57swhjj4$y|Z##!R1*blz(`f+(0T2W3@2X}dVU1wiKeichbj=Q_9MzAU zW;|&8 zThw?Px{HpwT%#WB;r+AcsQq4EhfI5ls-ATEBB#&gBYf4jgIm%P4+X_-df{kkEq?2) z_?nz6AZ860o`@*+Y8>IR#8S5<)Noa%0$yi>%YNf$P-|U9^VmRf-RYT= z;kGVb^1_Ih2G@+%Noc>J6jTD?O2SVtZGar&h(51Lc^AE2o84F=zPqcF&Dcz*4_T~O z!{MQh%bHBLIoY#h9U6c$&O*+FnpTrtpk%+KOei z!$sF)n{{HuW?c4TbQ|`yD`|ySy!mX-#y^s7QK4t2?M=#U*30wF_`G;~hHkjnaqr`e z5G&$P&Su_i{p}S3fAR7SCC?2dVj(~z|(pSSH?&mQTd2O8gN=cGT;M9Zi zXgKz;9CUpHje?9UeOejJ7F~tZLgKL+Y{caeU)*S2ZyuXiwU=Z%_5$OD<$8=0e8(X_ zPB?S1ks6zaNp4i02S6`CK}i&x@vs8NKiq=+q6?wU{?Dg}W~Z;h7&iR;Ap|y~HCIe< zIC<_8QyerlqZL;I?9r*Sf+U|%oEkgFNNKjnitNy!_>W$?Lv;9z8y9%$o3m;z$%2UB z*l(84*h6%-(2nPtW-eUKn^X9uGWX1~Edc)VqYpI9% zwJGXDC!8@hG2JTqWSYK-iLzIH8!KRchj5s9t^q1#^6&xUzi|E#qg)Mc2h@UhYh1LunShI1uu~7Xo?n6GbVs}M7my_Y(RW<>Ec_nLRJ5E~{kq)0K zQyLm*)6}j;tzoSv`>?5l8@1Y?owgwJ+B+#%tWB+h!cps}th%sy-q4uI%&9u|;e~Mr z!?1O}r}BxrIsvY(E(!gsnng{QV{I9^1!KzqA5jc3!FAM{%Ehq1vy~^S0|IpVep5y_ zb@BZ?7PUri?)<#3;KwR-iHzJQH*<*wzXXiopVQNPI3(2+28SvQg1oiMPN~`~Hft&V zi%SebH;I;Zf^9g9A9I~YIWw&z#w3A|{q|If=Jey0ecA?zvBq=Fn63my9(kmA1mCo= z&H=336HkZk{eYb)5Dr65NN$3Io`ncq?(cQh{a=l4{r0)&1egs3&wqcp+KBP99p`fC zTATOxdqOF_%5S-Gd&(CV_1M*ZriRJAtpyCag9Y1iIz5?(HbTT%j^jwQBH(wX&;rDH zBlj7u>$-RD8NEo6gXVFguyD9e#_Q1ru}+QGHXU#9j;1YpLCA^eiCqz_M}0^=zU28j zJCvjens7;w^eZISl?aN9jFFv4FT}?$!hg2>H#fw&fBM1HjLG&hzmgP zd9H~d`B$!d19ys#7;635w3@|GHmo!1LMJBAFY-~amI@0t()_tCEDos15y$Ehe7GDCUV(2Er*9Uimn} z9jFYKAZ!&vJLrl&RB|?PytQ`A+N*4w4n@vxRV^?5k^67tA+~)NP;q*e`y&?@aA*qe z9|H0pH99aF=}|i2$Wf?>Ha)Nbeh{vCWAY(7A8y*UlC829p35K#cVQrZ^dDZ0NeGE> zM*`#oSXcu+jL_YUN!^oBuPJ1Dx>zQDAayz7ChZP~?!<$86{Vm)CBY+fJriv_L#e({ z8F5LQ^NHK@iLw=tgD@%`@|iWLxQ8{bQTc>4cR+`O&`T!N++dkICceie&p$0D$T415 z6o`U*=Jp`6Mk5_Z+z3pmf6>4`sWHoJNH=`krxy^7Pej1?geEkt_0PYQpCOs-&j$D1 zOVy&2Dr{WKlKS-Q%u(y7+#Yr(*`9V^AiP4=C)#H0HuMy7b$(7aKQ^;fWK*gk&cAsY zK@E~3%7>B&z754oI)pCc%(p~%Y$CQhIK7EKovOON!JAvS?UNG*rRUr6CUApA>`EKI zI3yN}E{_gML%`cR$5S0t~u6GD06|9ThqxuAGWf!ZI$lMXY$gj;X zAjIh9k`tkqiAh+v2FXT$-4q^J`TR#*;g2`apbU&B6oJ=Yh~8Mngn$?(?T3FayS=cok-Qf|G znOKA_ zU6_C8GQ$i}Zce*_r!wy68!cd{73Af5)+r7>U)DhVst`Ytd=OHVxdxVW_8lvl-Q^Wl zY2s>4JnGWSxjhSB#&1uQ*e$Jc=-dB|_x}0{z!(2N@NHno_xE_u#MbJ+k+T1~J#pe8 zoezkTQ3ax8nE(BDVdK9%&?c^;4t91x=$4$7y%`V~=MJPu|Cbv&O-&z&j7H-JgN>nW zkF=}XT|hi8aorNg5|M)XVJT9Lyf`v$hP`HIm;onR5-_w|%*gg*gm5o`Wk)+vDZTZ< z=yZqM=eo<~WCtJ^5by`mF_IJv`r>Sz9ceKB3;ulClZY2Lz85|OzIeFj=x;r3v&fUX z3OF6WwPW~7_^;a(qlQ`WX=@K?X-?m*^L(8l^*89s$@#0mqUD<~6P}@S*Dfm${gzb% zDWi?%t0(XDHDyz`UEWg>XJzyC&Y9nBp9R-v6k=%_HG1S600L6D@vgBfH~TF8X_uJ} zv|_Dk*7cr8><%+-!f>e=a=gXn_Q>FR=|vlc6@I#jxF>q%yOU7fH+^S9l%73rY?yYLyewKOs4H|b0+sRIH8>}bwRr10flittNvv9ReG zv6WEP3nxW|91-{;UVNrLNwfVr;MdQI4rd~a+))%j2q83(BagRR~YBYFl%MUi% zue4-BB4@kE#ImzR?9x3r+7cWZogi<*3TPgdabFE_Xj>`9zi5d^UjSsKvgu0Z>Xh?~ z-y}3hdtP9Z5-=n4(PT(1!&IC?*LR?9ua{tGO@+OnYnS{2P|3&{$Xxy}Av7#j_%Cw1_@`x?4y^lecchKzyb>C?_#o??cS2nYhR`^?P zq}R#7j8p_$^Vj(RU?r8wi$53PaJ+nUB;*lp|Bv$X9A;P%_gk#HnY+m~lthAxAge;AO>_$C)11Qwkineq6$5 z^zei{3PAx3Si26-5Qg{~qKV<2Fos3i z35D!ah?~vTsS1RxI{P)ZRxc}jw@Op?o7;wGs?+@PrR2pY4M6RF&BGzgDE!^2`NHAdp%%Gj1q{%^(KMVq3ii zjuLBHX(@z|K@f8j^I(%)3Rn?)Q`}vE6#4E`4!xCzPvDsnP|SN^8D1APBXUVwl=O2e zB!Md?Ye}qG#X>BUfm9#Cx{39(d%_&41lS%>!N&))a{Y3$lm(p=jaI}a%K8j)#0Lwj z;z_->>r^CQxWwgfoCKjHPb)>5#AG4}bby2&BhPe>Z5I{fJjQYmI*h|x>O?EV;Nurk zj-UV2p_q1c0c(6w6S3qgN|*sEZ$uKfO+4MW+X&Y9(QazMslLA5IBjrP<_eKwAg(>n zD#;FpEoR9@Zi)PYN^1muhp90nzR3C@M)UYL&-q`Yy|-4LB?&kJLVybo|NmwL{HyD$ z0tG623*h*0Gy)<^|Eq36p4z-3Do~~}?=~~CE4nK&Yzx*YQZl6`0(v@1qoA9RQQ@L? z$}h{|wB0AK(w`d!CUd^}+=50?jI{)$-p;z$iP%_kx$fjV^?O}!IqW=)&ol0Vpxw?4 zAf3QtS^sD%H2D!2PTrQuldhg^t2`bZuO1#m|8v4Hhd8}J&~RbO9$<`BB{lB7!dI`e zgR9&|&7$LEGbDhNul7b&2@$bqA$6SxzUcM{rpOc5?Bh$qhuldZYP{w|*I)~~+X2;~ z?bH{(aU%w3pUI||A0mLQsL$@h$anDS+DVgv^QPZcUh48amdb@$!cZ8tC6xsvz3B5C zhOb0N`(YNQ7!V`Bi>|>!jqiNy)au!^YVtQ*3s>+?Yx;74F{%W*z&eOteX z&ol!vBa(OFij{A{AJG9x=9%%t5+@Vr`v^Zt!18J{XwR&tHDC+8I`8CsQdz%qFMiXfUy} zEAPuU^ChSJPG&P17~(OJ77@`AhO-;Kc@PBP4Q_-voc`JXkm)4tR-#j zI(D?@L%?08uWM<+k-4UYmkMg(Q0H}9= zZeJny;AT-^)>(|U!~x(}5DA)t!^4#>9Cyp?f14G!G);Hm!X4~_0Omc)OX!(y-u%JeMwag zH4zCbyid?XzVM&@J}ow7(%vZs>-7O^ek?Qtj<28h+ckfwXX#2#*x=$LI-b0S!|fPB z<98Kv&Ejiz85fm_J}X=eiv{2e+pDkVa_$zbtDun|(CT3HwWS$iCU1DADjMF#X~}&} z;BOlFU#%jDY56%0MAk(Bi^}}3W*}L6V9l6+O+){RK>oG}1GH>B(T>smzni9LQ-Fns zfdpw(WG9-sAbyEiXeBN#4Hv?di*4OB@{oh%WZlZz0KXWO(Y*v1EO2P}G(l~82g#s_ z^e!7T7XMx?R{VVQdgb$b-7To&w=j2a$pJJ*3BH}?+~-|y_q)8!U5$R`2YeCY-AQYL z@Te~&CoVxXL6O5I){2$ByYn)zHNZ2_D_4}pLNpN>LdIU(tAvB_V15W=>emWl+@F?n z?T|b8KD6aS=BqyD?aLqQV`e+-$I>6PNWyAa{tN*OK zYY#^ zZ0U1)nqNelQyu#;PSmQvu+vZ5(LiQnYx^mRL3Y@9kJqNptIGZ5R{cLG z{Sb0}OHA+`vU?(aPIqP!MV+THyxv}OwpeITzqOq1R?+1a3vhT#x4yQDLJx_()@G(- zE!&1XePJ2dLDBL^v69d1R|m@02HSx{wMV)eEIpS%)02HSXwUim@Ji#h8ng|zSCX$2 zXwCXl_T}R*Nj(+%1&!~v_%#x)9tkHix&}JCjx`?G2XYjyk1|;q&7kBGaRZyRy%%n7 zx-Rr{wJ_88E0=!4*fi3Ntv~GynvcZ=CXk>LV1@Q}KM{Xw=XL{R_mfHOdRy-o2d6O% zc)T{I{0yOusSLq1rs98cV&$Ivy0g^bvV?go)EtEGOe&%TU!93)-fC|v*|vB-TZ3^g zk{r~q)pW#nr&^Cnpgt4n2o{EeW@E5dJ3i68yC=T{sZRW^yLata#beAZcwfCF8Fz!F0 z{3+Z^xCjy47m2_AxKqAi>G_!V6dx4trD^mh9<5JJiu}d#dmXH#yLylPJuG7lf}?Z= zJ052(rJaDZU}VLd#2c(Z%2Rbvm+sx}U43X5eAzgydJkm>x$_b1(K;xeygeSTd zpc;&}RZGqzH~Vpp!+L{Xb~Ozf1jf^OzwFKc9|v~Q>Sx76J7_%PpVs3zh#39>wf=Y~ z%%9u6Y>+JR#vE9&tx2!p??vt=6qP>(($KdXkzC8qePj0qFA#-*t z?EFOiRh%XcZeRAxqiwqcEQL)!63ufA^iNnUj8meXG~%Bg$>GR@u!gMxiY(j2IoIPM z9qDrC6lMM{gM*Gq=G`V=K8n$~6$#zzTwAnN2hg1Ll0Bda7ALSdH#KOuO&v$;=Wag( z=XP|nLWnSQ30uZkn;QCZB^RqWq0;=5-4_*ioW(p#iKvED!=B0phu#)#_x-G{3SX|h zgJm0gnv)~Y6IwzoFnM0cE(ye_jRMOp57A_bjUmf^aEFFlC~<_{SuUZKTHd1#{WxDh z(-5nHrY*Q7+Y$SfmS{P`_eGm8n&uXZBRZv1CRe1+6EE%n`T<#g*w!QJ zYtwNV!AN@qUt}F{TlMi!6&sg4p#Y@B zq8;d0M;F6GByGh*4r^&yPoSNk(%i2_i;^iS%|%OaW)9%UqxqYrzu&O>UTM@NpJx;k ztrC@w98!jdudLAWStfsGg4&|jlR8E)cmF%NU8!dvp0omn*~NtPvYGaoPhEH6n#Ro^ zJdRf#&fhP#gvCGHa0nj*=ff0A9sJFBKsC|h2j~E(J~`&M$Qruh11rJi4K}a1ITgw- z=N|zt#@395A%)2<>wFPBGUKmO!)(QLb~tfK6olp?!R5le^nd!@FzmEpI7-o5pYG)& z>kpUTKFO5w5r^E+AR}S5NDazs`=puz&^uz*n1~I=oo*p1Msqy1dc#r6;A#jfY@g>2>%SB868i$4;gU%f%UAt4XF%W zElCg6B;QPiVBFeN)y1Qx&jIFSE}Tht+j@2TlSR8~4{4?2rcg`C2x`>C_&K2orcxF7RvK+5>}B7r1-i^HW+W?$52p8u44zU!&CHK5-A z15#-qK9=po^x;ku5$I`~Kx(2gfu2S&kkLv?I(S1fkk&f9af23z#ziq;b+yAv-?w8S zbAIuIY%(Q0hx0=pUi8R`0|UI&;%Am(SFW?qZm;2mT#J^S`LXMT&+If=tZPi#~9UZRWFRuLqMw`Ji9h&)1rB;P+WtWp4H>H$=+x4m85;*xBbK}e{F!nz17|% zv+lCy%**aKxoMwp4=p%dhG99=yn)n3X~)*MUPlp5-^!uIwcC4FMcJXD+Q)Z0o)uxX z9Sx_msyArY131IabN%2oNf;$Ui{0ZN_S9SDvQI5?yzc6BZz^<#6ICuN!ANj`rP0@a z3MOK!{OI!4#Z`0LN$%JtH#EYsPjJX~Ee~W64iUDRS1-Q!0k1hD88_PY1Lm||HHFb6 zsNbQFjnD7F4UPCFy#xSqsitF9pO`BUaT5amCFJ4iK*l|cI5`a@(1;JbK!`^9>^*NH zxwU>Km)PmcEiA9(9c4EI@#UO*2tr2y%=AJ?`HIB3^*n;)j}TlU_v(@Q-pHY z160CCO6?xB^!7b>zHzK?#hLLTSyYxC51{47m2gs|S4weSuh=3zpOva2NfQq-u+Gp* z4vG7|OgcFf?inj=#HJO-Xim#@uK7!$cqZ8p-UjN#+q2co^DjDr1s-89IaTWB)D6s5 zk`$6S8Np`dSK%tH(X)T3%}2&7l>5LDVh@a?1^+iAMBU!z|0jy>Q=e7==JEXelVnCL zLQqJzVUbjmNKpGlB#|U#W$I`;Va|AX<<@Wns%^rPRcU*%UIq3?+9m4Q1{SdCnWl9-38XZgxwwe)h zVvn|gbKW@2Cm6*OeMk0~?(U%gg*yk^S_PQJWK4T!85xf{#pUkb6_=gDq-W{6%aGe+ zYRc(097vq+-NO-I;lNF%S-eBcYj1Nn+vMA9LgJ6YMreiam&^z#HpLeZB|$84^oc|A z`{g!q3;T>(tYQyMDx?m|H#OtPjy7e%-=OT+wn6naE_Ca?%-G9%-bkzG*Jcah@WrmBq#c?B)u0%HSbzkOGnoF7(W8E$RhEk^ws2zTIc@|`pvdy z#+5J#k_DUC+@3IzL%MhEX4nPUFEph#=yFt+G9c*dSe>oplN1~CCngi?I?z1Hc?2EW zE@OF9+>%h)`Hr}RL~C7fWTT-w8AV;=T#Aw5s~&DC(a)Gnj&yuMkS%VNm9KQL#7>+6W9#Vh5j=%&AeTvz`^4?{~ck#=PPbt#;qM5FB7>5Pdta5n<4Mc*#Mk**h9JJ47nrNJ@obn{jI0$ z*cSA5IE{(0gh2eu`Gilbm zpI^xdHjx@}*q5ENC~|PzNU@z*lozJFbUg;8q{0EJ+6yx6>6&4awbnVyGLgT``zT@ShR1vsYcH#|pCA5T^pxsV z$D6U)59rP>hVn5@Y8#3YWJMJH9NP!L7U&W%@Mr2bG?s}CmUAc7LG7dvL#bLDl-EdX zjg{#O9y>{msPIYV26WDy`CJteZR922mTXv5LAkP=Denbw$*#&*e1BEpwzWBr8k*~h zILxcLmJ~umx-NR;wUqp9Y+x^vLs_*NZoGnMYOnapMWFkksR<>;h^;d~*3V<4BRpiz z*>N*Mz5K0mc3r7+*e1K#v^$6{SW$B6b2vkGgu2G~wC%pT&_{9NJn^P_kH~hh6=T0x z$G{W~g11RlLOUp=59TpaQo@o3=IS6n_6>%>P;T(;SxCggMA6i@a*xz^24Ph%;g?xE z?@I9&%%jowV8xrNU@(zaxPq8V%m?OgHX^%*gp6&vFpF4*`=>S@_-@~f)dn@6bp|;} z+;?MW)FXVI_v6z&^i*bQ58S`aXz}rG>&*mnEMq9W-3Bvf{T_7G;eI9;_YA488pM z z>AoP>@fd7ps@_E&hT+v++kcE4#VhfS*xFx`mqd@zEMH`bPjqWrwN+40wm&+!bM3)$<)VJ+Ib;@78AnKH)%YES~`6)Jf5K!DH=xLr8r|2FlV0^hw z`oGm?eQTT7vT!ttem*tjI}i8HRY1AK;utL@ZA6Y(7q$x(it^>d8eZLiN^=30CtuAK z5PF`oxw%7>=O+schBjGUn}6yb)*3vyP-!I&T*WOn@$`T-P1!jzRJP<5G?b(Nh_U0jQz$=5^Qv_*E!?mvI4$oW^+ zkZY?qUjbBm%m3Yb`;S@uKld^JACh94ivC~TTmBa97I%61*6ah1SZWDsd$ez4B$h&G z!7xdD&m7X>mlNh1=9J{0CErUG!vvneUQ41qIKCjmTDcR<<@KEAPxE{HdH?u;+e7;1 zYufm8c(gnsIl?adqDpNsm)W%1#}2Xs`3YRKpE|7*`+-+v_g+CPYt(%ESUJbW>iV$M zrhhWjX#a6?LJQ!O2L)i+UTD~EQxV}L$tMe@8lTmQ5U%uML=omp7AC!V>N?*LDCwT! zP2w5$t)*H%k${`+Lf}uuKG}JwQh%b5{f_?IL|iANUnzXQc+>Z2*9*xB9g@DJ4Ca?A z?Oeo=-tCck+KjIhuJW-eS?o>YFi1Gy-1Ks|8xYD`%dGY%LOxFCR>)(ttW}n}{}68- z+9eZMz%p##@>QJ)%|O5Vk}sM8{>2R^18XWp(uhi)q>J2ph~Xk5%*293lfN4x)Rfu$ zF<|gTIw)i#)zt4Z2odd60{r~@-kGDnbB<-jJgK9&fm}rsu zVN(Xn4ny-7ld{aGV9p0a1YvV8sY1P+tW@u8RI8>{jq&Zb_g?XD#g zc~vpz$vj$ZzZdsfbqJCcSZXlgSL$`LLsR0uNdnBI*`q@k1}0Li(7(o{>rh#R+>`s= zIIUD$hC#bHDYL_HpI=9K*x^sT&z_f)Q?tc98^rj0|(=y5JZs7Q)DG_hYp=p)ZHo=LmaZH|ijvnyCy zB7g=EJNz(rvEfM}#cRxXmIeZ#@I9Y0k9&M13MX@ATWr*;S9anO3V67>ifWAoH#3p7 z5Fa~e*QR}bwEd=pk}9jdv^o|yR9XdF9Fjul%A#?bXr@^SbyefuWi5MV&Er^FodJ_A zRadJS|5GDOXOTN;qwofl*41^oJLpe4U1gdM|K$XS&BKqJRfv_Et|j}5Bq9P_&U72f zo@O@)UZZrG&EDY-uD(7~jEYwBx}zrx$;ReTy}bx|P(rA7Y`oVlcroDG?)|k5o&D`B zyeqk0UGc+oW39DI8f0r(WKfu|B)xi*;-N*aME2?l<9rP&fJf-*>i9Dtw5C(E&Ag$) zY8AY2X>FudyX~aSq}%c)p5pmq$Offa48quLB|#S11_D zmG&o(z4m!Ck=CH(jWV_-dT)q_nXl#`uzn7N-~b}I>D37*YdgCJ+B=kB`YkHQh{ToI zyV~IVjSKYGJ}0i+pH)Y!ahORxYo5AMeUJmHr;N>s=ren%!RYV7n)4K@As*raC3_jq z=n)bP!PIiJnIJD8>>6h85`&b?6?+}e_>x|LSi=gm6_weV63r9#gowO)#jKrt8HX{Z zOF7}5fiu`Q@iB&p&hkAT4fNiK3bc2En%N@`W=i5*bhjk?eC6EXZjZJmHJt47t0`H| zYiBLz*O^4!uX%O&%(>!+Ode5WV!?U8=JVSjMX%;#?cj0YZ8XT^xR%}=+p&ASC>KK3 zA(nL1qL|SZ+7_s4!cxpJ1Es)9dsyDd@g4zSOs7n`WS18mt)%XJP$cv|BPpnA8^GZIV3-$dZxM)42|bC5DR~aKfv0PNj#q&)T@eS4pRS4)NeWY}q3v-E;?GMXqaX}`gz-Oiz=|uVrthYgkg<9m_Jmk8{ zK7ZPVigG$JhyL8>9eet@bw<(gq#!w__a}lhm_K4eROBu*?#laXl<#YQ&bk{%!OmrG zcd=W|&H7Z{_fv<1KQ;n@x4fw{Q9N$4Gx2ov42wE^(}iI&zg#!>Tr>q|i)?lZJ`8Y+ zrmqRA(annzcr2ttss%GkrCN#Dr;|%^B9Uj~x8PQ=Yshr1bI;%fWh25D$iBh6B*J!G ze{v>r(JxqDzlv!6wvyw58OoEy8|T>u>qoVldBWN!%Y6e`_hh;tGg91vc$DTlK0cT4 zhXC^f-%?#82DBkq6-+j<67)t}nz{iSVYtR0hDWNnvcg`aDT3^xtfB8gD{~IHH3tDY zq}YtrAMp5c^{}s6`}Eq4&Rg(k^#Mn2;BN4aUK|=0Zz;;t!zp&EQ*j?KJhye0C3_vi zwX)3!^N8X7nf$F`vlZ1SNWNUTUx*SDkCK(aFi(_0kh;CrvJdI_KJzIP$2AkIxLBH_ zU975}yqKU6S3F2DP69wh@VmJZ3P~c#?6=--;sA^6n~FXt`mQj9__#0=2tbsr7yQb8 z&rBj!e<#b*kBzzU%3%sxM=qD9VllaZp5)oxop(vfxfFW*6io+TW@IDgxz^$he*RG@ zz|Q^kcS>CiVK+--xL)KIwQ`5vL&OO9$Eo+3Jv09>@e3WmE52jkKKG6B`Rek3%5R;z z9Ng!-hMZ{sv}k+@i75G3m)n5LxG z=JK~C{vU?PykuF$AtAJ|c?fVZUqPke;)?-r98|YMQsr3MVlu2JQQmZBy9hWi=ua6< z3WoPDf2a=8s+rft4(YCb=5p^oxR*OzGd6%cHt7ms;Ck7fG^I&WM_l5$Lv5fU!}v)^ zY1(*%%BgneHg2O3e@{*jd)u zT*4Xon%wg?c`E8EWIW1kd{{glO~kjT%Hux4->Z>4R3s66L7Sn*0WvFbkIypf zu6O3Y3}|GZI#=*vcH7F~wbXZRa5VbxV@tNJmzLUGj(I1B($rsJ5WG;KP<Vp)CZ_KcI-pS4G$(;0ipUX6+3WQ;|~tVNcdzCiwe zrF{idl}pq%(%s!49nvk`ARyAI)Sd(S!*})5i{AU)wfJb|H>)Oo#UZ4iZf`!F7AMZhM&5 z@nXBwa`_4C=jUKxa?BFD?V;NFP}0V3sj!jwXwp{&HLl9nuf|T4GKLKpKF6?FG(@wk2DP38 zL+`Fjl$ygW$H#oG-*?e7JqXIAFZM2`YnSz7nNZ?~{uHlmj9?JmhV92w->qHeN;CY{ z0M5{CC~|01B1f3(NG(G%FY{InlFJGn3dlowT~#VuO)xK#5uPhXqX-9F9gKU>J>h_H+yw9v_4 zXqIJ;Y-2-%GD_eCr%r5;GSEfSfJ|d*{JPBaS~s1ev#hG%ssG}+36q&v_}0u}D8Y1e zJzvK~FjO{Fl6D48@cxb@sxKc$e-;uWVu^iLsw7Vc9Rg9%p2}y24J&2$gEG*RmE@R}WQp>gD57}EgIGTA9wMqD7K>rnI|Nm2p{uD(1e0gu z1YaUZSLCY?U3ko!!dR-oCvffHD16zc*bc&9pT-E?Vso_farS8ozdQ0sr?bgl{<{Wx zn^TEphzbJI4GfG$@gGL(cVnR%oRi{Yl{W1uXLK|eStN+>b5f)}y(kbNug}aPiZS4f z(Eb5V60%X=eJ>IcLF7MVP0*an7iPV2SII9{7L^Q?FDgFPH7|5ua$M!O^!2I^O@uW>Zfgwj#`F5CC?8SZb}8;R z`uICpqWz6b1@6N)WBEa9>-ed5##-Ds2UD{h+KE%F7se^cJ>1*7imm>#*UyF4Be^k7 zK0F`Z_IdtngJpw7eVsHF@iR72_@wdk@bQ__aWcZ=b(YOb@aq@o!IIos9ntQZbWaWY z41+^ooS(27^^Lo`Rd=)4!7_$ypoU4?7wBGCCsuBLf$0r~y;g+vrCH@s;HwaktFmw) zOz*JWP{=sZOvSXV>OQqo?>}YJ&ae)X9dOE&t!k7A#58Rb$vf?WmA0>c3BWw9!=2u< z`^c!-4a~Vismvt@h`Tk)li+&IhqdEIQW~)&iu*c6eBUW2e4ouC;)n*NZm!2vqcXWU9LJ`!n`yrwY|=o79@m7~IK?lRZOO zFkeTrD!PjKETa1y!hBzJ>K8!=6dP&vhISQUk0&Ulp1dJjzz&D(Ft?93ee%Sl4{>Fb#QE)?8~p<4RmEe(bO=yoPF_Qbd*oP{@Iz zDT#@G-04~t1FtzPz(jvU$n)L->{gF3J5#3Ak0$4H7=^gitP@iV%jNYBhjW|ptc=$x z7A%fQN?IpxKG2v{sWlWTCtDj~X!o+x=+ZV6@$~5_;@UUO!XzzpztNZpbrk*Bv6)yA za*$5KvY>3hqFT$0YF=m(l0;8ZSipr|Bz0hJz-Ttx|4b7!4FW)gKC48uU|vNw*wu+w z2F8}Q$}ostt(q!dIIGy~g-(TpH&^Z(NyApjhug`hn$9F6L|qVEtv*^M1T9bdbO>OSii6O9+?m0%MCgaBz^7wbZ7AX< zDOKtxMasbM8qqgSEuF9xYld&uHD)Fs>?xfjVAX3%cm>mjXa_t)Du^Pk@(+=awG=wvTI}T}pRO?i11;-3|r0qQtOt!8mu0*B_T&2=`#!of?yQc%wm9l5!I5Re@e zqsC=6r{iqqZ0rM^#r!(snHnttsqWOqm{dfk$h&kkQjq@uO&0`q>yG*%jneTiB z4Eq!wz;SPTpBxT?oy|3j4 zSfFn(tS|p34kjgdYSyMbOf`;m><=GioUYe~HX)bWq2QZiTi$#&|0?Qhxy=J&L@uqD z0~6d8YXG_22laO6neXwIFo-!D!#J~aK&P>D(8u7RSObXxR!$k^GYJIf(ad$PewSsAGW%~-!_x9QuI1`FS(6S9o{z+svl}Oj%|m{t#haA8 zSPX2gI*|muL5qO1NZ~D~34`l?7fWsr03AxN3jhs0GN!fQLrQE`r5KFK5R}+r{JDk< z&tz}ViW8NAT|+(isj;a{5dx)nl6jKqLTGo0BgFb)7YhwQ5!ViGvEXC?vZcM$zlO-jh3L$|Qk z99IbP`a*rVIj-#X+Ddq!%T0I+O~LfZ15yYc(I|}y{-NZWh{FU?M!nm<5W?l0i_+~@ zYm3*Z-o_VsE#e4J!E&c!OpZ=g+&g``wbv=%tlH48SmSe6SKPPWi(l{V61-yg*0}qw ztN5KD63m5lqg6)HC+-hQYWyxE^q#);TZWmK{k)|(Xa`ZSM(Zo}Wp-AH{G?#@tpXTd zS6EB3&+KyE-?P3g++m%%?ha2p?4a`VZSwzC1$E(3XW+J zt1|VP+&9Xwri>09t}QI6PEV4X3ngHyHBArV zciRd~RRmzd*QhpZYPE*Z7b6puS}i4&5KEEMjx$qEyQ$AQ2eHsPd|XIs%B?>G)xvj9 z&sC51;U|<_T$ILFBANws$)Cf2D4oYp=tX5c^)Is0Xw-U34IhC8!y(cx3AIJrzrh|C z;!(n$KRE0V%$wIL3kIh&R%ey=G+{0)vSj#NFj6A{5#h@Qi8Y7b&Y+x#5oS5rCn>h= zw`FrLchFX#cC++^^8V<tB+icDc~hf)>F-r!aZg{fU^2Y`ibLP^b%2^ L@0Zq5qN+E_t zHM5yMLum~bz1@mt`UVG0Sn}5)=!7xdE+6?qa(g5+@SS$QsZcAWno~Immw=Yw5w%L+ zq`+S3^&BTL262ny&NI=;7J_^0NMKU50{R$NKKVP&I@+~MV0?(VcgOLcO_}OOJB-x$ zos-^0)x=k7f8j00UI;0D7iUBrmTkMscLtxFa+C)Zh+YVVR>U4HJ}OJMpQBkep6o(> zj9oXvmejx4#JYxk0y*Wm9ZNTg-qPkutO3!BaSp4&tzzt`u>B> zK!5mnFCp%^VsNp_ZVgSCl0~r6GhU%^-8<-;^25@V`;Ig0I=}pV;KY;UK5`gT&NA2A9sx>v>^bm7TjbQrGv1=N~X) zc-P}k1W=czgML=*3Q+~k!YwtMKR$flk1sNay}BtQp*T0%0JFrFlr@1Gb4zoR4;u== z9Nx>E6?)zfFdXS%687nMKa(rq!^p9;1y;ex6P&d9mHc7)evD`(ev#9Uv|pp#hdzw5 zsO`bTxdd-6_yhf*HYNtdji~MVBvm+=JpFQ!a^jJ9`wdQU-?=@n$O_nkB1_YxNqhGS zWI2rW9s8(arxU%FEY>Kdy0l6}kmtNHt-S(^mJGcenwrE%Wf3(zUg^U#REXV%$}kVe zf=en9qE}F73Cx%k($d7XhuRso0#f=&G z-!1nT5%J4SpA=T6FX!T2fz?NP%5j_$?JD2VE_M@*A96+Aq2BUJlv(I^sO*|vElEc2 zTDyQYiAR_*=L)iPq`iH{o(gHKu(N+gwu>)3%>NdnZp5T8>0HplB1=W8bbLHxJj1tX zDj@aSlPMR}7Sn4k7f4>D*i)XePA187d`D)aQCIMr)v4ANQ40d`IN8nD@~HW-Il0QutC}&*&jEp;Fa0;B~DTR2Q~e zb%~su)3YjeQb8oBvK z*m=wV>RuU`pVvQ^GvAM_7p>NCw! z&cT;DW3bb2S`R;+@4MRtN$(hv5^rP}#qfqWXv09}ERyY#SB?ii_mP|IF*dJ)S|yQw zM$nkeQl+1&ni)P-xG8m&=-ocB!0=Kb8q{c_K8&{#1y3DW;>ZxK`W5)dyrxrK6SW+q zb2LxesJ7D{h2Lsio&t#zIjFP%1s2SKIBdL7!>q*0Bs3hFF`ih`kx-IU+#*u3Eb-YL z#FGnKztLOh_+=75KA{n}7nEvwH6TIDt8OmI+ar$Gnm2^gqnCAIORHLE&z7b5H&k|d zzH)!_lk<^AT|&&#<)nTiIt`LQu5U|n%j5#r$R^Q}+AM7O^!ak0F-QX?(=CtR#pOis zGgE8D^jDa@{wEf-pRT$I?{*Qz_IWSb280{ep>$^DRgTTgDpPE zl%c9?$AJUU4~3>=krN>=C*zw4?3^4~#y89>6&q5@<$xF0$DO;X zZ3;hqIUHsz-c67Sk+>%Gf-zCx%pKl?5b_!G0ziz0c3?ipbmpi!ej+MYU>6 zgLJX77Q=WnIOc$!c*3q2bG$~EK0Ssb+QnaMeJ|?l>oE`QvD5t=_~$-lH4&bQ8u15Q zKvr_p+wOqOee%7dsO0dqAQ(9#usq^_bh`O965rT+pkb97xDn3sA52wbf&gGVfxp}! zZ2z)b703RM&vegy4c`6^Bpy}ZCpaGgxR}hWKqh%N=spoNyP!rUM^l2y5;jNClc!f& zZX`icSwTdtNCwYq3g4GU`Y_43eB!!XSmxSZvYk(FY5oTCvO5?OV;r|UVV6=;g{hDv z%o%|KQ!z$~j(KCxqoR+uaLtLm!>J1kp@O7#a}Ka*KS-%rX=ZA_Z1|SMcHkssg}r0L zuKe~zEJ@Rz1~`L6$Bjb;ASADGE6SjDZMsflvpv#9{{@tWYzT?xw!xc_9!t=k%k26s z=W11Z=R$*M6T(pZ5F82;inV>}eckAm(pkJGSc3DtjLcfjUCTD(o7x=<(0=P|$^dqp zSDLK)Hd@i}V9i*75gI99UPU>zrII3UY8dtKj6; z%bt~;(vV*>x$R8u-)HKq6 zT`%(f?A0qGo+9`S@`Yfg7(`)`f&2(2{|c0Kl;VsXDmU?)x=c?oDZtF-E=U;;sI>Vs zVj1$29J_a9Z#PbBu``dw*i55L+(gBe^Gs~~Vf58#;|iuoOwDcNG5H8jjv~WD(?`R2 z%ND_Kngb0IcCDCe(Jhi=C>U`7c3hfVqLdIjcCs|^@R8HTxSz5&kw#h}aHUzZ5^_8< zyt#~8e(~jeIMFXY3OI-Yj`T_nOV=k@GJouIE_7acn z5%2c!;4weH$CD3hv&1DCF%){ak%DUew$zGa2?04eBnSuw#sy<^xmGG^T4PqPJHY%o zFO%Wxs(9}rH4q(>rvN+i7Pg5xt)>Ch+ffy|4Gy*aj2Z{L)5+B4Ok^h7!i@UUW-3L; zH4c9FamSoO4qx^bX4jhO*QpYr9S^+(mtP|A7*M%w*0+~(J%uTp4ITh*Q(88lF=A<9b%L-p{r@c|?L3qJb7W{5MVeE5ErVaHTd^gbR zmB%%Uka;kLpT%WBl*{6MGQlpQ&{04e56^-D_P%Xh&gEIZa|8VX_4VavpHOKQu?CQfDdhm9oT z!%BRTZy3?{?Eb@MZak~3#HJs0x`dA>!kied(X-Mpi)|Q;2?dWK!_z@2dEN*I4~efJ zM2WX&CT`a0bt2ZUB>5z#KBZ(CVI&w5=m<^nKC{U5s*P+nU)a?VTdPkrHcXHy9Ag@! z(df*skHTI&;?)$z}(+gBz4*XeNB2yd! z?@*QGRpws!Fqf3c5*qL{(S1`OC?2B;{nK1-ZoGtjdyb2E6-IFpCQhzPks5@8sTw{V z_DzX$K_WO8Iv-3m*j%ozx?c#|YALs#|LpXBboHpsIn5yj^B5+a3@o-q!w4ru2tfm? z46{kK^1D*%Ns*1t6lN7RDi}H$NtY}_3+m0J`d6h%1qNIZpiMJpMz)=H0r{-tA|DY5 zLucT-_fW#{2z(XI4HJn{qIZTJh*CQCPFCxtij(X*?4;vrTVh=V%}LQu5DYj9W9_;e z%5T^4PG|Gxd#T$>E)aTW>mrv`;2cQTFy;IA;+<`Cc-|jwu6b&;YpXCg7g*t6REQ1H zeQ;z;Yd7-5a`&E(I$@{47L%KcJ$aUEF!)BjQxE4@7$q`ZUO>K^?zQ|!+N@5M3lSsc zixUwMH8F^KXkjso<$lJt(pGvLb`$srYp-Md3G3eEW1L~TF50I)&fMO4G#cm^c#MZr zMe#zhby!9%Mm(+1CDXIM5n9eA2_y=PKoNufwjRb*GQmZ77gvaoRDng2ay zV99=a#6eHB>FfE9t~=KJvXR0yMTIpI0N-4f)inx3n!{w zyHAu{*hl18fSvm;uFv7n-Ilyn$0KyIyo)kdTj{>vgusv}^3QqNiE~?zi{E>l)`CET zG9bwEkM9{e%W)s;lo(V>&1vs3h`G14Rjj94wk9v4d_XHlxSG;MxSG~w#lXX!xtlfx z0j-J#w+n9GMj;KyZ?hX$NAqTZ9Sx6Mf>z34JOng4MPOduQ955Lq=(qFAi%Q|6X*o$ zd>cd2_fIbq@@0W%SgoUe0qwmCDTe7Txcmt_WYq2qT2I@Izl&_BQSddGHw?)R8X?DL zWz*ebtdE8pZTlI`0x>=_&?sndo$Udg!oi;pk;}#XLd45N0x^+uEJH`$T4BT+J$nOx zNd*y~dS!EXWpieE3KnpVuht-SqGh`6EsZH@liCd`X|eJ&pe6Y|^_SQTlj>cK=Y!_aYWat1Lgkxk?es#6yFKGy&Y1YDZzlNvuDGI88!;Mzb2Bk;Zl?QP zasB3$`Ri$mFa?eO2`y4xLw`t`qlqp^g_TL)AB@%bvJjk!#JDpX($`X$N6r6XQl>}o zg#AR(e3cO-6(Qmd+|vJa@GJ*i(k(HS>o)b+ZJCRu<=*Z7$r}_}YWp* z4aH~1R+b95FBuaUQsPAjWsyZvc)jhCQh2c%Th)^$_i5janph1eFvjqQN4<+KLg>4b zma_?{%hWX)#e>K%ShO+uS{Ffp-O#${qd&&zrvm|&XQF~1a46k}dlNZnMNk1tAzN6I zOu><$cAn5Py);$(Ni@)lRi&mbxx$R0rsKlto!TweJu_XekOB>%i4%C#bKG`G=aNxo z-ceR(FFP3ZcD?%Ni?VDnCn6mR)J7Ng-Om07dam))9|Gcs-}xT}(k?+XY2?NF(~5sw z;<_P@wG%gfqvZ>G-`8B&u4T&FF2k%QqXqHK+o{Dijtpui0F43LXChDk)D8#X$$7mt(@LJL%t1jOo ziQ*4=jm#s2gyT-+uRyuFgEEHl)#oB#%Q}J8$0T3zefm{Tz7QcA!DRg0WDhmrN#VX- z)cso2c?{huR31;%x{l3A1b!C<6Nb8z7>cn6PS}dQBkfiM1=rK&mqd79`W9IM zZa8*^!riZ^Xz|WgqI|$Ud_>a!su$mVjTkmt-Nr=}d;iPy{qTlb-CAaw0DKAxfTvmi zQ@o469s@x~9UFtc9AJKlcTubad{>o6=B)v`T|0cl$n;o&(nYC9hh^){gGFT`Lr9un zZS$--RL81m*gBdD7e9gdx{f3x5=O@7g=CPT5vM+uB)XP9JUp0ao9noBbocfA8B+bhOgSV_!d;b+7{J{VHZsOMU2V}w5;faonWG8mI6dajc+F8N zR`Ak!Kqf%rZI7lC!2J{n5KFSfU(q%Uc27xEgL4>@yZD(kir z{WK5{ndj4k?o8|ZmX&3`_<08EU?Lb?9@IT3Ec(xDXMTveCCa0JOcgJJ#} zAs9AAhYAnRvi4%_CINy2o!K-Fq;u2VN*IIF+j;s^h5^OhoIUxx#8dU5v&MsVe658b zG)>XEY=*mmSl-=Pv&#>uX{OKd^Fl}QUgbF&f_K<-dE2Q!;}y+%X%y~nRKDFyi$W^J zZvNuf7w3SMRLp~DR8EloL);fSq_834E&!9zNBGST{s*EN-^kcVJDp+PKRJcHM#W&s zZ4tO0Sq%{^QTiA{Ikg(J%3Sg?ZIz}QG>sR&QeJeOB};@&AkJO*fPfk5rDF~y%Y^e+ z-d9i(2aqKfAK&LoLRJTIYV3{CJJ^MITYyi`v#r+(Oc8IAxxXH!Md2R6FQNWI8!eoM z3{wuV)+CC#du91|#ZL(?0gnUp+B1AGM*Ob$fAR2og*$w}&l5K>zs{G%2Tw9H zp^uGnVG;&ON>#s7krW%!8sF&xHO*Bg_bmf!a`uAUtKAkR-tB04_GBhDn4Gz~ihY7? z_U4k*?f`Vrc@+%ZpjSpat*(@3kk&0G&x=xD#cXn~$}v~nV3F62y1-~Im#F#;91bU! z`W<<~wGTP0`C?v&(pJnWCJPw7u}`8GLZeSUoGmgqVaLZ~D|@ZDkR;WkjA*6WX}SU3 z)8+aF>Zg1kREqE@=GGq2Bhn4HBKS{X?1T&emNo`r#x}Ng3ii6+<^R{}w@cYv0hrIk z!=l{Ey23~TA+~x(!dE~WTCh+684e`^HOM@MeWpf6b$n8Pde*GKGm}5_zJ0jTH!lA| z!|*2O{yl%zxUHieG(}mPb?)ndpJy>cv6FVLJ+P^(Z@2wP0CFse~1EK$P|VgMc@U|=eebLn_3&bhV7t_d(n z7VJ-I!0o`%nK7A=O0pNHSL#FUPc*2iFIKNl;0TM#7(mt@JxY$N&egDQ7@=ZwXQsmQ z&s3W&P%kwFPd+8XIou1B#ib$=Xb2p4#`G5)rqf8HFZD3ob&F zXqx3vYfbjL1bA`pC-6wiQZ&vLvOK$6uFOx9Dvba*SxpCe5paMG8ik}leEg%<7jShL zDII}6I*kL?0VK|(I9*!}u+=9JJ@K%?Gdh7zk{?zGn{^W|L+z%Wj1t1bp7l8$eISRx zVx&-YA3)~kZY@_bo?z|Jc7HXMlzt~PZjhab*+;WVYB4NI(Y=p04&UbcbugaL$RK&0 z2ZBb5R5x+8U^|jMoO8tL5@I!euOpVD5UL5;2IyX_On=Cj`5qG>=h3#S?VPv&F=*Wf zo86U0s7aefjXu80g_oN{IDY>X(xr2M*kswc$zI%z1o|goNE&^NAwcbn?D$ZOitD@# z6#N#1?};|{fmKABxA5NGj7)6JOP4uQyV4}c*M>qEDX%JWqv%exoR)aB^OdU*9cO9R zzMVoE%&bqZd_%fw>6A(7q$NGefF0)vh49U49PdR+|8Q}3=@Jg$Fh0uD4(jrJ%YZ3& z(00!<1`l4a+)ELXym9YD|?LTI^C=tnlP8E$4X-=z?)fIEYD)sSX?m=~z# zOi5XhNKX!k{lN*`V>TppabF>msR85OJ};J-uob6w$WU&v>cC88WWpMQ?O>ALV==Vr z84F=;?X9w1#uD_NUfv#2|V!- zhdK@g(qJ@DHar7eSWEZ5TJen0soQWnF_{3DYOV+$=j!rm4^>wxYFn!pZ#WE|m4Qnu z(;-|bsyg*$1)sOX07M`ZGeAT^v&A#;J74ywpnI=Bkuona@+dFvCSv6hJT!4Ct{N>v zC?2=%Fan01F`P)uvOwni+QXJVua)sk%o}|os>QYpitBtuegHIRIBTsOH<1P{*7lY` z0J!4-BSo{N_Yu(mgVxr!pO&c^b`t!E%qq9}tkR3UB{Px1jviu&E{iAM2zY&#r4C!b zXL_K15B~F(K1>Vr7)Cx&z}wjXG!`-ceoKFucE3AT|Mq$rtFUZ2_7eS0mKq(-wsk>~ z6^#R*k$umN1zUzJDIvlf27u(+Aka}CqhUKwf5U&h7DB;y1$6~nahcER`+^&fr4e1G z9J_6&%rAR-+<{tw^oZfkvop^OXPK$|c2&3C2DAK~9fb{us50&2v=HglE1`EO+S$*!OgLm= z)EF9JC1Kdc=nU7OX}wc~D$1m(C~gpz@@#_#sT*ojam=yui1OewaVn zAAcWK|Ff<14=)@0uf|^@-^pq~XFrjG=;YBg$e^!;Kq+&gR(ke|N>z09b!I0n6-+eb z35FZUGMJ&=%S7w1+o9oW!kkBvu;|js?TqW`6|N4KZibE(4O}gEZnucU{-P*DfvjVw z7^6Oc66Jyn{#MehWnS}|EHpx`30^#)-J(v`a(;ogpoGv8j1$S06GFuOBdKFynq-E( zh0f$rLxqvq%^yij3#pY9F!kSOU|W|Hs<2Hq_ApNFo86VZCD*3^7y^tr?G$xW&_2=* zajJnw8+@Xu-51@NK2~AlA<3@T%mB-~pyglPX{x|Pq4fR@pjtUN0)8wsms*UO0SgvZ zEsXO9n-ei$?F@iKA1*25Oa?DgAID_S@xn5xpae#OxpJ=29fMk?-DNgeJ$ku6vax8B z6leTpm1d*n*!F=l4*T^=To}HbCJv!H*J3$ko|KR@mce9mlQ|mJ=ZGip`-WduQ#(S` zx>jAVHl;%ueBr&-hnWI#+y{DTqG?JK-Z3XXNh5^uNQqt%F7y&drC=g|quvfr$YRH3 z;Hxt@8fiFJpKEE_6C+?q9_uGvJ4lfHe$Kw}O*N>SIJu~27@NT~yuHG1Tm##uc-D^3 z`Evzv2?uy+^W~ZNVfj(IpEulvHjgw#l|owCv$&%x)N)=zhl=G(1(+Cx@-?v3ykH|r zjOMtW;3UmJ9HyoamfMYxC@rE^v%NRVmuLkID|njO#Bb49cXc551-N#cAXFc>g!lz#c!*cms6Hu92S)vn*f%dor$7py^pzV>xhvW| z%`5Ml>$~*N$AYSek+~$j4x_adP}Yg_hiwh`u+b8G%PQ=L__b@>UI$$2vv8Fa2H-Qa z1F0GAqux9)n&KRFZFP8^byPc4ptUeH;qT8dwO%L~ea(K;HHfHJvK=rh1XF7T@+>2K zC7}zV_yZS~&`iHc%UdQdI1x%Ju%WZHJ+eNftm)^ZE`jaS0+hPgPdrV!kSUwuceFl> ztHYxaVgZ73pRc|C`%@|Jq+clxRPv(04-xS5JrMx#sQdp%5&%|}KO_Oz{9EY%C!pwH zf9*}U0H+)v@&AUs2danf1sUW}@ZqbBsG=afq^ub5r2gNl6%Fcq6aoG~4fsKS_~rMK z?ftM^{NHLag0hlgq6&)7WW*jLJX8Qqb^lX<)7|%i4DwAd9r)eS#_%`JhoAhY0bDnI zFAp_3fZrc#{3XJFtq6=+`b)*5zgPU8gyA;;BOiUhd*DwefuE<}t3O;Sy-9#CV81Z` z01yENJTNjf0RmZ2;hJJ4e;@69q!XnWar0>+Xt$)1wfj4;D_`F9q?M|?Fwwe9~dQn^x>~n=3_kYe3wN{U|Z#Zwdwzc zX8<%7{{io>{PRk{`12B$<_0e;ElusM{tS)3rZwLM1i1l@(uW=4AEnY89+;2o575A% zzh?Hfz=LIC#%2bBdU^)7wlX>vI)*<|Ej(_!Ua5Ee8(`a!fd;+5x1AL6j|3_y?2G2LVdwL1p|XmEItje?)&_Y50#)7`E9D#sE5+SOEL{a4zacsq~HpW&!zwnE#ge z?$6!Ntl?F|0%p%JCjo96`~U=AE4>eZ?fnBL@Km6kj+xn?(H2`@1a$(184FZQf4@(H z41Yuuvb3~&$h%=Bqho9VG`jxGw()ofw22b;3j^;_6;N&uITL=AO7EAfe}w)%1Vo(- z^z8pPeEMTlKiurXav-V@P=GW)Ac5CP?^(V-qW<+ze8+xh^q&Q>_9)5i59mtoamhd8 zei!RMsh`JL4u9g2zWgKJ-){Xsoj_`L|v^#ISi>`EeGRAJr?p zrGKyd!%yIs_w`5C*T?XWGlTqupVI!VZNI>NUtKc&J{liZsgHAT{6uYk{U1>OB_qe< z_CL;b@RO-i_dhWG>L~>5oz<_I4<1uJ4mJOis?6ZusQw}F{A2jXG1Gs-iy8hK{P#QY zZxPfVQ#}s8`jg7Y@;^}hCA9xbT#w^d{v-*u`41%j9?kM`j~<8n`$^Vo|8Hc!Zbv`H zd>m}*CuW-KzhQpAA%8*t^~W!}dyiQjM>YD%lI;E)%m1ML9^>dS=HrM8KQV3J{*L+I z<10Mod3?(MCy#i*Z#=&%kNi>ZM&o; \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/msvc/ReHLDS.sln b/msvc/ReHLDS.sln new file mode 100644 index 0000000..cf5e61d --- /dev/null +++ b/msvc/ReHLDS.sln @@ -0,0 +1,88 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30501.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReHLDS", "..\rehlds\msvc\ReHLDS.vcxproj", "{70A2B904-B7DB-4C48-8DE0-AF567360D572}" + ProjectSection(ProjectDependencies) = postProject + {792DF067-9904-4579-99B9-46C17277ADE3} = {792DF067-9904-4579-99B9-46C17277ADE3} + {CEB94F7C-E459-4673-AABB-36E2074396C0} = {CEB94F7C-E459-4673-AABB-36E2074396C0} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cppunitlite", "..\dep\cppunitlite\msvc\cppunitlite.vcxproj", "{CEB94F7C-E459-4673-AABB-36E2074396C0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bzip2", "..\dep\bzip2\msvc\bzip2.vcxproj", "{792DF067-9904-4579-99B9-46C17277ADE3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gradle", "gradle", "{FFC337A9-D58C-4D62-B8BB-A54DD4E4DF41}" + ProjectSection(SolutionItems) = preProject + ..\build.gradle = ..\build.gradle + ..\gradle.properties = ..\gradle.properties + ..\settings.gradle = ..\settings.gradle + ..\shared.gradle = ..\shared.gradle + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Play|Win32 = Debug Play|Win32 + Debug Record|Win32 = Debug Record|Win32 + Debug Swds Play|Win32 = Debug Swds Play|Win32 + Debug Swds|Win32 = Debug Swds|Win32 + Debug|Win32 = Debug|Win32 + Release Play|Win32 = Release Play|Win32 + Release|Win32 = Release|Win32 + Tests|Win32 = Tests|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug Play|Win32.ActiveCfg = Debug Play|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug Play|Win32.Build.0 = Debug Play|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug Record|Win32.ActiveCfg = Debug Record|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug Record|Win32.Build.0 = Debug Record|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug Swds Play|Win32.ActiveCfg = Debug Swds Play|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug Swds Play|Win32.Build.0 = Debug Swds Play|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug Swds|Win32.ActiveCfg = Debug Swds|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug Swds|Win32.Build.0 = Debug Swds|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug|Win32.ActiveCfg = Debug|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Debug|Win32.Build.0 = Debug|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Release Play|Win32.ActiveCfg = Release Play|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Release Play|Win32.Build.0 = Release Play|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Release|Win32.ActiveCfg = Release|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Release|Win32.Build.0 = Release|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Tests|Win32.ActiveCfg = Tests|Win32 + {70A2B904-B7DB-4C48-8DE0-AF567360D572}.Tests|Win32.Build.0 = Tests|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug Play|Win32.ActiveCfg = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug Play|Win32.Build.0 = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug Record|Win32.ActiveCfg = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug Record|Win32.Build.0 = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug Swds Play|Win32.ActiveCfg = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug Swds Play|Win32.Build.0 = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug Swds|Win32.ActiveCfg = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug Swds|Win32.Build.0 = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug|Win32.ActiveCfg = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Debug|Win32.Build.0 = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Release Play|Win32.ActiveCfg = Release|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Release Play|Win32.Build.0 = Release|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Release|Win32.ActiveCfg = Release|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Release|Win32.Build.0 = Release|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Tests|Win32.ActiveCfg = Debug|Win32 + {CEB94F7C-E459-4673-AABB-36E2074396C0}.Tests|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug Play|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug Play|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug Record|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug Record|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug Swds Play|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug Swds Play|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug Swds|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug Swds|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Debug|Win32.Build.0 = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release Play|Win32.ActiveCfg = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release Play|Win32.Build.0 = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release|Win32.ActiveCfg = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Release|Win32.Build.0 = Release|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Tests|Win32.ActiveCfg = Debug|Win32 + {792DF067-9904-4579-99B9-46C17277ADE3}.Tests|Win32.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/publish.gradle b/publish.gradle new file mode 100644 index 0000000..40763e0 --- /dev/null +++ b/publish.gradle @@ -0,0 +1,132 @@ +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.apache.commons.io.FilenameUtils + +void _copyFileToDir(String from, String to) { + def dst = new File(project.file(to), FilenameUtils.getName(from)) + GradleCppUtils.copyFile(project.file(from), dst, false) +} + +void _copyFile(String from, String to) { + GradleCppUtils.copyFile(project.file(from), project.file(to), false) +} + +task publishPrepareFiles << { + def pubRootDir = project.file('publish/publishRoot') + if (pubRootDir.exists()) { + if (!pubRootDir.deleteDir()) { + throw new RuntimeException("Failed to delete ${pubRootDir}") + } + } + + pubRootDir.mkdirs() + + //bugfixed binaries + project.file('publish/publishRoot/bin/bugfixed').mkdirs() + _copyFileToDir('publish/releaseRehldsFixes/swds.dll', 'publish/publishRoot/bin/bugfixed/') + _copyFileToDir('publish/releaseRehldsFixes/swds.pdb', 'publish/publishRoot/bin/bugfixed/') + _copyFile('publish/releaseRehldsFixes/libengine_i486.so', 'publish/publishRoot/bin/bugfixed/engine_i486.so') + + //pure binaries + project.file('publish/publishRoot/bin/pure').mkdirs() + _copyFileToDir('publish/releaseRehldsNofixes/swds.dll', 'publish/publishRoot/bin/pure/') + _copyFileToDir('publish/releaseRehldsNofixes/swds.pdb', 'publish/publishRoot/bin/pure/') + _copyFile('publish/releaseRehldsNofixes/libengine_i486.so', 'publish/publishRoot/bin/pure/engine_i486.so') + + //hlsdk + project.file('publish/publishRoot/hlsdk').mkdirs() + copy { + from 'rehlds/common' + into 'publish/publishRoot/hlsdk/common' + } + copy { + from 'rehlds/dlls' + into 'publish/publishRoot/hlsdk/dlls' + } + copy { + from 'rehlds/pm_shared' + into 'publish/publishRoot/hlsdk/pm_shared' + } + copy { + from 'rehlds/public' + into 'publish/publishRoot/hlsdk/public' + include 'interface.h', 'interface.cpp' + } + copy { + from 'rehlds/public/rehlds' + into 'publish/publishRoot/hlsdk/engine' + } +} + +task publishPackage(type: Zip, dependsOn: 'publishPrepareFiles') { + baseName = "rehlds-dist-${project.version}" + destinationDir file('publish') + from 'publish/publishRoot' +} + +publishing { + publications { + maven(MavenPublication) { + version project.version + artifact publishPackage + + pom.withXml { + asNode().children().last() + { + resolveStrategy = DELEGATE_FIRST + name project.name + description project.description + //url github + //scm { + // url "${github}.git" + // connection "scm:git:${github}.git" + //} + /* + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + developers { + developer { + id 'dreamstalker' + name 'dreamstalker' + } + } + */ + } + } + } + } +} + +Properties repoCreds = new Properties() +if (file('repo_creds.properties').exists()) { + println 'Loading maven repo credentials' + file('repo_creds.properties').withReader('UTF-8', { Reader r -> + repoCreds.load(r) + }) +} + +publishing { + repositories { + maven { + if (project.version.contains('SNAPSHOT')) { + url "http://nexus.rehlds.org/nexus/content/repositories/rehlds-snapshots/" + } else { + url "http://nexus.rehlds.org/nexus/content/repositories/rehlds-releases/" + } + credentials { + username repoCreds.getProperty('username') + password repoCreds.getProperty('password') + } + } + } +} + +task doPublish { + dependsOn 'publishPackage' + if (repoCreds.getProperty('username') && repoCreds.getProperty('password')) { + dependsOn 'publish' + } +} diff --git a/rehlds/build.gradle b/rehlds/build.gradle new file mode 100644 index 0000000..7104901 --- /dev/null +++ b/rehlds/build.gradle @@ -0,0 +1,382 @@ +import gradlecpp.RehldsPlayTestPlugin +import gradlecpp.RehldsPlayTestTask +import gradlecpp.VelocityUtils +import org.doomedsociety.gradlecpp.GradleCppUtils +import org.doomedsociety.gradlecpp.LazyNativeDepSet +import org.doomedsociety.gradlecpp.cfg.ToolchainConfig +import org.doomedsociety.gradlecpp.cfg.ToolchainConfigUtils +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.doomedsociety.gradlecpp.msvc.EnhancedInstructionsSet +import org.doomedsociety.gradlecpp.msvc.FloatingPointModel +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.doomedsociety.gradlecpp.toolchain.icc.IccCompilerPlugin +import org.gradle.language.cpp.CppSourceSet +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeExecutableSpec +import org.gradle.nativeplatform.NativeLibrarySpec +import org.gradle.nativeplatform.SharedLibraryBinarySpec +import rehlds.testdemo.RehldsDemoRunner +import versioning.RehldsVersionInfo +import org.apache.commons.io.FilenameUtils + +apply plugin: 'cpp' +apply plugin: IccCompilerPlugin +apply plugin: RehldsPlayTestPlugin +apply plugin: gradlecpp.CppUnitTestPlugin + +repositories { + maven { + url 'http://nexus.rehlds.org/nexus/content/repositories/rehlds-releases/' + } +} + +configurations { + rehlds_tests +} + +dependencies { + rehlds_tests 'rehlds.testdemos:hl-phys-single1:1.1' + rehlds_tests 'rehlds.testdemos:crossfire-1-multiplayer-1:1.1' + rehlds_tests 'rehlds.testdemos:cstrike-muliplayer-1:1.1' + rehlds_tests 'rehlds.testdemos:shooting-hl-1:1.1' +} + +project.ext.dep_bzip2 = project(':dep/bzip2') +project.ext.dep_cppunitlite = project(':dep/cppunitlite') + +void createIntergrationTestTask(NativeBinarySpec b) { + boolean rehldsFixes = b.flavor.name.contains('rehldsFixes') + + if (!(b instanceof SharedLibraryBinarySpec)) return + if (!GradleCppUtils.windows) return + if (rehldsFixes) return + + def libLinkTask = GradleCppUtils.getLinkTask(b) + String unitTestTask = b.hasProperty('cppUnitTestTask') ? b.cppUnitTestTask : null + + def depFiles = [] + depFiles.addAll(libLinkTask.outputs.files.files) + + def demoItgTestTask = project.tasks.create(b.namingScheme.getTaskName('demoItgTest'), RehldsPlayTestTask) + demoItgTestTask.with { + rehldsImageRoot = new File(project.projectDir, '_rehldsTestImg') + rehldsTestLogs = new File(this.project.buildDir, "_rehldsTestLogs/${b.name}") + testDemos = project.configurations.rehlds_tests + testFor = b + + //inputs/outputs for up-to-date check + inputs.files depFiles + inputs.files testDemos.files + outputs.dir rehldsTestLogs + + //dependencies on library and test executable + dependsOn libLinkTask + if (unitTestTask) { + dependsOn unitTestTask + } + + postExtractAction { + def binaryOutFile = GradleCppUtils.getBinaryOutputFile(b) + GradleCppUtils.copyFile(binaryOutFile, new File(rehldsImageRoot, binaryOutFile.name), true) + } + } + + b.buildTask.dependsOn demoItgTestTask +} + +void setupUnitTests(NativeBinarySpec bin) { + boolean unitTestExecutable = bin.component.name.endsWith('_tests') + if (!unitTestExecutable) return + + GradleCppUtils.getLinkTask(bin).doLast { + String srcPath = '' + projectDir + (GradleCppUtils.windows ? '/lib/steam_api.dll' : '/lib/linux32/libsteam_api.so') + String dstPath = bin.executableFile.parent + (GradleCppUtils.windows ? '/steam_api.dll' : '/libsteam_api.so') + GradleCppUtils.copyFile(srcPath, dstPath, true) + } +} + +void postEvaluate(NativeBinarySpec b) { + + // attach generateAppVersion task to all 'compile source' tasks + GradleCppUtils.getCompileTasks(b).each { Task t -> + t.dependsOn project.generateAppVersion + } + + setupUnitTests(b) + createIntergrationTestTask(b) +} + +void setupToolchain(NativeBinarySpec b) { + boolean unitTestExecutable = b.component.name.endsWith('_tests') + boolean swdsLib = b.name.toLowerCase().contains('swds') + boolean rehldsFixes = b.flavor.name.contains('rehldsFixes') + + ToolchainConfig cfg = rootProject.createToolchainConfig(b) + cfg.projectInclude(project, '', '/public/rehlds', '/engine', '/common', '/pm_shared', '/rehlds', '/testsuite', '/hookers', '/public') + cfg.projectInclude(dep_bzip2, '/include') + + if (unitTestExecutable) { + cfg.projectInclude(dep_cppunitlite, '/include') + b.lib LazyNativeDepSet.create(dep_cppunitlite, 'cppunitlite', b.buildType.name, true) + } + b.lib LazyNativeDepSet.create(dep_bzip2, 'bzip2', b.buildType.name, true) + + cfg.singleDefines 'USE_BREAKPAD_HANDLER', 'DEDICATED', 'SWDS', 'REHLDS_SELF' + + if (cfg instanceof MsvcToolchainConfig) { + cfg.compilerOptions.pchConfig = new MsvcToolchainConfig.PrecompiledHeadersConfig( + enabled: true, + pchHeader: 'precompiled.h', + pchSourceSet: 'rehlds_pch' + ) + cfg.singleDefines('_CRT_SECURE_NO_WARNINGS') + if (!rehldsFixes) { + cfg.compilerOptions.floatingPointModel = FloatingPointModel.PRECISE + cfg.compilerOptions.enhancedInstructionsSet = EnhancedInstructionsSet.DISABLED + } + if (swdsLib) { + cfg.linkerOptions.randomizedBaseAddress = false + cfg.linkerOptions.baseAddress = '0x4970000' + } + cfg.projectLibpath(project, '/lib') + cfg.extraLibs 'steam_api.lib', 'psapi.lib', 'ws2_32.lib', 'kernel32.lib', 'user32.lib', 'advapi32.lib' + } else if (cfg instanceof GccToolchainConfig) { + cfg.compilerOptions.pchConfig = new GccToolchainConfig.PrecompilerHeaderOptions( + enabled: true, + pchSourceSet: 'rehlds_pch' + ) + cfg.compilerOptions.languageStandard = 'c++0x' + cfg.defines([ + '_stricmp': 'strcasecmp', + '_strnicmp': 'strncasecmp', + '_strdup': 'strdup', + '_unlink': 'unlink', + '_vsnprintf': 'vsnprintf', + ]) + cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp' + cfg.projectLibpath(project, '/lib/linux32') + cfg.extraLibs 'dl', 'm', 'stdc++', 'steam_api' + } + + if (!unitTestExecutable && !swdsLib) { + cfg.singleDefines 'HOOK_ENGINE' + } + + if (rehldsFixes) { + cfg.singleDefines 'REHLDS_FIXES', 'REHLDS_CHECKS' + } + + ToolchainConfigUtils.apply(project, cfg, b) + + GradleCppUtils.onTasksCreated(project, 'postEvaluate', { + postEvaluate(b) + }) +} + +class RehldsSrc { + static void rehlds_src(def h) { + h.rehlds_src(CppSourceSet) { + source { + srcDirs "engine", "rehlds", "public", "version" + if (GradleCppUtils.windows) srcDirs "testsuite" + + include "**/*.cpp" + exclude "precompiled.cpp" + exclude GradleCppUtils.windows ? "tier0/platform_linux.cpp" : "tier0/platform_win32.cpp" + } + + source { + srcDirs "hookers" + include "**/*.cpp" + exclude "6132_hooker.cpp", "hooker.cpp", "main.cpp", "main_swds.cpp" + if (!GradleCppUtils.windows) exclude "rehlds_debug.cpp" + } + } + } + + static void rehlds_pch(def h) { + h.rehlds_pch(CppSourceSet) { + source { + srcDirs "rehlds" + include "precompiled.cpp" + } + } + } + + static void rehlds_hooker_src(def h) { + h.rehlds_hooker_src(CppSourceSet) { + source { + srcDirs "hookers" + include "6132_hooker.cpp", "hooker.cpp" + } + } + } + + static void rehlds_hooker_main_src(def h) { + h.rehlds_hooker_main_src(CppSourceSet) { + source { + srcDirs "hookers" + include "main.cpp" + } + } + } + + static void rehlds_swds_main_src(def h) { + h.rehlds_swds_main_src(CppSourceSet) { + source { + srcDirs "hookers" + include "main_swds.cpp" + } + } + } + + static void rehlds_tests_src(def h) { + h.rehlds_tests_src(CppSourceSet) { + source { + srcDir "unittests" + include "**/*.cpp" + } + } + } +} + + +model { + buildTypes { + debug + release + } + + platforms { + x86 { + architecture "x86" + } + } + + toolChains { + visualCpp(VisualCpp) { + } + icc(Icc) { + } + } + + flavors { + rehldsNofixes + rehldsFixes + } + + components { + rehlds_hooker_engine(NativeLibrarySpec) { + targetPlatform 'x86' + baseName 'FileSystem_Stdio' + + sources { + RehldsSrc.rehlds_pch(it) + RehldsSrc.rehlds_src(it) + RehldsSrc.rehlds_hooker_src(it) + RehldsSrc.rehlds_hooker_main_src(it) + } + + binaries.all { NativeBinarySpec b -> project.setupToolchain(b) } + } + + rehlds_swds_engine(NativeLibrarySpec) { + targetPlatform 'x86' + baseName GradleCppUtils.windows ? 'swds' : 'engine_i486' + + sources { + RehldsSrc.rehlds_pch(it) + RehldsSrc.rehlds_src(it) + RehldsSrc.rehlds_swds_main_src(it) + } + + binaries.all { NativeBinarySpec b -> project.setupToolchain(b) } + } + + rehlds_hooker_engine_tests(NativeExecutableSpec) { + targetPlatform 'x86' + sources { + RehldsSrc.rehlds_pch(it) + RehldsSrc.rehlds_src(it) + RehldsSrc.rehlds_tests_src(it) + } + + binaries.all { NativeBinarySpec b -> project.setupToolchain(b) } + } + + rehlds_swds_engine_tests(NativeExecutableSpec) { + targetPlatform 'x86' + sources { + RehldsSrc.rehlds_pch(it) + RehldsSrc.rehlds_src(it) + RehldsSrc.rehlds_tests_src(it) + } + + binaries.all { NativeBinarySpec b -> project.setupToolchain(b) } + } + } +} + +task buildRelease { + dependsOn binaries.withType(SharedLibraryBinarySpec).matching { SharedLibraryBinarySpec blib -> + blib.buildable && blib.buildType.name == 'release' + } +} + +task prepareDevEnvTests { + def rehldsTests = new File(project.projectDir, '_dev/testDemos') + + inputs.files configurations.rehlds_tests.files + outputs.dir rehldsTests + + doLast { + rehldsTests.mkdirs() + configurations.rehlds_tests.files.each { File f -> + def t = zipTree(f) + copy { + into new File(rehldsTests, FilenameUtils.getBaseName(f.absolutePath)) + from t + } + } + } +} + +task prepareDevEnvEngine << { + ['_dev/rehlds', '_dev/rehlds_swds'].each { engineDir -> + def rehldsImage = new File(project.projectDir, engineDir) + rehldsImage.mkdirs() + def demoRunner = new RehldsDemoRunner(project.configurations.rehlds_playtest_image.getFiles(), rehldsImage, null) + demoRunner.prepareEngine() + } +} + +task prepareDevEnv { + dependsOn prepareDevEnvEngine, prepareDevEnvTests +} + +task clean << { + project.file('version/appversion.h').delete() +} + +task generateAppVersion { + RehldsVersionInfo verInfo = (RehldsVersionInfo) rootProject.rehldsVersionInfo + def tplFile = project.file('version/appversion.vm') + def renderedFile = project.file('version/appversion.h') + + inputs.file tplFile + inputs.file project.file('gradle.properties') + outputs.file renderedFile + inputs.property('version', verInfo.asMavenVersion()) + inputs.property('lastCommitDate', verInfo.lastCommitDate.toString()) + + doLast { + def templateCtx = [ + verInfo : verInfo + ] + + def content = VelocityUtils.renderTemplate(tplFile, templateCtx) + renderedFile.delete() + renderedFile.write(content, 'utf-8') + } +} diff --git a/rehlds/common/IGameServerData.h b/rehlds/common/IGameServerData.h new file mode 100644 index 0000000..2be739b --- /dev/null +++ b/rehlds/common/IGameServerData.h @@ -0,0 +1,13 @@ +#pragma once + +#include "maintypes.h" +#include "interface.h" + +class IGameServerData : public IBaseInterface { +public: + virtual ~IGameServerData() { }; + + virtual void WriteDataRequest(const void *buffer, int bufferSize) = 0; + + virtual int ReadDataResponse(void *data, int len) = 0; +}; diff --git a/rehlds/common/Sequence.h b/rehlds/common/Sequence.h new file mode 100644 index 0000000..dff3ef5 --- /dev/null +++ b/rehlds/common/Sequence.h @@ -0,0 +1,201 @@ +//--------------------------------------------------------------------------- +// +// S c r i p t e d S e q u e n c e s +// +//--------------------------------------------------------------------------- +#ifndef _INCLUDE_SEQUENCE_H_ +#define _INCLUDE_SEQUENCE_H_ + + +#ifndef _DEF_BYTE_ +typedef unsigned char byte; +#endif + +//--------------------------------------------------------------------------- +// client_textmessage_t +//--------------------------------------------------------------------------- +typedef struct client_textmessage_s +{ + int effect; + byte r1, g1, b1, a1; // 2 colors for effects + byte r2, g2, b2, a2; + float x; + float y; + float fadein; + float fadeout; + float holdtime; + float fxtime; + const char *pName; + const char *pMessage; +} client_textmessage_t; + + +//-------------------------------------------------------------------------- +// sequenceDefaultBits_e +// +// Enumerated list of possible modifiers for a command. This enumeration +// is used in a bitarray controlling what modifiers are specified for a command. +//--------------------------------------------------------------------------- +enum sequenceModifierBits +{ + SEQUENCE_MODIFIER_EFFECT_BIT = (1 << 1), + SEQUENCE_MODIFIER_POSITION_BIT = (1 << 2), + SEQUENCE_MODIFIER_COLOR_BIT = (1 << 3), + SEQUENCE_MODIFIER_COLOR2_BIT = (1 << 4), + SEQUENCE_MODIFIER_FADEIN_BIT = (1 << 5), + SEQUENCE_MODIFIER_FADEOUT_BIT = (1 << 6), + SEQUENCE_MODIFIER_HOLDTIME_BIT = (1 << 7), + SEQUENCE_MODIFIER_FXTIME_BIT = (1 << 8), + SEQUENCE_MODIFIER_SPEAKER_BIT = (1 << 9), + SEQUENCE_MODIFIER_LISTENER_BIT = (1 << 10), + SEQUENCE_MODIFIER_TEXTCHANNEL_BIT = (1 << 11), +}; +typedef enum sequenceModifierBits sequenceModifierBits_e ; + + +//--------------------------------------------------------------------------- +// sequenceCommandEnum_e +// +// Enumerated sequence command types. +//--------------------------------------------------------------------------- +enum sequenceCommandEnum_ +{ + SEQUENCE_COMMAND_ERROR = -1, + SEQUENCE_COMMAND_PAUSE = 0, + SEQUENCE_COMMAND_FIRETARGETS, + SEQUENCE_COMMAND_KILLTARGETS, + SEQUENCE_COMMAND_TEXT, + SEQUENCE_COMMAND_SOUND, + SEQUENCE_COMMAND_GOSUB, + SEQUENCE_COMMAND_SENTENCE, + SEQUENCE_COMMAND_REPEAT, + SEQUENCE_COMMAND_SETDEFAULTS, + SEQUENCE_COMMAND_MODIFIER, + SEQUENCE_COMMAND_POSTMODIFIER, + SEQUENCE_COMMAND_NOOP, + + SEQUENCE_MODIFIER_EFFECT, + SEQUENCE_MODIFIER_POSITION, + SEQUENCE_MODIFIER_COLOR, + SEQUENCE_MODIFIER_COLOR2, + SEQUENCE_MODIFIER_FADEIN, + SEQUENCE_MODIFIER_FADEOUT, + SEQUENCE_MODIFIER_HOLDTIME, + SEQUENCE_MODIFIER_FXTIME, + SEQUENCE_MODIFIER_SPEAKER, + SEQUENCE_MODIFIER_LISTENER, + SEQUENCE_MODIFIER_TEXTCHANNEL, +}; +typedef enum sequenceCommandEnum_ sequenceCommandEnum_e; + + +//--------------------------------------------------------------------------- +// sequenceCommandType_e +// +// Typeerated sequence command types. +//--------------------------------------------------------------------------- +enum sequenceCommandType_ +{ + SEQUENCE_TYPE_COMMAND, + SEQUENCE_TYPE_MODIFIER, +}; +typedef enum sequenceCommandType_ sequenceCommandType_e; + + +//--------------------------------------------------------------------------- +// sequenceCommandMapping_s +// +// A mapping of a command enumerated-value to its name. +//--------------------------------------------------------------------------- +typedef struct sequenceCommandMapping_ sequenceCommandMapping_s; +struct sequenceCommandMapping_ +{ + sequenceCommandEnum_e commandEnum; + const char* commandName; + sequenceCommandType_e commandType; +}; + + +//--------------------------------------------------------------------------- +// sequenceCommandLine_s +// +// Structure representing a single command (usually 1 line) from a +// .SEQ file entry. +//--------------------------------------------------------------------------- +typedef struct sequenceCommandLine_ sequenceCommandLine_s; +struct sequenceCommandLine_ +{ + int commandType; // Specifies the type of command + client_textmessage_t clientMessage; // Text HUD message struct + char* speakerName; // Targetname of speaking entity + char* listenerName; // Targetname of entity being spoken to + char* soundFileName; // Name of sound file to play + char* sentenceName; // Name of sentences.txt to play + char* fireTargetNames; // List of targetnames to fire + char* killTargetNames; // List of targetnames to remove + float delay; // Seconds 'till next command + int repeatCount; // If nonzero, reset execution pointer to top of block (N times, -1 = infinite) + int textChannel; // Display channel on which text message is sent + int modifierBitField; // Bit field to specify what clientmessage fields are valid + sequenceCommandLine_s* nextCommandLine; // Next command (linked list) +}; + + +//--------------------------------------------------------------------------- +// sequenceEntry_s +// +// Structure representing a single command (usually 1 line) from a +// .SEQ file entry. +//--------------------------------------------------------------------------- +typedef struct sequenceEntry_ sequenceEntry_s; +struct sequenceEntry_ +{ + char* fileName; // Name of sequence file without .SEQ extension + char* entryName; // Name of entry label in file + sequenceCommandLine_s* firstCommand; // Linked list of commands in entry + sequenceEntry_s* nextEntry; // Next loaded entry + qboolean isGlobal; // Is entry retained over level transitions? +}; + + + +//--------------------------------------------------------------------------- +// sentenceEntry_s +// Structure representing a single sentence of a group from a .SEQ +// file entry. Sentences are identical to entries in sentences.txt, but +// can be unique per level and are loaded/unloaded with the level. +//--------------------------------------------------------------------------- +typedef struct sentenceEntry_ sentenceEntry_s; +struct sentenceEntry_ +{ + char* data; // sentence data (ie "We have hostiles" ) + sentenceEntry_s* nextEntry; // Next loaded entry + qboolean isGlobal; // Is entry retained over level transitions? + unsigned int index; // this entry's position in the file. +}; + +//-------------------------------------------------------------------------- +// sentenceGroupEntry_s +// Structure representing a group of sentences found in a .SEQ file. +// A sentence group is defined by all sentences with the same name, ignoring +// the number at the end of the sentence name. Groups enable a sentence +// to be picked at random across a group. +//-------------------------------------------------------------------------- +typedef struct sentenceGroupEntry_ sentenceGroupEntry_s; +struct sentenceGroupEntry_ +{ + char* groupName; // name of the group (ie CT_ALERT ) + unsigned int numSentences; // number of sentences in group + sentenceEntry_s* firstSentence; // head of linked list of sentences in group + sentenceGroupEntry_s* nextEntry; // next loaded group +}; + +//--------------------------------------------------------------------------- +// Function declarations +//--------------------------------------------------------------------------- +sequenceEntry_s* SequenceGet( const char* fileName, const char* entryName ); +void Sequence_ParseFile( const char* fileName, qboolean isGlobal ); +void Sequence_OnLevelLoad( const char* mapName ); +sentenceEntry_s* SequencePickSentence( const char *groupName, int pickMethod, int *picked ); + +#endif // _INCLUDE_SEQUENCE_H_ diff --git a/rehlds/common/SteamCommon.h b/rehlds/common/SteamCommon.h new file mode 100644 index 0000000..4d5eb40 --- /dev/null +++ b/rehlds/common/SteamCommon.h @@ -0,0 +1,703 @@ + +//========= Copyright Valve Corporation, All rights reserved. ============// +/* +** The copyright to the contents herein is the property of Valve Corporation. +** The contents may be used and/or copied only with the written permission of +** Valve, or in accordance with the terms and conditions stipulated in +** the agreement/contract under which the contents have been supplied. +** +******************************************************************************* +** +** Contents: +** +** Common types used in the Steam DLL interface. +** +** This file is distributed to Steam application developers. +** +** +** +*******************************************************************************/ + +#ifndef INCLUDED_STEAM_COMMON_STEAMCOMMON_H +#define INCLUDED_STEAM_COMMON_STEAMCOMMON_H + +#if defined(_MSC_VER) && (_MSC_VER > 1000) +#pragma once +#endif + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Applications should not define STEAM_EXPORTS. */ + +#if defined ( _WIN32 ) + +#ifdef STEAM_EXPORTS +#define STEAM_API __declspec(dllexport) +#else +#define STEAM_API __declspec(dllimport) +#endif + +#define STEAM_CALL __cdecl + +#else + +#define STEAM_API /* */ +#define STEAM_CALL /* */ + +#endif + +typedef void (STEAM_CALL *KeyValueIteratorCallback_t )(const char *Key, const char *Val, void *pvParam); + + +/****************************************************************************** +** +** Exported macros and constants +** +******************************************************************************/ + +/* DEPRECATED -- these are ignored now, all API access is granted on SteamStartup */ +#define STEAM_USING_FILESYSTEM (0x00000001) +#define STEAM_USING_LOGGING (0x00000002) +#define STEAM_USING_USERID (0x00000004) +#define STEAM_USING_ACCOUNT (0x00000008) +#define STEAM_USING_ALL (0x0000000f) +/* END DEPRECATED */ + +#define STEAM_MAX_PATH (255) +#define STEAM_QUESTION_MAXLEN (255) +#define STEAM_SALT_SIZE (8) +#define STEAM_PROGRESS_PERCENT_SCALE (0x00001000) + +/* These are maximum significant string lengths, excluding nul-terminator. */ +#define STEAM_CARD_NUMBER_SIZE (17) +#define STEAM_CARD_HOLDERNAME_SIZE (100) +#define STEAM_CARD_EXPYEAR_SIZE (4) +#define STEAM_CARD_EXPMONTH_SIZE (2) +#define STEAM_CARD_CVV2_SIZE (5) +#define STEAM_BILLING_ADDRESS1_SIZE (128) +#define STEAM_BILLING_ADDRESS2_SIZE (128) +#define STEAM_BILLING_CITY_SIZE (50) +#define STEAM_BILLING_ZIP_SIZE (16) +#define STEAM_BILLING_STATE_SIZE (32) +#define STEAM_BILLING_COUNTRY_SIZE (32) +#define STEAM_BILLING_PHONE_SIZE (20) +#define STEAM_BILLING_EMAIL_ADDRESS_SIZE (100) +#define STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE (20) +#define STEAM_PROOF_OF_PURCHASE_TOKEN_SIZE (200) +#define STEAM_EXTERNAL_ACCOUNTNAME_SIZE (100) +#define STEAM_EXTERNAL_ACCOUNTPASSWORD_SIZE (80) +#define STEAM_BILLING_CONFIRMATION_CODE_SIZE (22) +#define STEAM_BILLING_CARD_APPROVAL_CODE_SIZE (100) +#define STEAM_BILLING_TRANS_DATE_SIZE (9) // mm/dd/yy +#define STEAM_BILLING_TRANS_TIME_SIZE (9) // hh:mm:ss + +/****************************************************************************** +** +** Scalar type and enumerated type definitions. +** +******************************************************************************/ + + +typedef unsigned int SteamHandle_t; + +typedef void * SteamUserIDTicketValidationHandle_t; + +typedef unsigned int SteamCallHandle_t; + +#if defined(_MSC_VER) +typedef unsigned __int64 SteamUnsigned64_t; +#else +typedef unsigned long long SteamUnsigned64_t; +#endif + +typedef enum +{ + eSteamSeekMethodSet = 0, + eSteamSeekMethodCur = 1, + eSteamSeekMethodEnd = 2 +} ESteamSeekMethod; + +typedef enum +{ + eSteamBufferMethodFBF = 0, + eSteamBufferMethodNBF = 1 +} ESteamBufferMethod; + +typedef enum +{ + eSteamErrorNone = 0, + eSteamErrorUnknown = 1, + eSteamErrorLibraryNotInitialized = 2, + eSteamErrorLibraryAlreadyInitialized = 3, + eSteamErrorConfig = 4, + eSteamErrorContentServerConnect = 5, + eSteamErrorBadHandle = 6, + eSteamErrorHandlesExhausted = 7, + eSteamErrorBadArg = 8, + eSteamErrorNotFound = 9, + eSteamErrorRead = 10, + eSteamErrorEOF = 11, + eSteamErrorSeek = 12, + eSteamErrorCannotWriteNonUserConfigFile = 13, + eSteamErrorCacheOpen = 14, + eSteamErrorCacheRead = 15, + eSteamErrorCacheCorrupted = 16, + eSteamErrorCacheWrite = 17, + eSteamErrorCacheSession = 18, + eSteamErrorCacheInternal = 19, + eSteamErrorCacheBadApp = 20, + eSteamErrorCacheVersion = 21, + eSteamErrorCacheBadFingerPrint = 22, + + eSteamErrorNotFinishedProcessing = 23, + eSteamErrorNothingToDo = 24, + eSteamErrorCorruptEncryptedUserIDTicket = 25, + eSteamErrorSocketLibraryNotInitialized = 26, + eSteamErrorFailedToConnectToUserIDTicketValidationServer = 27, + eSteamErrorBadProtocolVersion = 28, + eSteamErrorReplayedUserIDTicketFromClient = 29, + eSteamErrorReceiveResultBufferTooSmall = 30, + eSteamErrorSendFailed = 31, + eSteamErrorReceiveFailed = 32, + eSteamErrorReplayedReplyFromUserIDTicketValidationServer = 33, + eSteamErrorBadSignatureFromUserIDTicketValidationServer = 34, + eSteamErrorValidationStalledSoAborted = 35, + eSteamErrorInvalidUserIDTicket = 36, + eSteamErrorClientLoginRateTooHigh = 37, + eSteamErrorClientWasNeverValidated = 38, + eSteamErrorInternalSendBufferTooSmall = 39, + eSteamErrorInternalReceiveBufferTooSmall = 40, + eSteamErrorUserTicketExpired = 41, + eSteamErrorCDKeyAlreadyInUseOnAnotherClient = 42, + + eSteamErrorNotLoggedIn = 101, + eSteamErrorAlreadyExists = 102, + eSteamErrorAlreadySubscribed = 103, + eSteamErrorNotSubscribed = 104, + eSteamErrorAccessDenied = 105, + eSteamErrorFailedToCreateCacheFile = 106, + eSteamErrorCallStalledSoAborted = 107, + eSteamErrorEngineNotRunning = 108, + eSteamErrorEngineConnectionLost = 109, + eSteamErrorLoginFailed = 110, + eSteamErrorAccountPending = 111, + eSteamErrorCacheWasMissingRetry = 112, + eSteamErrorLocalTimeIncorrect = 113, + eSteamErrorCacheNeedsDecryption = 114, + eSteamErrorAccountDisabled = 115, + eSteamErrorCacheNeedsRepair = 116, + eSteamErrorRebootRequired = 117, + + eSteamErrorNetwork = 200, + eSteamErrorOffline = 201 + + +} ESteamError; + + +typedef enum +{ + eNoDetailedErrorAvailable, + eStandardCerrno, + eWin32LastError, + eWinSockLastError, + eDetailedPlatformErrorCount +} EDetailedPlatformErrorType; + +typedef enum /* Filter elements returned by SteamFind{First,Next} */ +{ + eSteamFindLocalOnly, /* limit search to local filesystem */ + eSteamFindRemoteOnly, /* limit search to remote repository */ + eSteamFindAll /* do not limit search (duplicates allowed) */ +} ESteamFindFilter; + + +/****************************************************************************** +** +** Exported structure and complex type definitions. +** +******************************************************************************/ + + +typedef struct +{ + ESteamError eSteamError; + EDetailedPlatformErrorType eDetailedErrorType; + int nDetailedErrorCode; + char szDesc[STEAM_MAX_PATH]; +} TSteamError; + + + +typedef struct +{ + int bIsDir; /* If non-zero, element is a directory; if zero, element is a file */ + unsigned int uSizeOrCount; /* If element is a file, this contains size of file in bytes */ + int bIsLocal; /* If non-zero, reported item is a standalone element on local filesystem */ + char cszName[STEAM_MAX_PATH]; /* Base element name (no path) */ + long lLastAccessTime; /* Seconds since 1/1/1970 (like time_t) when element was last accessed */ + long lLastModificationTime; /* Seconds since 1/1/1970 (like time_t) when element was last modified */ + long lCreationTime; /* Seconds since 1/1/1970 (like time_t) when element was created */ +} TSteamElemInfo; + + +typedef struct +{ + unsigned int uNumSubscriptions; + unsigned int uMaxNameChars; + unsigned int uMaxApps; + +} TSteamSubscriptionStats; + + +typedef struct +{ + unsigned int uNumApps; + unsigned int uMaxNameChars; + unsigned int uMaxInstallDirNameChars; + unsigned int uMaxVersionLabelChars; + unsigned int uMaxLaunchOptions; + unsigned int uMaxLaunchOptionDescChars; + unsigned int uMaxLaunchOptionCmdLineChars; + unsigned int uMaxNumIcons; + unsigned int uMaxIconSize; + unsigned int uMaxDependencies; + +} TSteamAppStats; + +typedef struct +{ + char *szLabel; + unsigned int uMaxLabelChars; + unsigned int uVersionId; + int bIsNotAvailable; +} TSteamAppVersion; + +typedef struct +{ + char *szDesc; + unsigned int uMaxDescChars; + char *szCmdLine; + unsigned int uMaxCmdLineChars; + unsigned int uIndex; + unsigned int uIconIndex; + int bNoDesktopShortcut; + int bNoStartMenuShortcut; + int bIsLongRunningUnattended; + +} TSteamAppLaunchOption; + + +typedef struct +{ + char *szName; + unsigned int uMaxNameChars; + char *szLatestVersionLabel; + unsigned int uMaxLatestVersionLabelChars; + char *szCurrentVersionLabel; + unsigned int uMaxCurrentVersionLabelChars; + char *szInstallDirName; + unsigned int uMaxInstallDirNameChars; + unsigned int uId; + unsigned int uLatestVersionId; + unsigned int uCurrentVersionId; + unsigned int uMinCacheFileSizeMB; + unsigned int uMaxCacheFileSizeMB; + unsigned int uNumLaunchOptions; + unsigned int uNumIcons; + unsigned int uNumVersions; + unsigned int uNumDependencies; + +} TSteamApp; + +typedef enum +{ + eNoCost = 0, + eBillOnceOnly = 1, + eBillMonthly = 2, + eProofOfPrepurchaseOnly = 3, + eGuestPass = 4, + eHardwarePromo = 5, + eNumBillingTypes, +} EBillingType; + +typedef struct +{ + char *szName; + unsigned int uMaxNameChars; + unsigned int *puAppIds; + unsigned int uMaxAppIds; + unsigned int uId; + unsigned int uNumApps; + EBillingType eBillingType; + unsigned int uCostInCents; + unsigned int uNumDiscounts; + int bIsPreorder; + int bRequiresShippingAddress; + unsigned int uDomesticShippingCostInCents; + unsigned int uInternationalShippingCostInCents; + bool bIsCyberCafeSubscription; + unsigned int uGameCode; + char szGameCodeDesc[STEAM_MAX_PATH]; + bool bIsDisabled; + bool bRequiresCD; + unsigned int uTerritoryCode; + bool bIsSteam3Subscription; + +} TSteamSubscription; + +typedef struct +{ + char szName[STEAM_MAX_PATH]; + unsigned int uDiscountInCents; + unsigned int uNumQualifiers; + +} TSteamSubscriptionDiscount; + +typedef struct +{ + char szName[STEAM_MAX_PATH]; + unsigned int uRequiredSubscription; + int bIsDisqualifier; + +} TSteamDiscountQualifier; + +typedef struct TSteamProgress +{ + int bValid; /* non-zero if call provides progress info */ + unsigned int uPercentDone; /* 0 to 100 * STEAM_PROGRESS_PERCENT_SCALE if bValid */ + char szProgress[STEAM_MAX_PATH]; /* additional progress info */ +} TSteamProgress; + +typedef enum +{ + eSteamNotifyTicketsWillExpire, + eSteamNotifyAccountInfoChanged, + eSteamNotifyContentDescriptionChanged, + eSteamNotifyPleaseShutdown, + eSteamNotifyNewContentServer, + eSteamNotifySubscriptionStatusChanged, + eSteamNotifyContentServerConnectionLost, + eSteamNotifyCacheLoadingCompleted, + eSteamNotifyCacheNeedsDecryption, + eSteamNotifyCacheNeedsRepair +} ESteamNotificationCallbackEvent; + + +typedef void(*SteamNotificationCallback_t)(ESteamNotificationCallbackEvent eEvent, unsigned int nData); + + +typedef char SteamPersonalQuestion_t[ STEAM_QUESTION_MAXLEN + 1 ]; + +typedef struct +{ + unsigned char uchSalt[STEAM_SALT_SIZE]; +} SteamSalt_t; + +typedef enum +{ + eVisa = 1, + eMaster = 2, + eAmericanExpress = 3, + eDiscover = 4, + eDinnersClub = 5, + eJCB = 6 +} ESteamPaymentCardType; + +typedef struct +{ + ESteamPaymentCardType eCardType; + char szCardNumber[ STEAM_CARD_NUMBER_SIZE +1 ]; + char szCardHolderName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szCardExpYear[ STEAM_CARD_EXPYEAR_SIZE + 1 ]; + char szCardExpMonth[ STEAM_CARD_EXPMONTH_SIZE+ 1 ]; + char szCardCVV2[ STEAM_CARD_CVV2_SIZE + 1 ]; + char szBillingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szBillingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szBillingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szBillingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szBillingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szBillingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + char szBillingPhone[ STEAM_BILLING_PHONE_SIZE + 1 ]; + char szBillingEmailAddress[ STEAM_BILLING_EMAIL_ADDRESS_SIZE + 1 ]; + unsigned int uExpectedCostInCents; + unsigned int uExpectedTaxInCents; + /* If the TSteamSubscription says that shipping info is required, */ + /* then the following fields must be filled out. */ + /* If szShippingName is empty, then assumes so are the rest. */ + char szShippingName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szShippingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szShippingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szShippingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szShippingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szShippingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szShippingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + char szShippingPhone[ STEAM_BILLING_PHONE_SIZE + 1 ]; + unsigned int uExpectedShippingCostInCents; + +} TSteamPaymentCardInfo; + +typedef struct +{ + char szTypeOfProofOfPurchase[ STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE + 1 ]; + + /* A ProofOfPurchase token is not necessarily a nul-terminated string; it may be binary data + (perhaps encrypted). Hence we need a length and an array of bytes. */ + unsigned int uLengthOfBinaryProofOfPurchaseToken; + char cBinaryProofOfPurchaseToken[ STEAM_PROOF_OF_PURCHASE_TOKEN_SIZE + 1 ]; +} TSteamPrepurchaseInfo; + +typedef struct +{ + char szAccountName[ STEAM_EXTERNAL_ACCOUNTNAME_SIZE + 1 ]; + char szPassword[ STEAM_EXTERNAL_ACCOUNTPASSWORD_SIZE + 1 ]; +} TSteamExternalBillingInfo; + +typedef enum +{ + ePaymentCardInfo = 1, + ePrepurchasedInfo = 2, + eAccountBillingInfo = 3, + eExternalBillingInfo = 4, /* indirect billing via ISP etc (not supported yet) */ + ePaymentCardReceipt = 5, + ePrepurchaseReceipt = 6, + eEmptyReceipt = 7 +} ESteamSubscriptionBillingInfoType; + +typedef struct +{ + ESteamSubscriptionBillingInfoType eBillingInfoType; + union { + TSteamPaymentCardInfo PaymentCardInfo; + TSteamPrepurchaseInfo PrepurchaseInfo; + TSteamExternalBillingInfo ExternalBillingInfo; + char bUseAccountBillingInfo; + }; + +} TSteamSubscriptionBillingInfo; + +typedef enum +{ + /* Subscribed */ + eSteamSubscriptionOK = 0, /* Subscribed */ + eSteamSubscriptionPending = 1, /* Awaiting transaction completion */ + eSteamSubscriptionPreorder = 2, /* Is currently a pre-order */ + eSteamSubscriptionPrepurchaseTransferred = 3, /* hop to this account */ + /* Unusbscribed */ + eSteamSubscriptionPrepurchaseInvalid = 4, /* Invalid cd-key */ + eSteamSubscriptionPrepurchaseRejected = 5, /* hopped out / banned / etc */ + eSteamSubscriptionPrepurchaseRevoked = 6, /* hop away from this account */ + eSteamSubscriptionPaymentCardDeclined = 7, /* CC txn declined */ + eSteamSubscriptionCancelledByUser = 8, /* Cancelled by client */ + eSteamSubscriptionCancelledByVendor = 9, /* Cancelled by us */ + eSteamSubscriptionPaymentCardUseLimit = 10, /* Card used too many times, potential fraud */ + eSteamSubscriptionPaymentCardAlert = 11, /* Got a "pick up card" or the like from bank */ + eSteamSubscriptionFailed = 12, /* Other Error in subscription data or transaction failed/lost */ + eSteamSubscriptionPaymentCardAVSFailure = 13, /* Card failed Address Verification check */ + eSteamSubscriptionPaymentCardInsufficientFunds = 14, /* Card failed due to insufficient funds */ + eSteamSubscriptionRestrictedCountry = 15 /* The subscription is not available in the user's country */ + +} ESteamSubscriptionStatus; + +typedef struct +{ + ESteamPaymentCardType eCardType; + char szCardLastFourDigits[ 4 + 1 ]; + char szCardHolderName[ STEAM_CARD_HOLDERNAME_SIZE + 1]; + char szBillingAddress1[ STEAM_BILLING_ADDRESS1_SIZE + 1 ]; + char szBillingAddress2[ STEAM_BILLING_ADDRESS2_SIZE + 1 ]; + char szBillingCity[ STEAM_BILLING_CITY_SIZE + 1 ]; + char szBillingZip[ STEAM_BILLING_ZIP_SIZE + 1 ]; + char szBillingState[ STEAM_BILLING_STATE_SIZE + 1 ]; + char szBillingCountry[ STEAM_BILLING_COUNTRY_SIZE + 1 ]; + + // The following are only available after the subscription leaves "pending" status + char szCardApprovalCode[ STEAM_BILLING_CARD_APPROVAL_CODE_SIZE + 1]; + char szTransDate[ STEAM_BILLING_TRANS_DATE_SIZE + 1]; /* mm/dd/yy */ + char szTransTime[ STEAM_BILLING_TRANS_TIME_SIZE + 1]; /* hh:mm:ss */ + unsigned int uPriceWithoutTax; + unsigned int uTaxAmount; + unsigned int uShippingCost; + +} TSteamPaymentCardReceiptInfo; + +typedef struct +{ + char szTypeOfProofOfPurchase[ STEAM_TYPE_OF_PROOF_OF_PURCHASE_SIZE + 1 ]; +} TSteamPrepurchaseReceiptInfo; + +typedef struct +{ + ESteamSubscriptionStatus eStatus; + ESteamSubscriptionStatus ePreviousStatus; + ESteamSubscriptionBillingInfoType eReceiptInfoType; + char szConfirmationCode[ STEAM_BILLING_CONFIRMATION_CODE_SIZE + 1]; + union { + TSteamPaymentCardReceiptInfo PaymentCardReceiptInfo; + TSteamPrepurchaseReceiptInfo PrepurchaseReceiptInfo; + }; + +} TSteamSubscriptionReceipt; + +typedef enum +{ + ePhysicalBytesReceivedThisSession = 1, + eAppReadyToLaunchStatus = 2, + eAppPreloadStatus = 3, + eAppEntireDepot = 4, + eCacheBytesPresent = 5 +} ESteamAppUpdateStatsQueryType; + +typedef struct +{ + SteamUnsigned64_t uBytesTotal; + SteamUnsigned64_t uBytesPresent; +} TSteamUpdateStats; + +typedef enum +{ + eSteamUserAdministrator = 0x00000001, /* May subscribe, unsubscribe, etc */ + eSteamUserDeveloper = 0x00000002, /* Steam or App developer */ + eSteamUserCyberCafe = 0x00000004 /* CyberCafe, school, etc -- UI should ask for password */ + /* before allowing logout, unsubscribe, etc */ +} ESteamUserTypeFlags; + +typedef enum +{ + eSteamAccountStatusDefault = 0x00000000, + eSteamAccountStatusEmailVerified = 0x00000001, + /* Note: Mask value 0x2 is reserved for future use. (Some, but not all, public accounts already have this set.) */ + eSteamAccountDisabled = 0x00000004 +} ESteamAccountStatusBitFields ; + + +typedef enum +{ + eSteamBootstrapperError = -1, + eSteamBootstrapperDontCheckForUpdate = 0, + eSteamBootstrapperCheckForUpdateAndRerun = 7 + +} ESteamBootStrapperClientAppResult; + +typedef enum +{ + eSteamOnline = 0, + eSteamOffline = 1, + eSteamNoAuthMode = 2, + eSteamBillingOffline = 3 +} eSteamOfflineStatus; + +typedef struct +{ + int eOfflineNow; + int eOfflineNextSession; +} TSteamOfflineStatus; + +typedef struct +{ + unsigned int uAppId; + int bIsSystemDefined; + char szMountPath[STEAM_MAX_PATH]; +} TSteamAppDependencyInfo; + +typedef enum +{ + eSteamOpenFileRegular = 0x0, + eSteamOpenFileIgnoreLocal = 0x1, + eSteamOpenFileChecksumReads = 0x2 +} ESteamOpenFileFlags; + +typedef enum +{ + eSteamValveCDKeyValidationServer = 0, + eSteamHalfLifeMasterServer = 1, + eSteamFriendsServer = 2, + eSteamCSERServer = 3, + eSteamHalfLife2MasterServer = 4, + eSteamRDKFMasterServer = 5, + eMaxServerTypes = 6 +} ESteamServerType; + +/****************************************************************************** +** +** More exported constants +** +******************************************************************************/ + + +#ifdef __cplusplus + +const SteamHandle_t STEAM_INVALID_HANDLE = 0; +const SteamCallHandle_t STEAM_INVALID_CALL_HANDLE = 0; +const SteamUserIDTicketValidationHandle_t STEAM_INACTIVE_USERIDTICKET_VALIDATION_HANDLE = 0; +const unsigned int STEAM_USE_LATEST_VERSION = 0xFFFFFFFF; + +#else + +#define STEAM_INVALID_HANDLE ((SteamHandle_t)(0)) +#define STEAM_INVALID_CALL_HANDLE ((SteamCallHandle_t)(0)) +#define STEAM_INACTIVE_USERIDTICKET_VALIDATION_HANDLE ((SteamUserIDTicketValidationHandle_t)(0)) +#define STEAM_USE_LATEST_VERSION (0xFFFFFFFFu); + +#endif + + +/****************************************************************************** +** Each Steam instance (licensed Steam Service Provider) has a unique SteamInstanceID_t. +** +** Each Steam instance as its own DB of users. +** Each user in the DB has a unique SteamLocalUserID_t (a serial number, with possible +** rare gaps in the sequence). +** +******************************************************************************/ + +typedef unsigned short SteamInstanceID_t; // MUST be 16 bits + + +#if defined ( _WIN32 ) +typedef unsigned __int64 SteamLocalUserID_t; // MUST be 64 bits +#else +typedef unsigned long long SteamLocalUserID_t; // MUST be 64 bits +#endif + +/****************************************************************************** +** +** Applications need to be able to authenticate Steam users from ANY instance. +** So a SteamIDTicket contains SteamGlobalUserID, which is a unique combination of +** instance and user id. +** +** SteamLocalUserID is an unsigned 64-bit integer. +** For platforms without 64-bit int support, we provide access via a union that splits it into +** high and low unsigned 32-bit ints. Such platforms will only need to compare LocalUserIDs +** for equivalence anyway - not perform arithmetic with them. +** +********************************************************************************/ +typedef struct +{ + unsigned int Low32bits; + unsigned int High32bits; +} TSteamSplitLocalUserID; + +typedef struct +{ + SteamInstanceID_t m_SteamInstanceID; + + union + { + SteamLocalUserID_t As64bits; + TSteamSplitLocalUserID Split; + } m_SteamLocalUserID; + +} TSteamGlobalUserID; + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/rehlds/common/beamdef.h b/rehlds/common/beamdef.h new file mode 100644 index 0000000..f493391 --- /dev/null +++ b/rehlds/common/beamdef.h @@ -0,0 +1,62 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( BEAMDEFH ) +#define BEAMDEFH +#ifdef _WIN32 +#pragma once +#endif + +#define FBEAM_STARTENTITY 0x00000001 +#define FBEAM_ENDENTITY 0x00000002 +#define FBEAM_FADEIN 0x00000004 +#define FBEAM_FADEOUT 0x00000008 +#define FBEAM_SINENOISE 0x00000010 +#define FBEAM_SOLID 0x00000020 +#define FBEAM_SHADEIN 0x00000040 +#define FBEAM_SHADEOUT 0x00000080 +#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? +#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? +#define FBEAM_ISACTIVE 0x40000000 +#define FBEAM_FOREVER 0x80000000 + +typedef struct beam_s BEAM; +struct beam_s +{ + BEAM *next; + int type; + int flags; + vec3_t source; + vec3_t target; + vec3_t delta; + float t; // 0 .. 1 over lifetime of beam + float freq; + float die; + float width; + float amplitude; + float r, g, b; + float brightness; + float speed; + float frameRate; + float frame; + int segments; + int startEntity; + int endEntity; + int modelIndex; + int frameCount; + struct model_s *pFollowModel; + struct particle_s *particles; +}; + +#endif diff --git a/rehlds/common/cl_entity.h b/rehlds/common/cl_entity.h new file mode 100644 index 0000000..b8fd373 --- /dev/null +++ b/rehlds/common/cl_entity.h @@ -0,0 +1,115 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// cl_entity.h +#if !defined( CL_ENTITYH ) +#define CL_ENTITYH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct efrag_s +{ + struct mleaf_s *leaf; + struct efrag_s *leafnext; + struct cl_entity_s *entity; + struct efrag_s *entnext; +} efrag_t; + +typedef struct +{ + byte mouthopen; // 0 = mouth closed, 255 = mouth agape + byte sndcount; // counter for running average + int sndavg; // running average +} mouth_t; + +typedef struct +{ + float prevanimtime; + float sequencetime; + byte prevseqblending[2]; + vec3_t prevorigin; + vec3_t prevangles; + + int prevsequence; + float prevframe; + + byte prevcontroller[4]; + byte prevblending[2]; +} latchedvars_t; + +typedef struct +{ + // Time stamp for this movement + float animtime; + + vec3_t origin; + vec3_t angles; +} position_history_t; + +typedef struct cl_entity_s cl_entity_t; + +#define HISTORY_MAX 64 // Must be power of 2 +#define HISTORY_MASK ( HISTORY_MAX - 1 ) + + +#if !defined( ENTITY_STATEH ) +#include "entity_state.h" +#endif + +#if !defined( PROGS_H ) +#include "progs.h" +#endif + +struct cl_entity_s +{ + int index; // Index into cl_entities ( should match actual slot, but not necessarily ) + + qboolean player; // True if this entity is a "player" + + entity_state_t baseline; // The original state from which to delta during an uncompressed message + entity_state_t prevstate; // The state information from the penultimate message received from the server + entity_state_t curstate; // The state information from the last message received from server + + int current_position; // Last received history update index + position_history_t ph[ HISTORY_MAX ]; // History of position and angle updates for this player + + mouth_t mouth; // For synchronizing mouth movements. + + latchedvars_t latched; // Variables used by studio model rendering routines + + // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. + // + float lastmove; + + // Actual render position and angles + vec3_t origin; + vec3_t angles; + + // Attachment points + vec3_t attachment[4]; + + // Other entity local information + int trivial_accept; + + struct model_s *model; // cl.model_precache[ curstate.modelindes ]; all visible entities have a model + struct efrag_s *efrag; // linked list of efrags + struct mnode_s *topnode; // for bmodels, first world node that splits bmodel, or NULL if not split + + float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? + int visframe; // last frame this entity was found in an active leaf + colorVec cvFloorColor; +}; + +#endif // !CL_ENTITYH diff --git a/rehlds/common/com_model.h b/rehlds/common/com_model.h new file mode 100644 index 0000000..6ccee32 --- /dev/null +++ b/rehlds/common/com_model.h @@ -0,0 +1,340 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// com_model.h +#pragma once + +#define STUDIO_RENDER 1 +#define STUDIO_EVENTS 2 + +//#define MAX_MODEL_NAME 64 +//#define MAX_MAP_HULLS 4 +//#define MIPLEVELS 4 +//#define NUM_AMBIENTS 4 // automatic ambient sounds +//#define MAXLIGHTMAPS 4 +#define PLANE_ANYZ 5 + +#define ALIAS_Z_CLIP_PLANE 5 + +// flags in finalvert_t.flags +#define ALIAS_LEFT_CLIP 0x0001 +#define ALIAS_TOP_CLIP 0x0002 +#define ALIAS_RIGHT_CLIP 0x0004 +#define ALIAS_BOTTOM_CLIP 0x0008 +#define ALIAS_Z_CLIP 0x0010 +#define ALIAS_ONSEAM 0x0020 +#define ALIAS_XY_CLIP_MASK 0x000F + +#define ZISCALE ((float)0x8000) + +#define CACHE_SIZE 32 // used to align key data structures + +//typedef enum +//{ +// mod_brush, +// mod_sprite, +// mod_alias, +// mod_studio +//} modtype_t; + +// must match definition in modelgen.h +//#ifndef SYNCTYPE_T +//#define SYNCTYPE_T +// +//typedef enum +//{ +// ST_SYNC=0, +// ST_RAND +//} synctype_t; +// +//#endif + +//typedef struct +//{ +// float mins[3], maxs[3]; +// float origin[3]; +// int headnode[MAX_MAP_HULLS]; +// int visleafs; // not including the solid leaf 0 +// int firstface, numfaces; +//} dmodel_t; + +// plane_t structure +//typedef struct mplane_s +//{ +// vec3_t normal; // surface normal +// float dist; // closest appoach to origin +// byte type; // for texture axis selection and fast side tests +// byte signbits; // signx + signy<<1 + signz<<1 +// byte pad[2]; +//} mplane_t; + +//typedef struct +//{ +// vec3_t position; +//} mvertex_t; + +//typedef struct +//{ +// unsigned short v[2]; +// unsigned int cachededgeoffset; +//} medge_t; + +//typedef struct texture_s +//{ +// char name[16]; +// unsigned width, height; +// int anim_total; // total tenths in sequence ( 0 = no) +// int anim_min, anim_max; // time for this frame min <=time< max +// struct texture_s *anim_next; // in the animation sequence +// struct texture_s *alternate_anims; // bmodels in frame 1 use these +// unsigned offsets[MIPLEVELS]; // four mip maps stored +// unsigned paloffset; +//} texture_t; + +//typedef struct +//{ +// float vecs[2][4]; // [s/t] unit vectors in world space. +// // [i][3] is the s/t offset relative to the origin. +// // s or t = dot(3Dpoint,vecs[i])+vecs[i][3] +// float mipadjust; // ?? mipmap limits for very small surfaces +// texture_t *texture; +// int flags; // sky or slime, no lightmap or 256 subdivision +//} mtexinfo_t; + +//typedef struct mnode_s +//{ +// // common with leaf +// int contents; // 0, to differentiate from leafs +// int visframe; // node needs to be traversed if current +// +// short minmaxs[6]; // for bounding box culling +// +// struct mnode_s *parent; +// +// // node specific +// mplane_t *plane; +// struct mnode_s *children[2]; +// +// unsigned short firstsurface; +// unsigned short numsurfaces; +//} mnode_t; + +//typedef struct msurface_s msurface_t; +//typedef struct decal_s decal_t; + +// JAY: Compress this as much as possible +//struct decal_s +//{ +// decal_t *pnext; // linked list for each surface +// msurface_t *psurface; // Surface id for persistence / unlinking +// short dx; // Offsets into surface texture (in texture coordinates, so we don't need floats) +// short dy; +// short texture; // Decal texture +// byte scale; // Pixel scale +// byte flags; // Decal flags +// +// short entityIndex; // Entity this is attached to +//}; + +//typedef struct mleaf_s +//{ +// // common with node +// int contents; // wil be a negative contents number +// int visframe; // node needs to be traversed if current +// +// short minmaxs[6]; // for bounding box culling +// +// struct mnode_s *parent; +// +// // leaf specific +// byte *compressed_vis; +// struct efrag_s *efrags; +// +// msurface_t **firstmarksurface; +// int nummarksurfaces; +// int key; // BSP sequence number for leaf's contents +// byte ambient_sound_level[NUM_AMBIENTS]; +//} mleaf_t; + +//struct msurface_s +//{ +// int visframe; // should be drawn when node is crossed +// +// int dlightframe; // last frame the surface was checked by an animated light +// int dlightbits; // dynamically generated. Indicates if the surface illumination +// // is modified by an animated light. +// +// mplane_t *plane; // pointer to shared plane +// int flags; // see SURF_ #defines +// +// int firstedge; // look up in model->surfedges[], negative numbers +// int numedges; // are backwards edges +// +// // surface generation data +// struct surfcache_s *cachespots[MIPLEVELS]; +// +// short texturemins[2]; // smallest s/t position on the surface. +// short extents[2]; // ?? s/t texture size, 1..256 for all non-sky surfaces +// +// mtexinfo_t *texinfo; +// +// // lighting info +// byte styles[MAXLIGHTMAPS]; // index into d_lightstylevalue[] for animated lights +// // no one surface can be effected by more than 4 +// // animated lights. +// color24 *samples; +// +// decal_t *pdecals; +//}; + +//typedef struct +//{ +// int planenum; +// short children[2]; // negative numbers are contents +//} dclipnode_t; + +//typedef struct hull_s +//{ +// dclipnode_t *clipnodes; +// mplane_t *planes; +// int firstclipnode; +// int lastclipnode; +// vec3_t clip_mins; +// vec3_t clip_maxs; +//} hull_t; + +typedef struct cache_user_s +{ + void *data; +} cache_user_t; + +//typedef struct model_s +//{ +// char name[ MAX_MODEL_NAME ]; +// qboolean needload; // bmodels and sprites don't cache normally +// +// modtype_t type; +// int numframes; +// synctype_t synctype; +// +// int flags; +// +// // +// // volume occupied by the model +// // +// vec3_t mins, maxs; +// float radius; +// +// // +// // brush model +// // +// int firstmodelsurface, nummodelsurfaces; +// +// int numsubmodels; +// dmodel_t *submodels; +// +// int numplanes; +// mplane_t *planes; +// +// int numleafs; // number of visible leafs, not counting 0 +// struct mleaf_s *leafs; +// +// int numvertexes; +// mvertex_t *vertexes; +// +// int numedges; +// medge_t *edges; +// +// int numnodes; +// mnode_t *nodes; +// +// int numtexinfo; +// mtexinfo_t *texinfo; +// +// int numsurfaces; +// msurface_t *surfaces; +// +// int numsurfedges; +// int *surfedges; +// +// int numclipnodes; +// dclipnode_t *clipnodes; +// +// int nummarksurfaces; +// msurface_t **marksurfaces; +// +// hull_t hulls[MAX_MAP_HULLS]; +// +// int numtextures; +// texture_t **textures; +// +// byte *visdata; +// +// color24 *lightdata; +// +// char *entities; +// +// // +// // additional model data +// // +// cache_user_t cache; // only access through Mod_Extradata +// +//} model_t; + +//typedef vec_t vec4_t[4]; + +typedef struct alight_s +{ + int ambientlight; // clip at 128 + int shadelight; // clip at 192 - ambientlight + vec3_t color; + float *plightvec; +} alight_t; + +typedef struct auxvert_s +{ + float fv[3]; // viewspace x, y +} auxvert_t; + +#include "custom.h" + +//#define MAX_SCOREBOARDNAME 32 + +// Defined in client.h differently +//typedef struct player_info_s +//{ +// // User id on server +// int userid; +// +// // User info string +// char userinfo[ MAX_INFO_STRING ]; +// +// // Name +// char name[ MAX_SCOREBOARDNAME ]; +// +// // Spectator or not, unused +// int spectator; +// +// int ping; +// int packet_loss; +// +// // skin information +// char model[MAX_QPATH]; +// int topcolor; +// int bottomcolor; +// +// // last frame rendered +// int renderframe; +// +// // Gait frame estimation +// int gaitsequence; +// float gaitframe; +// float gaityaw; +// vec3_t prevgaitorigin; +// +// customization_t customdata; +//} player_info_t; diff --git a/rehlds/common/con_nprint.h b/rehlds/common/con_nprint.h new file mode 100644 index 0000000..849d1d4 --- /dev/null +++ b/rehlds/common/con_nprint.h @@ -0,0 +1,38 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( CON_NPRINTH ) +#define CON_NPRINTH +#ifdef _WIN32 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct con_nprint_s +{ + int index; // Row # + float time_to_live; // # of seconds before it dissappears + float color[ 3 ]; // RGB colors ( 0.0 -> 1.0 scale ) +} con_nprint_t; + +void Con_NPrintf( int idx, const char *fmt, ... ); +void Con_NXPrintf( struct con_nprint_s *info, const char *fmt, ... ); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rehlds/common/const.h b/rehlds/common/const.h new file mode 100644 index 0000000..e8ba7c0 --- /dev/null +++ b/rehlds/common/const.h @@ -0,0 +1,791 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef CONST_H +#define CONST_H +#ifdef _WIN32 +#pragma once +#endif + +// +// Constants shared by the engine and dlls +// This header file included by engine files and DLL files. +// Most came from server.h + +// edict->flags +#define FL_FLY (1<<0) // Changes the SV_Movestep() behavior to not need to be on ground +#define FL_SWIM (1<<1) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water) +#define FL_CONVEYOR (1<<2) +#define FL_CLIENT (1<<3) +#define FL_INWATER (1<<4) +#define FL_MONSTER (1<<5) +#define FL_GODMODE (1<<6) +#define FL_NOTARGET (1<<7) +#define FL_SKIPLOCALHOST (1<<8) // Don't send entity to local host, it's predicting this entity itself +#define FL_ONGROUND (1<<9) // At rest / on the ground +#define FL_PARTIALGROUND (1<<10) // not all corners are valid +#define FL_WATERJUMP (1<<11) // player jumping out of water +#define FL_FROZEN (1<<12) // Player is frozen for 3rd person camera +#define FL_FAKECLIENT (1<<13) // JAC: fake client, simulated server side; don't send network messages to them +#define FL_DUCKING (1<<14) // Player flag -- Player is fully crouched +#define FL_FLOAT (1<<15) // Apply floating force to this entity when in water +#define FL_GRAPHED (1<<16) // worldgraph has this ent listed as something that blocks a connection + +// UNDONE: Do we need these? +#define FL_IMMUNE_WATER (1<<17) +#define FL_IMMUNE_SLIME (1<<18) +#define FL_IMMUNE_LAVA (1<<19) + +#define FL_PROXY (1<<20) // This is a spectator proxy +#define FL_ALWAYSTHINK (1<<21) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path) +#define FL_BASEVELOCITY (1<<22) // Base velocity has been applied this frame (used to convert base velocity into momentum) +#define FL_MONSTERCLIP (1<<23) // Only collide in with monsters who have FL_MONSTERCLIP set +#define FL_ONTRAIN (1<<24) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction. +#define FL_WORLDBRUSH (1<<25) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) +#define FL_SPECTATOR (1<<26) // This client is a spectator, don't run touch functions, etc. +#define FL_CUSTOMENTITY (1<<29) // This is a custom entity +#define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time +#define FL_DORMANT (1<<31) // Entity is dormant, no updates to client + + +// Engine edict->spawnflags +#define SF_NOTINDEATHMATCH 0x0800 // Do not spawn when deathmatch and loading entities from a file + + +// Goes into globalvars_t.trace_flags +#define FTRACE_SIMPLEBOX (1<<0) // Traceline with a simple box + + +// walkmove modes +#define WALKMOVE_NORMAL 0 // normal walkmove +#define WALKMOVE_WORLDONLY 1 // doesn't hit ANY entities, no matter what the solid type +#define WALKMOVE_CHECKONLY 2 // move, but don't touch triggers + +// edict->movetype values +#define MOVETYPE_NONE 0 // never moves +//#define MOVETYPE_ANGLENOCLIP 1 +//#define MOVETYPE_ANGLECLIP 2 +#define MOVETYPE_WALK 3 // Player only - moving on the ground +#define MOVETYPE_STEP 4 // gravity, special edge handling -- monsters use this +#define MOVETYPE_FLY 5 // No gravity, but still collides with stuff +#define MOVETYPE_TOSS 6 // gravity/collisions +#define MOVETYPE_PUSH 7 // no clip to world, push and crush +#define MOVETYPE_NOCLIP 8 // No gravity, no collisions, still do velocity/avelocity +#define MOVETYPE_FLYMISSILE 9 // extra size to monsters +#define MOVETYPE_BOUNCE 10 // Just like Toss, but reflect velocity when contacting surfaces +#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity +#define MOVETYPE_FOLLOW 12 // track movement of aiment +#define MOVETYPE_PUSHSTEP 13 // BSP model that needs physics/world collisions (uses nearest hull for world collision) + +// edict->solid values +// NOTE: Some movetypes will cause collisions independent of SOLID_NOT/SOLID_TRIGGER when the entity moves +// SOLID only effects OTHER entities colliding with this one when they move - UGH! +#define SOLID_NOT 0 // no interaction with other objects +#define SOLID_TRIGGER 1 // touch on edge, but not blocking +#define SOLID_BBOX 2 // touch on edge, block +#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground +#define SOLID_BSP 4 // bsp clip, touch on edge, block + +// edict->deadflag values +#define DEAD_NO 0 // alive +#define DEAD_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground +#define DEAD_DEAD 2 // dead. lying still. +#define DEAD_RESPAWNABLE 3 +#define DEAD_DISCARDBODY 4 + +#define DAMAGE_NO 0 +#define DAMAGE_YES 1 +#define DAMAGE_AIM 2 + +// entity effects +#define EF_BRIGHTFIELD 1 // swirling cloud of particles +#define EF_MUZZLEFLASH 2 // single frame ELIGHT on entity attachment 0 +#define EF_BRIGHTLIGHT 4 // DLIGHT centered at entity origin +#define EF_DIMLIGHT 8 // player flashlight +#define EF_INVLIGHT 16 // get lighting from ceiling +#define EF_NOINTERP 32 // don't interpolate the next frame +#define EF_LIGHT 64 // rocket flare glow sprite +#define EF_NODRAW 128 // don't draw entity +#define EF_NIGHTVISION 256 // player nightvision +#define EF_SNIPERLASER 512 // sniper laser effect +#define EF_FIBERCAMERA 1024// fiber camera + + +// entity flags +#define EFLAG_SLERP 1 // do studio interpolation of this entity + +// +// temp entity events +// +#define TE_BEAMPOINTS 0 // beam effect between two points +// coord coord coord (start position) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMENTPOINT 1 // beam effect between point and entity +// short (start entity) +// coord coord coord (end position) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_GUNSHOT 2 // particle effect plus ricochet sound +// coord coord coord (position) + +#define TE_EXPLOSION 3 // additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps +// coord coord coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (framerate) +// byte (flags) +// +// The Explosion effect has some flags to control performance/aesthetic features: +#define TE_EXPLFLAG_NONE 0 // all flags clear makes default Half-Life explosion +#define TE_EXPLFLAG_NOADDITIVE 1 // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite) +#define TE_EXPLFLAG_NODLIGHTS 2 // do not render dynamic lights +#define TE_EXPLFLAG_NOSOUND 4 // do not play client explosion sound +#define TE_EXPLFLAG_NOPARTICLES 8 // do not draw particles + + +#define TE_TAREXPLOSION 4 // Quake1 "tarbaby" explosion with sound +// coord coord coord (position) + +#define TE_SMOKE 5 // alphablend sprite, move vertically 30 pps +// coord coord coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (framerate) + +#define TE_TRACER 6 // tracer effect from point to point +// coord, coord, coord (start) +// coord, coord, coord (end) + +#define TE_LIGHTNING 7 // TE_BEAMPOINTS with simplified parameters +// coord, coord, coord (start) +// coord, coord, coord (end) +// byte (life in 0.1's) +// byte (width in 0.1's) +// byte (amplitude in 0.01's) +// short (sprite model index) + +#define TE_BEAMENTS 8 +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_SPARKS 9 // 8 random tracers with gravity, ricochet sprite +// coord coord coord (position) + +#define TE_LAVASPLASH 10 // Quake1 lava splash +// coord coord coord (position) + +#define TE_TELEPORT 11 // Quake1 teleport splash +// coord coord coord (position) + +#define TE_EXPLOSION2 12 // Quake1 colormaped (base palette) particle explosion with sound +// coord coord coord (position) +// byte (starting color) +// byte (num colors) + +#define TE_BSPDECAL 13 // Decal from the .BSP file +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// short (texture index of precached decal texture name) +// short (entity index) +// [optional - only included if previous short is non-zero (not the world)] short (index of model of above entity) + +#define TE_IMPLOSION 14 // tracers moving toward a point +// coord, coord, coord (position) +// byte (radius) +// byte (count) +// byte (life in 0.1's) + +#define TE_SPRITETRAIL 15 // line of moving glow sprites with gravity, fadeout, and collisions +// coord, coord, coord (start) +// coord, coord, coord (end) +// short (sprite index) +// byte (count) +// byte (life in 0.1's) +// byte (scale in 0.1's) +// byte (velocity along vector in 10's) +// byte (randomness of velocity in 10's) + +#define TE_BEAM 16 // obsolete + +#define TE_SPRITE 17 // additive sprite, plays 1 cycle +// coord, coord, coord (position) +// short (sprite index) +// byte (scale in 0.1's) +// byte (brightness) + +#define TE_BEAMSPRITE 18 // A beam with a sprite at the end +// coord, coord, coord (start position) +// coord, coord, coord (end position) +// short (beam sprite index) +// short (end sprite index) + +#define TE_BEAMTORUS 19 // screen aligned beam ring, expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMDISK 20 // disk that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMCYLINDER 21 // cylinder that expands to max radius over lifetime +// coord coord coord (center position) +// coord coord coord (axis and radius) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_BEAMFOLLOW 22 // create a line of decaying beam segments until entity stops moving +// short (entity:attachment to follow) +// short (sprite index) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte,byte,byte (color) +// byte (brightness) + +#define TE_GLOWSPRITE 23 +// coord, coord, coord (pos) short (model index) byte (scale / 10) + +#define TE_BEAMRING 24 // connect a beam ring to two entities +// short (start entity) +// short (end entity) +// short (sprite index) +// byte (starting frame) +// byte (frame rate in 0.1's) +// byte (life in 0.1's) +// byte (line width in 0.1's) +// byte (noise amplitude in 0.01's) +// byte,byte,byte (color) +// byte (brightness) +// byte (scroll speed in 0.1's) + +#define TE_STREAK_SPLASH 25 // oriented shower of tracers +// coord coord coord (start position) +// coord coord coord (direction vector) +// byte (color) +// short (count) +// short (base speed) +// short (ramdon velocity) + +#define TE_BEAMHOSE 26 // obsolete + +#define TE_DLIGHT 27 // dynamic light, effect world, minor entity effect +// coord, coord, coord (pos) +// byte (radius in 10's) +// byte byte byte (color) +// byte (brightness) +// byte (life in 10's) +// byte (decay rate in 10's) + +#define TE_ELIGHT 28 // point entity light, no world effect +// short (entity:attachment to follow) +// coord coord coord (initial position) +// coord (radius) +// byte byte byte (color) +// byte (life in 0.1's) +// coord (decay rate) + +#define TE_TEXTMESSAGE 29 +// short 1.2.13 x (-1 = center) +// short 1.2.13 y (-1 = center) +// byte Effect 0 = fade in/fade out + // 1 is flickery credits + // 2 is write out (training room) + +// 4 bytes r,g,b,a color1 (text color) +// 4 bytes r,g,b,a color2 (effect color) +// ushort 8.8 fadein time +// ushort 8.8 fadeout time +// ushort 8.8 hold time +// optional ushort 8.8 fxtime (time the highlight lags behing the leading text in effect 2) +// string text message (512 chars max sz string) +#define TE_LINE 30 +// coord, coord, coord startpos +// coord, coord, coord endpos +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_BOX 31 +// coord, coord, coord boxmins +// coord, coord, coord boxmaxs +// short life in 0.1 s +// 3 bytes r, g, b + +#define TE_KILLBEAM 99 // kill all beams attached to entity +// short (entity) + +#define TE_LARGEFUNNEL 100 +// coord coord coord (funnel position) +// short (sprite index) +// short (flags) + +#define TE_BLOODSTREAM 101 // particle spray +// coord coord coord (start position) +// coord coord coord (spray vector) +// byte (color) +// byte (speed) + +#define TE_SHOWLINE 102 // line of particles every 5 units, dies in 30 seconds +// coord coord coord (start position) +// coord coord coord (end position) + +#define TE_BLOOD 103 // particle spray +// coord coord coord (start position) +// coord coord coord (spray vector) +// byte (color) +// byte (speed) + +#define TE_DECAL 104 // Decal applied to a brush entity (not the world) +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) +// short (entity index) + +#define TE_FIZZ 105 // create alpha sprites inside of entity, float upwards +// short (entity) +// short (sprite index) +// byte (density) + +#define TE_MODEL 106 // create a moving model that bounces and makes a sound when it hits +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// angle (initial yaw) +// short (model index) +// byte (bounce sound type) +// byte (life in 0.1's) + +#define TE_EXPLODEMODEL 107 // spherical shower of models, picks from set +// coord, coord, coord (origin) +// coord (velocity) +// short (model index) +// short (count) +// byte (life in 0.1's) + +#define TE_BREAKMODEL 108 // box of models or sprites +// coord, coord, coord (position) +// coord, coord, coord (size) +// coord, coord, coord (velocity) +// byte (random velocity in 10's) +// short (sprite or model index) +// byte (count) +// byte (life in 0.1 secs) +// byte (flags) + +#define TE_GUNSHOTDECAL 109 // decal and ricochet sound +// coord, coord, coord (position) +// short (entity index???) +// byte (decal???) + +#define TE_SPRITE_SPRAY 110 // spay of alpha sprites +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (sprite index) +// byte (count) +// byte (speed) +// byte (noise) + +#define TE_ARMOR_RICOCHET 111 // quick spark sprite, client ricochet sound. +// coord, coord, coord (position) +// byte (scale in 0.1's) + +#define TE_PLAYERDECAL 112 // ??? +// byte (playerindex) +// coord, coord, coord (position) +// short (entity???) +// byte (decal number???) +// [optional] short (model index???) + +#define TE_BUBBLES 113 // create alpha sprites inside of box, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BUBBLETRAIL 114 // create alpha sprites along a line, float upwards +// coord, coord, coord (min start position) +// coord, coord, coord (max start position) +// coord (float height) +// short (model index) +// byte (count) +// coord (speed) + +#define TE_BLOODSPRITE 115 // spray of opaque sprite1's that fall, single sprite2 for 1..2 secs (this is a high-priority tent) +// coord, coord, coord (position) +// short (sprite1 index) +// short (sprite2 index) +// byte (color) +// byte (scale) + +#define TE_WORLDDECAL 116 // Decal applied to the world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name) + +#define TE_WORLDDECALHIGH 117 // Decal (with texture index > 256) applied to world brush +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) + +#define TE_DECALHIGH 118 // Same as TE_DECAL, but the texture index was greater than 256 +// coord, coord, coord (x,y,z), decal position (center of texture in world) +// byte (texture index of precached decal texture name - 256) +// short (entity index) + +#define TE_PROJECTILE 119 // Makes a projectile (like a nail) (this is a high-priority tent) +// coord, coord, coord (position) +// coord, coord, coord (velocity) +// short (modelindex) +// byte (life) +// byte (owner) projectile won't collide with owner (if owner == 0, projectile will hit any client). + +#define TE_SPRAY 120 // Throws a shower of sprites or models +// coord, coord, coord (position) +// coord, coord, coord (direction) +// short (modelindex) +// byte (count) +// byte (speed) +// byte (noise) +// byte (rendermode) + +#define TE_PLAYERSPRITES 121 // sprites emit from a player's bounding box (ONLY use for players!) +// byte (playernum) +// short (sprite modelindex) +// byte (count) +// byte (variance) (0 = no variance in size) (10 = 10% variance in size) + +#define TE_PARTICLEBURST 122 // very similar to lavasplash. +// coord (origin) +// short (radius) +// byte (particle color) +// byte (duration * 10) (will be randomized a bit) + +#define TE_FIREFIELD 123 // makes a field of fire. +// coord (origin) +// short (radius) (fire is made in a square around origin. -radius, -radius to radius, radius) +// short (modelindex) +// byte (count) +// byte (flags) +// byte (duration (in seconds) * 10) (will be randomized a bit) +// +// to keep network traffic low, this message has associated flags that fit into a byte: +#define TEFIRE_FLAG_ALLFLOAT 1 // all sprites will drift upwards as they animate +#define TEFIRE_FLAG_SOMEFLOAT 2 // some of the sprites will drift upwards. (50% chance) +#define TEFIRE_FLAG_LOOP 4 // if set, sprite plays at 15 fps, otherwise plays at whatever rate stretches the animation over the sprite's duration. +#define TEFIRE_FLAG_ALPHA 8 // if set, sprite is rendered alpha blended at 50% else, opaque +#define TEFIRE_FLAG_PLANAR 16 // if set, all fire sprites have same initial Z instead of randomly filling a cube. +#define TEFIRE_FLAG_ADDITIVE 32 // if set, sprite is rendered non-opaque with additive + +#define TE_PLAYERATTACHMENT 124 // attaches a TENT to a player (this is a high-priority tent) +// byte (entity index of player) +// coord (vertical offset) ( attachment origin.z = player origin.z + vertical offset ) +// short (model index) +// short (life * 10 ); + +#define TE_KILLPLAYERATTACHMENTS 125 // will expire all TENTS attached to a player. +// byte (entity index of player) + +#define TE_MULTIGUNSHOT 126 // much more compact shotgun message +// This message is used to make a client approximate a 'spray' of gunfire. +// Any weapon that fires more than one bullet per frame and fires in a bit of a spread is +// a good candidate for MULTIGUNSHOT use. (shotguns) +// +// NOTE: This effect makes the client do traces for each bullet, these client traces ignore +// entities that have studio models.Traces are 4096 long. +// +// coord (origin) +// coord (origin) +// coord (origin) +// coord (direction) +// coord (direction) +// coord (direction) +// coord (x noise * 100) +// coord (y noise * 100) +// byte (count) +// byte (bullethole decal texture index) + +#define TE_USERTRACER 127 // larger message than the standard tracer, but allows some customization. +// coord (origin) +// coord (origin) +// coord (origin) +// coord (velocity) +// coord (velocity) +// coord (velocity) +// byte ( life * 10 ) +// byte ( color ) this is an index into an array of color vectors in the engine. (0 - ) +// byte ( length * 10 ) + + + +#define MSG_BROADCAST 0 // unreliable to all +#define MSG_ONE 1 // reliable to one (msg_entity) +#define MSG_ALL 2 // reliable to all +#define MSG_INIT 3 // write to the init string +#define MSG_PVS 4 // Ents in PVS of org +#define MSG_PAS 5 // Ents in PAS of org +#define MSG_PVS_R 6 // Reliable to PVS +#define MSG_PAS_R 7 // Reliable to PAS +#define MSG_ONE_UNRELIABLE 8 // Send to one client, but don't put in reliable stream, put in unreliable datagram ( could be dropped ) +#define MSG_SPEC 9 // Sends to all spectator proxies + +// contents of a spot in the world +#define CONTENTS_EMPTY -1 +#define CONTENTS_SOLID -2 +#define CONTENTS_WATER -3 +#define CONTENTS_SLIME -4 +#define CONTENTS_LAVA -5 +#define CONTENTS_SKY -6 +/* These additional contents constants are defined in bspfile.h +#define CONTENTS_ORIGIN -7 // removed at csg time +#define CONTENTS_CLIP -8 // changed to contents_solid +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 + +#define CONTENTS_TRANSLUCENT -15 +*/ +#define CONTENTS_LADDER -16 + +#define CONTENT_FLYFIELD -17 +#define CONTENT_GRAVITY_FLYFIELD -18 +#define CONTENT_FOG -19 + +#define CONTENT_EMPTY -1 +#define CONTENT_SOLID -2 +#define CONTENT_WATER -3 +#define CONTENT_SLIME -4 +#define CONTENT_LAVA -5 +#define CONTENT_SKY -6 + +// channels +#define CHAN_AUTO 0 +#define CHAN_WEAPON 1 +#define CHAN_VOICE 2 +#define CHAN_ITEM 3 +#define CHAN_BODY 4 +#define CHAN_STREAM 5 // allocate stream channel from the static or dynamic area +#define CHAN_STATIC 6 // allocate channel from the static area +#define CHAN_NETWORKVOICE_BASE 7 // voice data coming across the network +#define CHAN_NETWORKVOICE_END 500 // network voice data reserves slots (CHAN_NETWORKVOICE_BASE through CHAN_NETWORKVOICE_END). +#define CHAN_BOT 501 // channel used for bot chatter. + +// attenuation values +#define ATTN_NONE 0 +#define ATTN_NORM (float)0.8 +#define ATTN_IDLE (float)2 +#define ATTN_STATIC (float)1.25 + +// pitch values +#define PITCH_NORM 100 // non-pitch shifted +#define PITCH_LOW 95 // other values are possible - 0-255, where 255 is very high +#define PITCH_HIGH 120 + +// volume values +#define VOL_NORM 1.0 + +// plats +#define PLAT_LOW_TRIGGER 1 + +// Trains +#define SF_TRAIN_WAIT_RETRIGGER 1 +#define SF_TRAIN_START_ON 4 // Train is initially moving +#define SF_TRAIN_PASSABLE 8 // Train is not solid -- used to make water trains + +// buttons +#ifndef IN_BUTTONS_H +#include "in_buttons.h" +#endif + +// Break Model Defines + +#define BREAK_TYPEMASK 0x4F +#define BREAK_GLASS 0x01 +#define BREAK_METAL 0x02 +#define BREAK_FLESH 0x04 +#define BREAK_WOOD 0x08 + +#define BREAK_SMOKE 0x10 +#define BREAK_TRANS 0x20 +#define BREAK_CONCRETE 0x40 +#define BREAK_2 0x80 + +// Colliding temp entity sounds + +#define BOUNCE_GLASS BREAK_GLASS +#define BOUNCE_METAL BREAK_METAL +#define BOUNCE_FLESH BREAK_FLESH +#define BOUNCE_WOOD BREAK_WOOD +#define BOUNCE_SHRAP 0x10 +#define BOUNCE_SHELL 0x20 +#define BOUNCE_CONCRETE BREAK_CONCRETE +#define BOUNCE_SHOTSHELL 0x80 + +// Temp entity bounce sound types +#define TE_BOUNCE_NULL 0 +#define TE_BOUNCE_SHELL 1 +#define TE_BOUNCE_SHOTSHELL 2 + +// Rendering constants +enum +{ + kRenderNormal, // src + kRenderTransColor, // c*a+dest*(1-a) + kRenderTransTexture, // src*a+dest*(1-a) + kRenderGlow, // src*a+dest -- No Z buffer checks + kRenderTransAlpha, // src*srca+dest*(1-srca) + kRenderTransAdd, // src*a+dest +}; + +enum +{ + kRenderFxNone = 0, + kRenderFxPulseSlow, + kRenderFxPulseFast, + kRenderFxPulseSlowWide, + kRenderFxPulseFastWide, + kRenderFxFadeSlow, + kRenderFxFadeFast, + kRenderFxSolidSlow, + kRenderFxSolidFast, + kRenderFxStrobeSlow, + kRenderFxStrobeFast, + kRenderFxStrobeFaster, + kRenderFxFlickerSlow, + kRenderFxFlickerFast, + kRenderFxNoDissipation, + kRenderFxDistort, // Distort/scale/translate flicker + kRenderFxHologram, // kRenderFxDistort + distance fade + kRenderFxDeadPlayer, // kRenderAmt is the player index + kRenderFxExplode, // Scale up really big! + kRenderFxGlowShell, // Glowing Shell + kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) + kRenderFxLightMultiplier, //CTM !!!CZERO added to tell the studiorender that the value in iuser2 is a lightmultiplier +}; + + +typedef unsigned int func_t; +typedef unsigned int string_t; + +typedef unsigned char byte; +typedef unsigned short word; +#define _DEF_BYTE_ + +#undef true +#undef false + +#ifndef __cplusplus +typedef enum {false, true} qboolean; +#else +typedef int qboolean; +#endif + +typedef struct +{ + byte r, g, b; +} color24; + +typedef struct +{ + unsigned r, g, b, a; +} colorVec; + +#ifdef _WIN32 +#pragma pack(push,2) +#endif + +typedef struct +{ + unsigned short r, g, b, a; +} PackedColorVec; + +#ifdef _WIN32 +#pragma pack(pop) +#endif +typedef struct link_s +{ + struct link_s *prev, *next; +} link_t; + +typedef struct edict_s edict_t; + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +typedef struct +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + plane_t plane; // surface normal at impact + edict_t * ent; // entity the surface is on + int hitgroup; // 0 == generic, non zero is specific body part +} trace_t; + +#endif // CONST_H diff --git a/rehlds/common/crc.h b/rehlds/common/crc.h new file mode 100644 index 0000000..913af67 --- /dev/null +++ b/rehlds/common/crc.h @@ -0,0 +1,55 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* crc.h */ +#pragma once + +#include "quakedef.h" + +// MD5 Hash +typedef struct +{ + unsigned int buf[4]; + unsigned int bits[2]; + unsigned char in[64]; +} MD5Context_t; + +typedef unsigned int CRC32_t; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +void CRC32_Init(CRC32_t *pulCRC); +CRC32_t CRC32_Final(CRC32_t pulCRC); +void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch); +void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *pBuffer, int nBuffer); +NOXREF BOOL CRC_File(CRC32_t *crcvalue, char *pszFileName); + +#ifdef __cplusplus +} +#endif + +byte COM_BlockSequenceCRCByte(byte *base, int length, int sequence); +int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName); + +void MD5Init(MD5Context_t *ctx); +void MD5Update(MD5Context_t *ctx, const unsigned char *buf, unsigned int len); +void MD5Final(unsigned char digest[16], MD5Context_t *ctx); +void MD5Transform(unsigned int buf[4], const unsigned int in[16]); + +BOOL MD5_Hash_File(unsigned char digest[16], char *pszFileName, BOOL bUsefopen, BOOL bSeed, unsigned int seed[4]); +char *MD5_Print(unsigned char hash[16]); diff --git a/rehlds/common/cvardef.h b/rehlds/common/cvardef.h new file mode 100644 index 0000000..23b442f --- /dev/null +++ b/rehlds/common/cvardef.h @@ -0,0 +1,39 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef CVARDEF_H +#define CVARDEF_H + +#define FCVAR_ARCHIVE (1<<0) // set to cause it to be saved to vars.rc +#define FCVAR_USERINFO (1<<1) // changes the client's info string +#define FCVAR_SERVER (1<<2) // notifies players when changed +#define FCVAR_EXTDLL (1<<3) // defined by external DLL +#define FCVAR_CLIENTDLL (1<<4) // defined by the client dll +#define FCVAR_PROTECTED (1<<5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value +#define FCVAR_SPONLY (1<<6) // This cvar cannot be changed by clients connected to a multiplayer server. +#define FCVAR_PRINTABLEONLY (1<<7) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). +#define FCVAR_UNLOGGED (1<<8) // If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log +#define FCVAR_NOEXTRAWHITEPACE (1<<9) // strip trailing/leading white space from this cvar + +typedef struct cvar_s +{ + char *name; + char *string; + int flags; + float value; + struct cvar_s *next; +} cvar_t; + +#endif // CVARDEF_H diff --git a/rehlds/common/demo_api.h b/rehlds/common/demo_api.h new file mode 100644 index 0000000..be20cc1 --- /dev/null +++ b/rehlds/common/demo_api.h @@ -0,0 +1,31 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( DEMO_APIH ) +#define DEMO_APIH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct demo_api_s +{ + int ( *IsRecording ) ( void ); + int ( *IsPlayingback ) ( void ); + int ( *IsTimeDemo ) ( void ); + void ( *WriteBuffer ) ( int size, unsigned char *buffer ); +} demo_api_t; + +extern demo_api_t demoapi; + +#endif diff --git a/rehlds/common/director_cmds.h b/rehlds/common/director_cmds.h new file mode 100644 index 0000000..da99929 --- /dev/null +++ b/rehlds/common/director_cmds.h @@ -0,0 +1,38 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// director_cmds.h +// sub commands for svc_director + +#define DRC_ACTIVE 0 // tells client that he's an spectator and will get director command +#define DRC_STATUS 1 // send status infos about proxy +#define DRC_CAMERA 2 // set the actual director camera position +#define DRC_EVENT 3 // informs the dircetor about ann important game event + + +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_SIDE (1<<4) +#define DRC_FLAG_DRAMATIC (1<<5) + + + +// commands of the director API function CallDirectorProc(...) + +#define DRCAPI_NOP 0 // no operation +#define DRCAPI_ACTIVE 1 // de/acivates director mode in engine +#define DRCAPI_STATUS 2 // request proxy information +#define DRCAPI_SETCAM 3 // set camera n to given position and angle +#define DRCAPI_GETCAM 4 // request camera n position and angle +#define DRCAPI_DIRPLAY 5 // set director time and play with normal speed +#define DRCAPI_DIRFREEZE 6 // freeze directo at this time +#define DRCAPI_SETVIEWMODE 7 // overview or 4 cameras +#define DRCAPI_SETOVERVIEWPARAMS 8 // sets parameter for overview mode +#define DRCAPI_SETFOCUS 9 // set the camera which has the input focus +#define DRCAPI_GETTARGETS 10 // queries engine for player list +#define DRCAPI_SETVIEWPOINTS 11 // gives engine all waypoints + + diff --git a/rehlds/common/dlight.h b/rehlds/common/dlight.h new file mode 100644 index 0000000..0abc857 --- /dev/null +++ b/rehlds/common/dlight.h @@ -0,0 +1,33 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( DLIGHTH ) +#define DLIGHTH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct dlight_s +{ + vec3_t origin; + float radius; + color24 color; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; + qboolean dark; // subtracts light instead of adding +} dlight_t; + +#endif diff --git a/rehlds/common/dll_state.h b/rehlds/common/dll_state.h new file mode 100644 index 0000000..c297132 --- /dev/null +++ b/rehlds/common/dll_state.h @@ -0,0 +1,23 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +//DLL State Flags + +#define DLL_INACTIVE 0 // no dll +#define DLL_ACTIVE 1 // dll is running +#define DLL_PAUSED 2 // dll is paused +#define DLL_CLOSE 3 // closing down dll +#define DLL_TRANS 4 // Level Transition + +// DLL Pause reasons + +#define DLL_NORMAL 0 // User hit Esc or something. +#define DLL_QUIT 4 // Quit now +#define DLL_RESTART 5 // Switch to launcher for linux, does a quit but returns 1 + +// DLL Substate info ( not relevant ) +#define ENG_NORMAL (1<<0) diff --git a/rehlds/common/entity_state.h b/rehlds/common/entity_state.h new file mode 100644 index 0000000..4bd381e --- /dev/null +++ b/rehlds/common/entity_state.h @@ -0,0 +1,197 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef ENTITY_STATE_H +#define ENTITY_STATE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "const.h" + + +// For entityType below +#define ENTITY_NORMAL (1<<0) +#define ENTITY_BEAM (1<<1) + +// Entity state is used for the baseline and for delta compression of a packet of +// entities that is sent to a client. +typedef struct entity_state_s entity_state_t; + +struct entity_state_s +{ +// Fields which are filled in by routines outside of delta compression + int entityType; + // Index into cl_entities array for this entity. + int number; + float msg_time; + + // Message number last time the player/entity state was updated. + int messagenum; + + // Fields which can be transitted and reconstructed over the network stream + vec3_t origin; + vec3_t angles; + + int modelindex; + int sequence; + float frame; + int colormap; + short skin; + short solid; + int effects; + float scale; + + byte eflags; + + // Render information + int rendermode; + int renderamt; + color24 rendercolor; + int renderfx; + + int movetype; + float animtime; + float framerate; + int body; + byte controller[4]; + byte blending[4]; + vec3_t velocity; + + // Send bbox down to client for use during prediction. + vec3_t mins; + vec3_t maxs; + + int aiment; + // If owned by a player, the index of that player ( for projectiles ). + int owner; + + // Friction, for prediction. + float friction; + // Gravity multiplier + float gravity; + +// PLAYER SPECIFIC + int team; + int playerclass; + int health; + qboolean spectator; + int weaponmodel; + int gaitsequence; + // If standing on conveyor, e.g. + vec3_t basevelocity; + // Use the crouched hull, or the regular player hull. + int usehull; + // Latched buttons last time state updated. + int oldbuttons; + // -1 = in air, else pmove entity number + int onground; + int iStepLeft; + // How fast we are falling + float flFallVelocity; + + float fov; + int weaponanim; + + // Parametric movement overrides + vec3_t startpos; + vec3_t endpos; + float impacttime; + float starttime; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +}; + +#include "pm_info.h" + +typedef struct clientdata_s +{ + vec3_t origin; + vec3_t velocity; + + int viewmodel; + vec3_t punchangle; + int flags; + int waterlevel; + int watertype; + vec3_t view_ofs; + float health; + + int bInDuck; + + int weapons; // remove? + + int flTimeStepSound; + int flDuckTime; + int flSwimTime; + int waterjumptime; + + float maxspeed; + + float fov; + int weaponanim; + + int m_iId; + int ammo_shells; + int ammo_nails; + int ammo_cells; + int ammo_rockets; + float m_flNextAttack; + + int tfstate; + + int pushmsec; + + int deadflag; + + char physinfo[ MAX_PHYSINFO_STRING ]; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +} clientdata_t; + +#include "weaponinfo.h" + +typedef struct local_state_s +{ + entity_state_t playerstate; + clientdata_t client; + weapon_data_t weapondata[ 64 ]; +} local_state_t; + +#endif // ENTITY_STATE_H diff --git a/rehlds/common/entity_types.h b/rehlds/common/entity_types.h new file mode 100644 index 0000000..2ab96e3 --- /dev/null +++ b/rehlds/common/entity_types.h @@ -0,0 +1,26 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// entity_types.h +#if !defined( ENTITY_TYPESH ) +#define ENTITY_TYPESH + +#define ET_NORMAL 0 +#define ET_PLAYER 1 +#define ET_TEMPENTITY 2 +#define ET_BEAM 3 +// BMODEL or SPRITE that was split across BSP nodes +#define ET_FRAGMENTED 4 + +#endif // !ENTITY_TYPESH diff --git a/rehlds/common/enums.h b/rehlds/common/enums.h new file mode 100644 index 0000000..4f6021d --- /dev/null +++ b/rehlds/common/enums.h @@ -0,0 +1,27 @@ +/*** + * + * Copyright (c) 2009, Valve LLC. All rights reserved. + * + * This product contains software technology licensed from Id + * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. + * All Rights Reserved. + * + * Use, distribution, and modification of this source code and/or resulting + * object code is restricted to non-commercial enhancements to products from + * Valve LLC. All other use, distribution, or modification is prohibited + * without written permission from Valve LLC. + * + ****/ + +#ifndef ENUMS_H +#define ENUMS_H + +typedef enum netsrc_s +{ + NS_CLIENT, + NS_SERVER, + NS_MULTICAST // xxxMO +} netsrc_t; + +#endif + diff --git a/rehlds/common/event_api.h b/rehlds/common/event_api.h new file mode 100644 index 0000000..9e4a1fe --- /dev/null +++ b/rehlds/common/event_api.h @@ -0,0 +1,51 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( EVENT_APIH ) +#define EVENT_APIH +#ifdef _WIN32 +#pragma once +#endif + +#define EVENT_API_VERSION 1 + +typedef struct event_api_s +{ + int version; + void ( *EV_PlaySound ) ( int ent, float *origin, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); + void ( *EV_StopSound ) ( int ent, int channel, const char *sample ); + int ( *EV_FindModelIndex )( const char *pmodel ); + int ( *EV_IsLocal ) ( int playernum ); + int ( *EV_LocalPlayerDucking ) ( void ); + void ( *EV_LocalPlayerViewheight ) ( float * ); + void ( *EV_LocalPlayerBounds ) ( int hull, float *mins, float *maxs ); + int ( *EV_IndexFromTrace) ( struct pmtrace_s *pTrace ); + struct physent_s *( *EV_GetPhysent ) ( int idx ); + void ( *EV_SetUpPlayerPrediction ) ( int dopred, int bIncludeLocalClient ); + void ( *EV_PushPMStates ) ( void ); + void ( *EV_PopPMStates ) ( void ); + void ( *EV_SetSolidPlayers ) (int playernum); + void ( *EV_SetTraceHull ) ( int hull ); + void ( *EV_PlayerTrace ) ( float *start, float *end, int traceFlags, int ignore_pe, struct pmtrace_s *tr ); + void ( *EV_WeaponAnimation ) ( int sequence, int body ); + unsigned short ( *EV_PrecacheEvent ) ( int type, const char* psz ); + void ( *EV_PlaybackEvent ) ( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); + const char *( *EV_TraceTexture ) ( int ground, float *vstart, float *vend ); + void ( *EV_StopAllSounds ) ( int entnum, int entchannel ); + void ( *EV_KillEvents ) ( int entnum, const char *eventname ); +} event_api_t; + +extern event_api_t eventapi; + +#endif diff --git a/rehlds/common/event_args.h b/rehlds/common/event_args.h new file mode 100644 index 0000000..8c41076 --- /dev/null +++ b/rehlds/common/event_args.h @@ -0,0 +1,50 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( EVENT_ARGSH ) +#define EVENT_ARGSH +#ifdef _WIN32 +#pragma once +#endif + +// Event was invoked with stated origin +#define FEVENT_ORIGIN ( 1<<0 ) + +// Event was invoked with stated angles +#define FEVENT_ANGLES ( 1<<1 ) + +typedef struct event_args_s +{ + int flags; + + // Transmitted + int entindex; + + float origin[3]; + float angles[3]; + float velocity[3]; + + int ducking; + + float fparam1; + float fparam2; + + int iparam1; + int iparam2; + + int bparam1; + int bparam2; +} event_args_t; + +#endif diff --git a/rehlds/common/event_flags.h b/rehlds/common/event_flags.h new file mode 100644 index 0000000..d601e43 --- /dev/null +++ b/rehlds/common/event_flags.h @@ -0,0 +1,47 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( EVENT_FLAGSH ) +#define EVENT_FLAGSH +#ifdef _WIN32 +#pragma once +#endif + +// Skip local host for event send. +#define FEV_NOTHOST (1<<0) + +// Send the event reliably. You must specify the origin and angles and use +// PLAYBACK_EVENT_FULL for this to work correctly on the server for anything +// that depends on the event origin/angles. I.e., the origin/angles are not +// taken from the invoking edict for reliable events. +#define FEV_RELIABLE (1<<1) + +// Don't restrict to PAS/PVS, send this event to _everybody_ on the server ( useful for stopping CHAN_STATIC +// sounds started by client event when client is not in PVS anymore ( hwguy in TFC e.g. ). +#define FEV_GLOBAL (1<<2) + +// If this client already has one of these events in its queue, just update the event instead of sending it as a duplicate +// +#define FEV_UPDATE (1<<3) + +// Only send to entity specified as the invoker +#define FEV_HOSTONLY (1<<4) + +// Only send if the event was created on the server. +#define FEV_SERVER (1<<5) + +// Only issue event client side ( from shared code ) +#define FEV_CLIENT (1<<6) + +#endif diff --git a/rehlds/common/hltv.h b/rehlds/common/hltv.h new file mode 100644 index 0000000..136183d --- /dev/null +++ b/rehlds/common/hltv.h @@ -0,0 +1,61 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// hltv.h +// all shared consts between server, clients and proxy + +#ifndef HLTV_H +#define HLTV_H + +#define TYPE_CLIENT 0 // client is a normal HL client (default) +#define TYPE_PROXY 1 // client is another proxy +#define TYPE_COMMENTATOR 3 // client is a commentator +#define TYPE_DEMO 4 // client is a demo file + +// sub commands of svc_hltv: +#define HLTV_ACTIVE 0 // tells client that he's an spectator and will get director commands +#define HLTV_STATUS 1 // send status infos about proxy +#define HLTV_LISTEN 2 // tell client to listen to a multicast stream + +// director command types: +#define DRC_CMD_NONE 0 // NULL director command +#define DRC_CMD_START 1 // start director mode +#define DRC_CMD_EVENT 2 // informs about director command +#define DRC_CMD_MODE 3 // switches camera modes +#define DRC_CMD_CAMERA 4 // set fixed camera +#define DRC_CMD_TIMESCALE 5 // sets time scale +#define DRC_CMD_MESSAGE 6 // send HUD centerprint +#define DRC_CMD_SOUND 7 // plays a particular sound +#define DRC_CMD_STATUS 8 // HLTV broadcast status +#define DRC_CMD_BANNER 9 // set GUI banner +#define DRC_CMD_STUFFTEXT 10 // like the normal svc_stufftext but as director command +#define DRC_CMD_CHASE 11 // chase a certain player +#define DRC_CMD_INEYE 12 // view player through own eyes +#define DRC_CMD_MAP 13 // show overview map +#define DRC_CMD_CAMPATH 14 // define camera waypoint +#define DRC_CMD_WAYPOINTS 15 // start moving camera, inetranl message + +#define DRC_CMD_LAST 15 + + +// DRC_CMD_EVENT event flags +#define DRC_FLAG_PRIO_MASK 0x0F // priorities between 0 and 15 (15 most important) +#define DRC_FLAG_SIDE (1<<4) // +#define DRC_FLAG_DRAMATIC (1<<5) // is a dramatic scene +#define DRC_FLAG_SLOWMOTION (1<<6) // would look good in SloMo +#define DRC_FLAG_FACEPLAYER (1<<7) // player is doning something (reload/defuse bomb etc) +#define DRC_FLAG_INTRO (1<<8) // is a introduction scene +#define DRC_FLAG_FINAL (1<<9) // is a final scene +#define DRC_FLAG_NO_RANDOM (1<<10) // don't randomize event data + + +// DRC_CMD_WAYPOINT flags +#define DRC_FLAG_STARTPATH 1 // end with speed 0.0 +#define DRC_FLAG_SLOWSTART 2 // start with speed 0.0 +#define DRC_FLAG_SLOWEND 4 // end with speed 0.0 + +#endif // HLTV_H diff --git a/rehlds/common/in_buttons.h b/rehlds/common/in_buttons.h new file mode 100644 index 0000000..7ed5650 --- /dev/null +++ b/rehlds/common/in_buttons.h @@ -0,0 +1,38 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef IN_BUTTONS_H +#define IN_BUTTONS_H +#ifdef _WIN32 +#pragma once +#endif + +#define IN_ATTACK (1 << 0) +#define IN_JUMP (1 << 1) +#define IN_DUCK (1 << 2) +#define IN_FORWARD (1 << 3) +#define IN_BACK (1 << 4) +#define IN_USE (1 << 5) +#define IN_CANCEL (1 << 6) +#define IN_LEFT (1 << 7) +#define IN_RIGHT (1 << 8) +#define IN_MOVELEFT (1 << 9) +#define IN_MOVERIGHT (1 << 10) +#define IN_ATTACK2 (1 << 11) +#define IN_RUN (1 << 12) +#define IN_RELOAD (1 << 13) +#define IN_ALT1 (1 << 14) +#define IN_SCORE (1 << 15) // Used by client.dll for when scoreboard is held down + +#endif // IN_BUTTONS_H diff --git a/rehlds/common/ivoicetweak.h b/rehlds/common/ivoicetweak.h new file mode 100644 index 0000000..c15ef5f --- /dev/null +++ b/rehlds/common/ivoicetweak.h @@ -0,0 +1,38 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef IVOICETWEAK_H +#define IVOICETWEAK_H +#ifdef _WIN32 +#pragma once +#endif + +// These provide access to the voice controls. +typedef enum +{ + MicrophoneVolume=0, // values 0-1. + OtherSpeakerScale, // values 0-1. Scales how loud other players are. + MicBoost, // 20 db gain to voice input +} VoiceTweakControl; + + +typedef struct IVoiceTweak_s +{ + // These turn voice tweak mode on and off. While in voice tweak mode, the user's voice is echoed back + // without sending to the server. + int (*StartVoiceTweakMode)(); // Returns 0 on error. + void (*EndVoiceTweakMode)(); + + // Get/set control values. + void (*SetControlFloat)(VoiceTweakControl iControl, float value); + float (*GetControlFloat)(VoiceTweakControl iControl); + + int (*GetSpeakingVolume)(); +} IVoiceTweak; + + +#endif // IVOICETWEAK_H diff --git a/rehlds/common/kbutton.h b/rehlds/common/kbutton.h new file mode 100644 index 0000000..c8177e4 --- /dev/null +++ b/rehlds/common/kbutton.h @@ -0,0 +1,44 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef KBUTTON_H +#define KBUTTON_H +#ifdef _WIN32 +#pragma once +#endif + + +/* <31b2a> ../common/kbutton.h:7 */ +typedef struct kbutton_s +{ + int down[2]; + int state; +} kbutton_t; + + +#endif // KBUTTON_H diff --git a/rehlds/common/mathlib.h b/rehlds/common/mathlib.h new file mode 100644 index 0000000..5e91d41 --- /dev/null +++ b/rehlds/common/mathlib.h @@ -0,0 +1,49 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#pragma once + + +/* <42b7f> ../common/mathlib.h:3 */ +typedef float vec_t; + +/* <42b91> ../common/mathlib.h:6 */ +typedef vec_t vec3_t[3]; + +/* <80013> ../common/mathlib.h:8 */ +typedef vec_t vec4_t[4]; + +/* <42bac> ../common/mathlib.h:18 */ +typedef int fixed16_t; /* size: 4 */ + +/* <42bb7> ../common/mathlib.h:60 */ +typedef union DLONG_u +{ + int i[2]; + double d; + float f; +} DLONG; + +#define M_PI 3.14159265358979323846 + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#define clamp(val, min, max) (((val) > (max)) ? (max) : (((val) < (min)) ? (min) : (val))) diff --git a/rehlds/common/net_api.h b/rehlds/common/net_api.h new file mode 100644 index 0000000..c8e3439 --- /dev/null +++ b/rehlds/common/net_api.h @@ -0,0 +1,99 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( NET_APIH ) +#define NET_APIH +#ifdef _WIN32 +#pragma once +#endif + +#if !defined ( NETADRH ) +#include "netadr.h" +#endif + +#define NETAPI_REQUEST_SERVERLIST ( 0 ) // Doesn't need a remote address +#define NETAPI_REQUEST_PING ( 1 ) +#define NETAPI_REQUEST_RULES ( 2 ) +#define NETAPI_REQUEST_PLAYERS ( 3 ) +#define NETAPI_REQUEST_DETAILS ( 4 ) + +// Set this flag for things like broadcast requests, etc. where the engine should not +// kill the request hook after receiving the first response +#define FNETAPI_MULTIPLE_RESPONSE ( 1<<0 ) + +typedef void ( *net_api_response_func_t ) ( struct net_response_s *response ); + +#define NET_SUCCESS ( 0 ) +#define NET_ERROR_TIMEOUT ( 1<<0 ) +#define NET_ERROR_PROTO_UNSUPPORTED ( 1<<1 ) +#define NET_ERROR_UNDEFINED ( 1<<2 ) + +typedef struct net_adrlist_s +{ + struct net_adrlist_s *next; + netadr_t remote_address; +} net_adrlist_t; + +typedef struct net_response_s +{ + // NET_SUCCESS or an error code + int error; + + // Context ID + int context; + // Type + int type; + + // Server that is responding to the request + netadr_t remote_address; + + // Response RTT ping time + double ping; + // Key/Value pair string ( separated by backlash \ characters ) + // WARNING: You must copy this buffer in the callback function, because it is freed + // by the engine right after the call!!!! + // ALSO: For NETAPI_REQUEST_SERVERLIST requests, this will be a pointer to a linked list of net_adrlist_t's + void *response; +} net_response_t; + +typedef struct net_status_s +{ + // Connected to remote server? 1 == yes, 0 otherwise + int connected; + // Client's IP address + netadr_t local_address; + // Address of remote server + netadr_t remote_address; + // Packet Loss ( as a percentage ) + int packet_loss; + // Latency, in seconds ( multiply by 1000.0 to get milliseconds ) + double latency; + // Connection time, in seconds + double connection_time; + // Rate setting ( for incoming data ) + double rate; +} net_status_t; + +typedef struct net_api_s +{ + // APIs + void ( *InitNetworking )( void ); + void ( *Status ) ( struct net_status_s *status ); + void ( *SendRequest) ( int context, int request, int flags, double timeout, struct netadr_s *remote_address, net_api_response_func_t response ); + void ( *CancelRequest ) ( int context ); + void ( *CancelAllRequests ) ( void ); + char *( *AdrToString ) ( struct netadr_s *a ); + int ( *CompareAdr ) ( struct netadr_s *a, struct netadr_s *b ); + int ( *StringToAdr ) ( char *s, struct netadr_s *a ); + const char *( *ValueForKey ) ( const char *s, const char *key ); + void ( *RemoveKey ) ( char *s, const char *key ); + void ( *SetValueForKey ) (char *s, const char *key, const char *value, int maxsize ); +} net_api_t; + +extern net_api_t netapi; + +#endif // NET_APIH diff --git a/rehlds/common/netadr.h b/rehlds/common/netadr.h new file mode 100644 index 0000000..5cbf0ea --- /dev/null +++ b/rehlds/common/netadr.h @@ -0,0 +1,40 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// netadr.h +#ifndef NETADR_H +#define NETADR_H +#ifdef _WIN32 +#pragma once +#endif + +typedef enum +{ + NA_UNUSED, + NA_LOOPBACK, + NA_BROADCAST, + NA_IP, + NA_IPX, + NA_BROADCAST_IPX, +} netadrtype_t; + +typedef struct netadr_s +{ + netadrtype_t type; + unsigned char ip[4]; + unsigned char ipx[10]; + unsigned short port; +} netadr_t; + +#endif // NETADR_H diff --git a/rehlds/common/nowin.h b/rehlds/common/nowin.h new file mode 100644 index 0000000..d4fc615 --- /dev/null +++ b/rehlds/common/nowin.h @@ -0,0 +1,16 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef INC_NOWIN_H +#define INC_NOWIN_H +#ifndef _WIN32 + +#include +#include + +#endif //!_WIN32 +#endif //INC_NOWIN_H diff --git a/rehlds/common/parsemsg.cpp b/rehlds/common/parsemsg.cpp new file mode 100644 index 0000000..fa96324 --- /dev/null +++ b/rehlds/common/parsemsg.cpp @@ -0,0 +1,259 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// parsemsg.cpp +// +//-------------------------------------------------------------------------------------------------------------- +#include "parsemsg.h" +#include + +typedef unsigned char byte; +#define true 1 + +static byte *gpBuf; +static int giSize; +static int giRead; +static int giBadRead; + +int READ_OK( void ) +{ + return !giBadRead; +} + +void BEGIN_READ( void *buf, int size ) +{ + giRead = 0; + giBadRead = 0; + giSize = size; + gpBuf = (byte*)buf; +} + + +int READ_CHAR( void ) +{ + int c; + + if (giRead + 1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (signed char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_BYTE( void ) +{ + int c; + + if (giRead+1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (unsigned char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_SHORT( void ) +{ + int c; + + if (giRead+2 > giSize) + { + giBadRead = true; + return -1; + } + + c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) ); + + giRead += 2; + + return c; +} + +int READ_WORD( void ) +{ + return READ_SHORT(); +} + + +int READ_LONG( void ) +{ + int c; + + if (giRead+4 > giSize) + { + giBadRead = true; + return -1; + } + + c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24); + + giRead += 4; + + return c; +} + +float READ_FLOAT( void ) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + dat.b[0] = gpBuf[giRead]; + dat.b[1] = gpBuf[giRead+1]; + dat.b[2] = gpBuf[giRead+2]; + dat.b[3] = gpBuf[giRead+3]; + giRead += 4; + +// dat.l = LittleLong (dat.l); + + return dat.f; +} + +char* READ_STRING( void ) +{ + static char string[2048]; + int l,c; + + string[0] = 0; + + l = 0; + do + { + if ( giRead+1 > giSize ) + break; // no more characters + + c = READ_CHAR(); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +float READ_COORD( void ) +{ + return (float)(READ_SHORT() * (1.0/8)); +} + +float READ_ANGLE( void ) +{ + return (float)(READ_CHAR() * (360.0/256)); +} + +float READ_HIRESANGLE( void ) +{ + return (float)(READ_SHORT() * (360.0/65536)); +} + +//-------------------------------------------------------------------------------------------------------------- +BufferWriter::BufferWriter() +{ + Init( NULL, 0 ); +} + +//-------------------------------------------------------------------------------------------------------------- +BufferWriter::BufferWriter( unsigned char *buffer, int bufferLen ) +{ + Init( buffer, bufferLen ); +} + +//-------------------------------------------------------------------------------------------------------------- +void BufferWriter::Init( unsigned char *buffer, int bufferLen ) +{ + m_overflow = false; + m_buffer = buffer; + m_remaining = bufferLen; + m_overallLength = bufferLen; +} + +//-------------------------------------------------------------------------------------------------------------- +void BufferWriter::WriteByte( unsigned char data ) +{ + if (!m_buffer || !m_remaining) + { + m_overflow = true; + return; + } + + *m_buffer = data; + ++m_buffer; + --m_remaining; +} + +//-------------------------------------------------------------------------------------------------------------- +void BufferWriter::WriteLong( int data ) +{ + if (!m_buffer || m_remaining < 4) + { + m_overflow = true; + return; + } + + m_buffer[0] = data&0xff; + m_buffer[1] = (data>>8)&0xff; + m_buffer[2] = (data>>16)&0xff; + m_buffer[3] = data>>24; + m_buffer += 4; + m_remaining -= 4; +} + +//-------------------------------------------------------------------------------------------------------------- +void BufferWriter::WriteString( const char *str ) +{ + if (!m_buffer || !m_remaining) + { + m_overflow = true; + return; + } + + if (!str) + str = ""; + + int len = strlen(str)+1; + if ( len > m_remaining ) + { + m_overflow = true; + str = ""; + len = 1; + } + + strcpy((char *)m_buffer, str); + m_remaining -= len; + m_buffer += len; +} + +//-------------------------------------------------------------------------------------------------------------- +int BufferWriter::GetSpaceUsed() +{ + return m_overallLength - m_remaining; +} + +//-------------------------------------------------------------------------------------------------------------- diff --git a/rehlds/common/parsemsg.h b/rehlds/common/parsemsg.h new file mode 100644 index 0000000..194f844 --- /dev/null +++ b/rehlds/common/parsemsg.h @@ -0,0 +1,66 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// parsemsg.h +// MDC - copying from cstrike\cl_dll so career-mode stuff can catch messages +// in this dll. (and C++ifying it) +// + +#ifndef PARSEMSG_H +#define PARSEMSG_H + +#define ASSERT( x ) +//-------------------------------------------------------------------------------------------------------------- +void BEGIN_READ( void *buf, int size ); +int READ_CHAR( void ); +int READ_BYTE( void ); +int READ_SHORT( void ); +int READ_WORD( void ); +int READ_LONG( void ); +float READ_FLOAT( void ); +char* READ_STRING( void ); +float READ_COORD( void ); +float READ_ANGLE( void ); +float READ_HIRESANGLE( void ); +int READ_OK( void ); + +//-------------------------------------------------------------------------------------------------------------- +class BufferWriter +{ +public: + BufferWriter(); + BufferWriter( unsigned char *buffer, int bufferLen ); + void Init( unsigned char *buffer, int bufferLen ); + + void WriteByte( unsigned char data ); + void WriteLong( int data ); + void WriteString( const char *str ); + + bool HasOverflowed(); + int GetSpaceUsed(); + +protected: + unsigned char *m_buffer; + int m_remaining; + bool m_overflow; + int m_overallLength; +}; + +//-------------------------------------------------------------------------------------------------------------- + +#endif // PARSEMSG_H + + + diff --git a/rehlds/common/particledef.h b/rehlds/common/particledef.h new file mode 100644 index 0000000..b1356d2 --- /dev/null +++ b/rehlds/common/particledef.h @@ -0,0 +1,57 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( PARTICLEDEFH ) +#define PARTICLEDEFH +#ifdef _WIN32 +#pragma once +#endif + +typedef enum { + pt_static, + pt_grav, + pt_slowgrav, + pt_fire, + pt_explode, + pt_explode2, + pt_blob, + pt_blob2, + pt_vox_slowgrav, + pt_vox_grav, + pt_clientcustom // Must have callback function specified +} ptype_t; + +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +typedef struct particle_s +{ +// driver-usable fields + vec3_t org; + short color; + short packedColor; +// drivers never touch the following fields + struct particle_s *next; + vec3_t vel; + float ramp; + float die; + ptype_t type; + void (*deathfunc)( struct particle_s *particle ); + + // for pt_clientcusttom, we'll call this function each frame + void (*callback)( struct particle_s *particle, float frametime ); + + // For deathfunc, etc. + unsigned char context; +} particle_t; + +#endif diff --git a/rehlds/common/pmtrace.h b/rehlds/common/pmtrace.h new file mode 100644 index 0000000..8d33780 --- /dev/null +++ b/rehlds/common/pmtrace.h @@ -0,0 +1,43 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( PMTRACEH ) +#define PMTRACEH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct +{ + vec3_t normal; + float dist; +} pmplane_t; + +typedef struct pmtrace_s pmtrace_t; + +struct pmtrace_s +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; // End point is in empty space or in water + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + pmplane_t plane; // surface normal at impact + int ent; // entity at impact + vec3_t deltavelocity; // Change in player's velocity caused by impact. + // Only run on server. + int hitgroup; +}; + +#endif diff --git a/rehlds/common/port.h b/rehlds/common/port.h new file mode 100644 index 0000000..fc12e70 --- /dev/null +++ b/rehlds/common/port.h @@ -0,0 +1,119 @@ +// port.h: portability helper +// +////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "archtypes.h" // DAL + +#ifdef _WIN32 + + // Insert your headers here + #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + #define WIN32_EXTRA_LEAN + + #include "winsani_in.h" + #include + #include "winsani_out.h" + + #include + #include + #include + +#else // _WIN32 + + #include + #include + #include // exit() + #include // strncpy() + #include // tolower() + #include + #include + #include + #include + + typedef unsigned char BYTE; + + typedef int32 LONG; + //typedef uint32 ULONG; + + #ifndef ARCHTYPES_H + typedef uint32 ULONG; + #endif + + typedef void *HANDLE; + + #ifndef HMODULE + typedef void *HMODULE; + #endif + + typedef char * LPSTR; + + #define __cdecl + + + #ifdef __linux__ + typedef struct POINT_s + { + int x; + int y; + } POINT; + typedef void *HINSTANCE; + typedef void *HWND; + typedef void *HDC; + typedef void *HGLRC; + + typedef struct RECT_s + { + int left; + int right; + int top; + int bottom; + } RECT; + #endif + + + #ifdef __cplusplus + + //#undef FALSE + //#undef TRUE + + #ifdef OSX + //#else + //const bool FALSE = false; + //const bool TRUE = true; + #endif + #endif + + #ifndef NULL + #ifdef __cplusplus + #define NULL 0 + #else + #define NULL ((void *)0) + #endif + #endif + + #ifdef __cplusplus + inline int ioctlsocket( int d, int cmd, uint32 *argp ) { return ioctl( d, cmd, argp ); } + inline int closesocket( int fd ) { return close( fd ); } + inline char * GetCurrentDirectory( size_t size, char * buf ) { return getcwd( buf, size ); } + inline int WSAGetLastError() { return errno; } + + inline void DebugBreak( void ) { exit( 1 ); } + #endif + + extern char g_szEXEName[ 4096 ]; + + #define _snprintf snprintf + + #if defined(OSX) + #define SO_ARCH_SUFFIX ".dylib" + #else + #if defined ( __x86_64__ ) + #define SO_ARCH_SUFFIX "_amd64.so" + #else + #define SO_ARCH_SUFFIX ".so" + #endif + #endif +#endif + diff --git a/rehlds/common/qfont.h b/rehlds/common/qfont.h new file mode 100644 index 0000000..010b5be --- /dev/null +++ b/rehlds/common/qfont.h @@ -0,0 +1,41 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( QFONTH ) +#define QFONTH +#ifdef _WIN32 +#pragma once +#endif + +// Font stuff + +#define NUM_GLYPHS 256 +// does not exist: // #include "basetypes.h" + +typedef struct +{ + short startoffset; + short charwidth; +} charinfo; + +typedef struct qfont_s +{ + int width, height; + int rowcount; + int rowheight; + charinfo fontinfo[ NUM_GLYPHS ]; + unsigned char data[4]; +} qfont_t; + +#endif // qfont.h diff --git a/rehlds/common/quakedef.h b/rehlds/common/quakedef.h new file mode 100644 index 0000000..42a971d --- /dev/null +++ b/rehlds/common/quakedef.h @@ -0,0 +1,41 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +/* <19039> ../common/quakedef.h:29 */ +typedef int BOOL; /* size: 4 */ + +/* <627f> ../common/quakedef.h:137 */ +//moved to com_model.h +//typedef struct cache_user_s +//{ +// void *data; +//} cache_user_t; + +/* <4313b> ../common/quakedef.h:162 */ +typedef int (*pfnUserMsgHook)(const char *, int, void *); diff --git a/rehlds/common/r_efx.h b/rehlds/common/r_efx.h new file mode 100644 index 0000000..1348175 --- /dev/null +++ b/rehlds/common/r_efx.h @@ -0,0 +1,197 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined ( R_EFXH ) +#define R_EFXH +#ifdef _WIN32 +#pragma once +#endif + +// particle_t +#if !defined( PARTICLEDEFH ) +#include "particledef.h" +#endif + +// BEAM +#if !defined( BEAMDEFH ) +#include "beamdef.h" +#endif + +// dlight_t +#if !defined ( DLIGHTH ) +#include "dlight.h" +#endif + +// cl_entity_t +#if !defined( CL_ENTITYH ) +#include "cl_entity.h" +#endif + +/* +// FOR REFERENCE, These are the built-in tracer colors. Note, color 4 is the one +// that uses the tracerred/tracergreen/tracerblue and traceralpha cvar settings +color24 gTracerColors[] = +{ + { 255, 255, 255 }, // White + { 255, 0, 0 }, // Red + { 0, 255, 0 }, // Green + { 0, 0, 255 }, // Blue + { 0, 0, 0 }, // Tracer default, filled in from cvars, etc. + { 255, 167, 17 }, // Yellow-orange sparks + { 255, 130, 90 }, // Yellowish streaks (garg) + { 55, 60, 144 }, // Blue egon streak + { 255, 130, 90 }, // More Yellowish streaks (garg) + { 255, 140, 90 }, // More Yellowish streaks (garg) + { 200, 130, 90 }, // More red streaks (garg) + { 255, 120, 70 }, // Darker red streaks (garg) +}; +*/ + +// Temporary entity array +#define TENTPRIORITY_LOW 0 +#define TENTPRIORITY_HIGH 1 + +// TEMPENTITY flags +#define FTENT_NONE 0x00000000 +#define FTENT_SINEWAVE 0x00000001 +#define FTENT_GRAVITY 0x00000002 +#define FTENT_ROTATE 0x00000004 +#define FTENT_SLOWGRAVITY 0x00000008 +#define FTENT_SMOKETRAIL 0x00000010 +#define FTENT_COLLIDEWORLD 0x00000020 +#define FTENT_FLICKER 0x00000040 +#define FTENT_FADEOUT 0x00000080 +#define FTENT_SPRANIMATE 0x00000100 +#define FTENT_HITSOUND 0x00000200 +#define FTENT_SPIRAL 0x00000400 +#define FTENT_SPRCYCLE 0x00000800 +#define FTENT_COLLIDEALL 0x00001000 // will collide with world and slideboxes +#define FTENT_PERSIST 0x00002000 // tent is not removed when unable to draw +#define FTENT_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything +#define FTENT_PLYRATTACHMENT 0x00008000 // tent is attached to a player (owner) +#define FTENT_SPRANIMATELOOP 0x00010000 // animating sprite doesn't die when last frame is displayed +#define FTENT_SPARKSHOWER 0x00020000 +#define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) +#define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) + +typedef struct tempent_s +{ + int flags; + float die; + float frameMax; + float x; + float y; + float z; + float fadeSpeed; + float bounceFactor; + int hitSound; + void ( *hitcallback ) ( struct tempent_s *ent, struct pmtrace_s *ptr ); + void ( *callback ) ( struct tempent_s *ent, float frametime, float currenttime ); + struct tempent_s *next; + int priority; + short clientIndex; // if attached, this is the index of the client to stick to + // if COLLIDEALL, this is the index of the client to ignore + // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! + + vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. + cl_entity_t entity; + + // baseline.origin - velocity + // baseline.renderamt - starting fadeout intensity + // baseline.angles - angle velocity +} TEMPENTITY; + +typedef struct efx_api_s efx_api_t; + +struct efx_api_s +{ + particle_t *( *R_AllocParticle ) ( void ( *callback ) ( struct particle_s *particle, float frametime ) ); + void ( *R_BlobExplosion ) ( float * org ); + void ( *R_Blood ) ( float * org, float * dir, int pcolor, int speed ); + void ( *R_BloodSprite ) ( float * org, int colorindex, int modelIndex, int modelIndex2, float size ); + void ( *R_BloodStream ) ( float * org, float * dir, int pcolor, int speed ); + void ( *R_BreakModel ) ( float *pos, float *size, float *dir, float random, float life, int count, int modelIndex, char flags ); + void ( *R_Bubbles ) ( float * mins, float * maxs, float height, int modelIndex, int count, float speed ); + void ( *R_BubbleTrail ) ( float * start, float * end, float height, int modelIndex, int count, float speed ); + void ( *R_BulletImpactParticles ) ( float * pos ); + void ( *R_EntityParticles ) ( struct cl_entity_s *ent ); + void ( *R_Explosion ) ( float *pos, int model, float scale, float framerate, int flags ); + void ( *R_FizzEffect ) ( struct cl_entity_s *pent, int modelIndex, int density ); + void ( *R_FireField ) ( float * org, int radius, int modelIndex, int count, int flags, float life ); + void ( *R_FlickerParticles ) ( float * org ); + void ( *R_FunnelSprite ) ( float *org, int modelIndex, int reverse ); + void ( *R_Implosion ) ( float * end, float radius, int count, float life ); + void ( *R_LargeFunnel ) ( float * org, int reverse ); + void ( *R_LavaSplash ) ( float * org ); + void ( *R_MultiGunshot ) ( float * org, float * dir, float * noise, int count, int decalCount, int *decalIndices ); + void ( *R_MuzzleFlash ) ( float *pos1, int type ); + void ( *R_ParticleBox ) ( float *mins, float *maxs, unsigned char r, unsigned char g, unsigned char b, float life ); + void ( *R_ParticleBurst ) ( float * pos, int size, int color, float life ); + void ( *R_ParticleExplosion ) ( float * org ); + void ( *R_ParticleExplosion2 ) ( float * org, int colorStart, int colorLength ); + void ( *R_ParticleLine ) ( float * start, float *end, unsigned char r, unsigned char g, unsigned char b, float life ); + void ( *R_PlayerSprites ) ( int client, int modelIndex, int count, int size ); + void ( *R_Projectile ) ( float * origin, float * velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s *ent, struct pmtrace_s *ptr ) ); + void ( *R_RicochetSound ) ( float * pos ); + void ( *R_RicochetSprite ) ( float *pos, struct model_s *pmodel, float duration, float scale ); + void ( *R_RocketFlare ) ( float *pos ); + void ( *R_RocketTrail ) ( float * start, float * end, int type ); + void ( *R_RunParticleEffect ) ( float * org, float * dir, int color, int count ); + void ( *R_ShowLine ) ( float * start, float * end ); + void ( *R_SparkEffect ) ( float *pos, int count, int velocityMin, int velocityMax ); + void ( *R_SparkShower ) ( float *pos ); + void ( *R_SparkStreaks ) ( float * pos, int count, int velocityMin, int velocityMax ); + void ( *R_Spray ) ( float * pos, float * dir, int modelIndex, int count, int speed, int spread, int rendermode ); + void ( *R_Sprite_Explode ) ( TEMPENTITY *pTemp, float scale, int flags ); + void ( *R_Sprite_Smoke ) ( TEMPENTITY *pTemp, float scale ); + void ( *R_Sprite_Spray ) ( float * pos, float * dir, int modelIndex, int count, int speed, int iRand ); + void ( *R_Sprite_Trail ) ( int type, float * start, float * end, int modelIndex, int count, float life, float size, float amplitude, int renderamt, float speed ); + void ( *R_Sprite_WallPuff ) ( TEMPENTITY *pTemp, float scale ); + void ( *R_StreakSplash ) ( float * pos, float * dir, int color, int count, float speed, int velocityMin, int velocityMax ); + void ( *R_TracerEffect ) ( float * start, float * end ); + void ( *R_UserTracerParticle ) ( float * org, float * vel, float life, int colorIndex, float length, unsigned char deathcontext, void ( *deathfunc)( struct particle_s *particle ) ); + particle_t *( *R_TracerParticles ) ( float * org, float * vel, float life ); + void ( *R_TeleportSplash ) ( float * org ); + void ( *R_TempSphereModel ) ( float *pos, float speed, float life, int count, int modelIndex ); + TEMPENTITY *( *R_TempModel ) ( float *pos, float *dir, float *angles, float life, int modelIndex, int soundtype ); + TEMPENTITY *( *R_DefaultSprite ) ( float *pos, int spriteIndex, float framerate ); + TEMPENTITY *( *R_TempSprite ) ( float *pos, float *dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); + int ( *Draw_DecalIndex ) ( int id ); + int ( *Draw_DecalIndexFromName ) ( char *name ); + void ( *R_DecalShoot ) ( int textureIndex, int entity, int modelIndex, float * position, int flags ); + void ( *R_AttachTentToPlayer ) ( int client, int modelIndex, float zoffset, float life ); + void ( *R_KillAttachedTents ) ( int client ); + BEAM *( *R_BeamCirclePoints ) ( int type, float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamEntPoint ) ( int startEnt, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamEnts ) ( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamFollow ) ( int startEnt, int modelIndex, float life, float width, float r, float g, float b, float brightness ); + void ( *R_BeamKill ) ( int deadEntity ); + BEAM *( *R_BeamLightning ) ( float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed ); + BEAM *( *R_BeamPoints ) ( float * start, float * end, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + BEAM *( *R_BeamRing ) ( int startEnt, int endEnt, int modelIndex, float life, float width, float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ); + dlight_t *( *CL_AllocDlight ) ( int key ); + dlight_t *( *CL_AllocElight ) ( int key ); + TEMPENTITY *( *CL_TempEntAlloc ) ( float * org, struct model_s *model ); + TEMPENTITY *( *CL_TempEntAllocNoModel ) ( float * org ); + TEMPENTITY *( *CL_TempEntAllocHigh ) ( float * org, struct model_s *model ); + TEMPENTITY *( *CL_TentEntAllocCustom ) ( float *origin, struct model_s *model, int high, void ( *callback ) ( struct tempent_s *ent, float frametime, float currenttime ) ); + void ( *R_GetPackedColor ) ( short *packed, short color ); + short ( *R_LookupColor ) ( unsigned char r, unsigned char g, unsigned char b ); + void ( *R_DecalRemoveAll ) ( int textureIndex ); //textureIndex points to the decal index in the array, not the actual texture index. + void ( *R_FireCustomDecal ) ( int textureIndex, int entity, int modelIndex, float * position, int flags, float scale ); +}; + +extern efx_api_t efx; + +#endif diff --git a/rehlds/common/r_studioint.h b/rehlds/common/r_studioint.h new file mode 100644 index 0000000..bbe105b --- /dev/null +++ b/rehlds/common/r_studioint.h @@ -0,0 +1,151 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( R_STUDIOINT_H ) +#define R_STUDIOINT_H +#if defined( _WIN32 ) +#pragma once +#endif + +#define STUDIO_INTERFACE_VERSION 1 + +typedef struct engine_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc ) ( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check ) ( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile ) ( char *path, struct cache_user_s *cu ); + // Retrieve model pointer for the named model + struct model_s *( *Mod_ForName ) ( const char *name, int crash_if_missing ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata ) ( struct model_s *mod ); + // Retrieve indexed model from client side model precache list + struct model_s *( *GetModelByIndex ) ( int index ); + // Get entity that is set for rendering + struct cl_entity_s * ( *GetCurrentEntity ) ( void ); + // Get referenced player_info_t + struct player_info_s *( *PlayerInfo ) ( int index ); + // Get most recently received player state data from network system + struct entity_state_s *( *GetPlayerState ) ( int index ); + // Get viewentity + struct cl_entity_s * ( *GetViewEntity ) ( void ); + // Get current frame count, and last two timestampes on client + void ( *GetTimes ) ( int *framecount, double *current, double *old ); + // Get a pointer to a cvar by name + struct cvar_s *( *GetCvar ) ( const char *name ); + // Get current render origin and view vectors ( up, right and vpn ) + void ( *GetViewInfo ) ( float *origin, float *upv, float *rightv, float *vpnv ); + // Get sprite model used for applying chrome effect + struct model_s *( *GetChromeSprite ) ( void ); + // Get model counters so we can incement instrumentation + void ( *GetModelCounters ) ( int **s, int **a ); + // Get software scaling coefficients + void ( *GetAliasScale ) ( float *x, float *y ); + + // Get bone, light, alias, and rotation matrices + float ****( *StudioGetBoneTransform ) ( void ); + float ****( *StudioGetLightTransform )( void ); + float ***( *StudioGetAliasTransform ) ( void ); + float ***( *StudioGetRotationMatrix ) ( void ); + + // Set up body part, and get submodel pointers + void ( *StudioSetupModel ) ( int bodypart, void **ppbodypart, void **ppsubmodel ); + // Check if entity's bbox is in the view frustum + int ( *StudioCheckBBox ) ( void ); + // Apply lighting effects to model + void ( *StudioDynamicLight ) ( struct cl_entity_s *ent, struct alight_s *plight ); + void ( *StudioEntityLight ) ( struct alight_s *plight ); + void ( *StudioSetupLighting ) ( struct alight_s *plighting ); + + // Draw mesh vertices + void ( *StudioDrawPoints ) ( void ); + + // Draw hulls around bones + void ( *StudioDrawHulls ) ( void ); + // Draw bbox around studio models + void ( *StudioDrawAbsBBox ) ( void ); + // Draws bones + void ( *StudioDrawBones ) ( void ); + // Loads in appropriate texture for model + void ( *StudioSetupSkin ) ( void *ptexturehdr, int index ); + // Sets up for remapped colors + void ( *StudioSetRemapColors ) ( int top, int bottom ); + // Set's player model and returns model pointer + struct model_s *( *SetupPlayerModel ) ( int index ); + // Fires any events embedded in animation + void ( *StudioClientEvents ) ( void ); + // Retrieve/set forced render effects flags + int ( *GetForceFaceFlags ) ( void ); + void ( *SetForceFaceFlags ) ( int flags ); + // Tell engine the value of the studio model header + void ( *StudioSetHeader ) ( void *header ); + // Tell engine which model_t * is being renderered + void ( *SetRenderModel ) ( struct model_s *model ); + + // Final state setup and restore for rendering + void ( *SetupRenderer ) ( int rendermode ); + void ( *RestoreRenderer ) ( void ); + + // Set render origin for applying chrome effect + void ( *SetChromeOrigin ) ( void ); + + // True if using D3D/OpenGL + int ( *IsHardware ) ( void ); + + // Only called by hardware interface + void ( *GL_StudioDrawShadow ) ( void ); + void ( *GL_SetRenderMode ) ( int mode ); + + void ( *StudioSetRenderamt ) (int iRenderamt); //!!!CZERO added for rendering glass on viewmodels + void ( *StudioSetCullState ) ( int iCull ); + void ( *StudioRenderShadow ) ( int iSprite, float *p1, float *p2, float *p3, float *p4 ); +} engine_studio_api_t; + +typedef struct server_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc ) ( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check ) ( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile ) ( char *path, struct cache_user_s *cu ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata ) ( struct model_s *mod ); +} server_studio_api_t; + + +// client blending +typedef struct r_studio_interface_s +{ + int version; + int ( *StudioDrawModel ) ( int flags ); + int ( *StudioDrawPlayer ) ( int flags, struct entity_state_s *pplayer ); +} r_studio_interface_t; + +extern r_studio_interface_t *pStudioAPI; + +// server blending +#define SV_BLENDING_INTERFACE_VERSION 1 + +typedef struct sv_blending_interface_s +{ + int version; + + void ( *SV_StudioSetupBones )( struct model_s *pModel, + float frame, + int sequence, + const vec3_t angles, + const vec3_t origin, + const byte *pcontroller, + const byte *pblending, + int iBone, + const edict_t *pEdict ); +} sv_blending_interface_t; + +#endif // R_STUDIOINT_H diff --git a/rehlds/common/ref_params.h b/rehlds/common/ref_params.h new file mode 100644 index 0000000..10e8837 --- /dev/null +++ b/rehlds/common/ref_params.h @@ -0,0 +1,75 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( REF_PARAMSH ) +#define REF_PARAMSH + +typedef struct ref_params_s +{ + // Output + float vieworg[3]; + float viewangles[3]; + + float forward[3]; + float right[3]; + float up[3]; + + // Client frametime; + float frametime; + // Client time + float time; + + // Misc + int intermission; + int paused; + int spectator; + int onground; + int waterlevel; + + float simvel[3]; + float simorg[3]; + + float viewheight[3]; + float idealpitch; + + float cl_viewangles[3]; + + int health; + float crosshairangle[3]; + float viewsize; + + float punchangle[3]; + int maxclients; + int viewentity; + int playernum; + int max_entities; + int demoplayback; + int hardware; + + int smoothing; + + // Last issued usercmd + struct usercmd_s *cmd; + + // Movevars + struct movevars_s *movevars; + + int viewport[4]; // the viewport coordinates x ,y , width, height + + int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview + // so long in cycles until this value is 0 (multiple views) + int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions +} ref_params_t; + +#endif // !REF_PARAMSH diff --git a/rehlds/common/screenfade.h b/rehlds/common/screenfade.h new file mode 100644 index 0000000..d1d7126 --- /dev/null +++ b/rehlds/common/screenfade.h @@ -0,0 +1,24 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( SCREENFADEH ) +#define SCREENFADEH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct screenfade_s +{ + float fadeSpeed; // How fast to fade (tics / second) (+ fade in, - fade out) + float fadeEnd; // When the fading hits maximum + float fadeTotalEnd; // Total End Time of the fade (used for FFADE_OUT) + float fadeReset; // When to reset to not fading (for fadeout and hold) + byte fader, fadeg, fadeb, fadealpha; // Fade color + int fadeFlags; // Fading flags +} screenfade_t; + +#endif // !SCREENFADEH diff --git a/rehlds/common/studio_event.h b/rehlds/common/studio_event.h new file mode 100644 index 0000000..5ecf24f --- /dev/null +++ b/rehlds/common/studio_event.h @@ -0,0 +1,29 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( STUDIO_EVENTH ) +#define STUDIO_EVENTH +#ifdef _WIN32 +#pragma once +#endif + +typedef struct mstudioevent_s +{ + int frame; + int event; + int type; + char options[64]; +} mstudioevent_t; + +#endif // STUDIO_EVENTH diff --git a/rehlds/common/triangleapi.h b/rehlds/common/triangleapi.h new file mode 100644 index 0000000..db2d849 --- /dev/null +++ b/rehlds/common/triangleapi.h @@ -0,0 +1,64 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( TRIANGLEAPIH ) +#define TRIANGLEAPIH +#ifdef _WIN32 +#pragma once +#endif + +typedef enum +{ + TRI_FRONT = 0, + TRI_NONE = 1, +} TRICULLSTYLE; + +#define TRI_API_VERSION 1 + +#define TRI_TRIANGLES 0 +#define TRI_TRIANGLE_FAN 1 +#define TRI_QUADS 2 +#define TRI_POLYGON 3 +#define TRI_LINES 4 +#define TRI_TRIANGLE_STRIP 5 +#define TRI_QUAD_STRIP 6 + +typedef struct triangleapi_s +{ + int version; + + void ( *RenderMode )( int mode ); + void ( *Begin )( int primitiveCode ); + void ( *End ) ( void ); + + void ( *Color4f ) ( float r, float g, float b, float a ); + void ( *Color4ub ) ( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); + void ( *TexCoord2f ) ( float u, float v ); + void ( *Vertex3fv ) ( float *worldPnt ); + void ( *Vertex3f ) ( float x, float y, float z ); + void ( *Brightness ) ( float brightness ); + void ( *CullFace ) ( TRICULLSTYLE style ); + int ( *SpriteTexture ) ( struct model_s *pSpriteModel, int frame ); + int ( *WorldToScreen ) ( float *world, float *screen ); // Returns 1 if it's z clipped + void ( *Fog ) ( float flFogColor[3], float flStart, float flEnd, int bOn ); // Works just like GL_FOG, flFogColor is r/g/b. + void ( *ScreenToWorld ) ( float *screen, float *world ); + void ( *GetMatrix ) ( const int pname, float *matrix ); + int ( *BoxInPVS ) ( float *mins, float *maxs ); + void ( *LightAtPoint ) ( float *pos, float *value ); + void ( *Color4fRendermode ) ( float r, float g, float b, float a, int rendermode ); + void ( *FogParams ) ( float flDensity, int iFogSkybox ); // Used with Fog()...sets fog density and whether the fog should be applied to the skybox + +} triangleapi_t; + +#endif // !TRIANGLEAPIH diff --git a/rehlds/common/usercmd.h b/rehlds/common/usercmd.h new file mode 100644 index 0000000..ab88ddb --- /dev/null +++ b/rehlds/common/usercmd.h @@ -0,0 +1,41 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef USERCMD_H +#define USERCMD_H +#ifdef _WIN32 +#pragma once +#endif + +typedef struct usercmd_s +{ + short lerp_msec; // Interpolation time on client + byte msec; // Duration in ms of command + vec3_t viewangles; // Command view angles. + +// intended velocities + float forwardmove; // Forward velocity. + float sidemove; // Sideways velocity. + float upmove; // Upward velocity. + byte lightlevel; // Light level at spot where we are standing. + unsigned short buttons; // Attack buttons + byte impulse; // Impulse command issued. + byte weaponselect; // Current weapon id + +// Experimental player impact stuff. + int impact_index; + vec3_t impact_position; +} usercmd_t; + +#endif // USERCMD_H diff --git a/rehlds/common/vmodes.h b/rehlds/common/vmodes.h new file mode 100644 index 0000000..43334d3 --- /dev/null +++ b/rehlds/common/vmodes.h @@ -0,0 +1,35 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + + +/* <430ee> ../common/vmodes.h:40 */ +typedef struct rect_s +{ + int left, right, top, bottom; +} wrect_t; diff --git a/rehlds/common/weaponinfo.h b/rehlds/common/weaponinfo.h new file mode 100644 index 0000000..5a601ba --- /dev/null +++ b/rehlds/common/weaponinfo.h @@ -0,0 +1,53 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef WEAPONINFO_H +#define WEAPONINFO_H +#ifdef _WIN32 +#pragma once +#endif + +// Info about weapons player might have in his/her possession +typedef struct weapon_data_s +{ + int m_iId; + int m_iClip; + + float m_flNextPrimaryAttack; + float m_flNextSecondaryAttack; + float m_flTimeWeaponIdle; + + int m_fInReload; + int m_fInSpecialReload; + float m_flNextReload; + float m_flPumpTime; + float m_fReloadTime; + + float m_fAimedDamage; + float m_fNextAimBonus; + int m_fInZoom; + int m_iWeaponState; + + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; +} weapon_data_t; + +#endif // WEAPONINFO_H diff --git a/rehlds/common/winsani_in.h b/rehlds/common/winsani_in.h new file mode 100644 index 0000000..e2bb599 --- /dev/null +++ b/rehlds/common/winsani_in.h @@ -0,0 +1,7 @@ +#if _MSC_VER >= 1500 // MSVC++ 9.0 (Visual Studio 2008) +#pragma push_macro("ARRAYSIZE") +#ifdef ARRAYSIZE +#undef ARRAYSIZE +#endif +#define HSPRITE WINDOWS_HSPRITE +#endif diff --git a/rehlds/common/winsani_out.h b/rehlds/common/winsani_out.h new file mode 100644 index 0000000..3d9cef0 --- /dev/null +++ b/rehlds/common/winsani_out.h @@ -0,0 +1,4 @@ +#if _MSC_VER >= 1500 // MSVC++ 9.0 (Visual Studio 2008) +#undef HSPRITE +#pragma pop_macro("ARRAYSIZE") +#endif diff --git a/rehlds/dlls/activity.h b/rehlds/dlls/activity.h new file mode 100644 index 0000000..37c82b6 --- /dev/null +++ b/rehlds/dlls/activity.h @@ -0,0 +1,109 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef ACTIVITY_H +#define ACTIVITY_H + + +typedef enum { + ACT_RESET = 0, // Set m_Activity to this invalid value to force a reset to m_IdealActivity + ACT_IDLE = 1, + ACT_GUARD, + ACT_WALK, + ACT_RUN, + ACT_FLY, // Fly (and flap if appropriate) + ACT_SWIM, + ACT_HOP, // vertical jump + ACT_LEAP, // long forward jump + ACT_FALL, + ACT_LAND, + ACT_STRAFE_LEFT, + ACT_STRAFE_RIGHT, + ACT_ROLL_LEFT, // tuck and roll, left + ACT_ROLL_RIGHT, // tuck and roll, right + ACT_TURN_LEFT, // turn quickly left (stationary) + ACT_TURN_RIGHT, // turn quickly right (stationary) + ACT_CROUCH, // the act of crouching down from a standing position + ACT_CROUCHIDLE, // holding body in crouched position (loops) + ACT_STAND, // the act of standing from a crouched position + ACT_USE, + ACT_SIGNAL1, + ACT_SIGNAL2, + ACT_SIGNAL3, + ACT_TWITCH, + ACT_COWER, + ACT_SMALL_FLINCH, + ACT_BIG_FLINCH, + ACT_RANGE_ATTACK1, + ACT_RANGE_ATTACK2, + ACT_MELEE_ATTACK1, + ACT_MELEE_ATTACK2, + ACT_RELOAD, + ACT_ARM, // pull out gun, for instance + ACT_DISARM, // reholster gun + ACT_EAT, // monster chowing on a large food item (loop) + ACT_DIESIMPLE, + ACT_DIEBACKWARD, + ACT_DIEFORWARD, + ACT_DIEVIOLENT, + ACT_BARNACLE_HIT, // barnacle tongue hits a monster + ACT_BARNACLE_PULL, // barnacle is lifting the monster ( loop ) + ACT_BARNACLE_CHOMP, // barnacle latches on to the monster + ACT_BARNACLE_CHEW, // barnacle is holding the monster in its mouth ( loop ) + ACT_SLEEP, + ACT_INSPECT_FLOOR, // for active idles, look at something on or near the floor + ACT_INSPECT_WALL, // for active idles, look at something directly ahead of you ( doesn't HAVE to be a wall or on a wall ) + ACT_IDLE_ANGRY, // alternate idle animation in which the monster is clearly agitated. (loop) + ACT_WALK_HURT, // limp (loop) + ACT_RUN_HURT, // limp (loop) + ACT_HOVER, // Idle while in flight + ACT_GLIDE, // Fly (don't flap) + ACT_FLY_LEFT, // Turn left in flight + ACT_FLY_RIGHT, // Turn right in flight + ACT_DETECT_SCENT, // this means the monster smells a scent carried by the air + ACT_SNIFF, // this is the act of actually sniffing an item in front of the monster + ACT_BITE, // some large monsters can eat small things in one bite. This plays one time, EAT loops. + ACT_THREAT_DISPLAY, // without attacking, monster demonstrates that it is angry. (Yell, stick out chest, etc ) + ACT_FEAR_DISPLAY, // monster just saw something that it is afraid of + ACT_EXCITED, // for some reason, monster is excited. Sees something he really likes to eat, or whatever. + ACT_SPECIAL_ATTACK1, // very monster specific special attacks. + ACT_SPECIAL_ATTACK2, + ACT_COMBAT_IDLE, // agitated idle. + ACT_WALK_SCARED, + ACT_RUN_SCARED, + ACT_VICTORY_DANCE, // killed a player, do a victory dance. + ACT_DIE_HEADSHOT, // die, hit in head. + ACT_DIE_CHESTSHOT, // die, hit in chest + ACT_DIE_GUTSHOT, // die, hit in gut + ACT_DIE_BACKSHOT, // die, hit in back + ACT_FLINCH_HEAD, + ACT_FLINCH_CHEST, + ACT_FLINCH_STOMACH, + ACT_FLINCH_LEFTARM, + ACT_FLINCH_RIGHTARM, + ACT_FLINCH_LEFTLEG, + ACT_FLINCH_RIGHTLEG, +} Activity; + + +typedef struct { + int type; + char *name; +} activity_map_t; + +extern activity_map_t activity_map[]; + + +#endif //ACTIVITY_H diff --git a/rehlds/dlls/activitymap.h b/rehlds/dlls/activitymap.h new file mode 100644 index 0000000..b72c4e4 --- /dev/null +++ b/rehlds/dlls/activitymap.h @@ -0,0 +1,97 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#define _A( a ) { a, #a } + +activity_map_t activity_map[] = +{ +_A( ACT_IDLE ), +_A( ACT_GUARD ), +_A( ACT_WALK ), +_A( ACT_RUN ), +_A( ACT_FLY ), +_A( ACT_SWIM ), +_A( ACT_HOP ), +_A( ACT_LEAP ), +_A( ACT_FALL ), +_A( ACT_LAND ), +_A( ACT_STRAFE_LEFT ), +_A( ACT_STRAFE_RIGHT ), +_A( ACT_ROLL_LEFT ), +_A( ACT_ROLL_RIGHT ), +_A( ACT_TURN_LEFT ), +_A( ACT_TURN_RIGHT ), +_A( ACT_CROUCH ), +_A( ACT_CROUCHIDLE ), +_A( ACT_STAND ), +_A( ACT_USE ), +_A( ACT_SIGNAL1 ), +_A( ACT_SIGNAL2 ), +_A( ACT_SIGNAL3 ), +_A( ACT_TWITCH ), +_A( ACT_COWER ), +_A( ACT_SMALL_FLINCH ), +_A( ACT_BIG_FLINCH ), +_A( ACT_RANGE_ATTACK1 ), +_A( ACT_RANGE_ATTACK2 ), +_A( ACT_MELEE_ATTACK1 ), +_A( ACT_MELEE_ATTACK2 ), +_A( ACT_RELOAD ), +_A( ACT_ARM ), +_A( ACT_DISARM ), +_A( ACT_EAT ), +_A( ACT_DIESIMPLE ), +_A( ACT_DIEBACKWARD ), +_A( ACT_DIEFORWARD ), +_A( ACT_DIEVIOLENT ), +_A( ACT_BARNACLE_HIT ), +_A( ACT_BARNACLE_PULL ), +_A( ACT_BARNACLE_CHOMP ), +_A( ACT_BARNACLE_CHEW ), +_A( ACT_SLEEP ), +_A( ACT_INSPECT_FLOOR ), +_A( ACT_INSPECT_WALL ), +_A( ACT_IDLE_ANGRY ), +_A( ACT_WALK_HURT ), +_A( ACT_RUN_HURT ), +_A( ACT_HOVER ), +_A( ACT_GLIDE ), +_A( ACT_FLY_LEFT ), +_A( ACT_FLY_RIGHT ), +_A( ACT_DETECT_SCENT ), +_A( ACT_SNIFF ), +_A( ACT_BITE ), +_A( ACT_THREAT_DISPLAY ), +_A( ACT_FEAR_DISPLAY ), +_A( ACT_EXCITED ), +_A( ACT_SPECIAL_ATTACK1 ), +_A( ACT_SPECIAL_ATTACK2 ), +_A( ACT_COMBAT_IDLE ), +_A( ACT_WALK_SCARED ), +_A( ACT_RUN_SCARED ), +_A( ACT_VICTORY_DANCE ), +_A( ACT_DIE_HEADSHOT ), +_A( ACT_DIE_CHESTSHOT ), +_A( ACT_DIE_GUTSHOT ), +_A( ACT_DIE_BACKSHOT ), +_A( ACT_FLINCH_HEAD ), +_A( ACT_FLINCH_CHEST ), +_A( ACT_FLINCH_STOMACH ), +_A( ACT_FLINCH_LEFTARM ), +_A( ACT_FLINCH_RIGHTARM ), +_A( ACT_FLINCH_LEFTLEG ), +_A( ACT_FLINCH_RIGHTLEG ), +0, NULL +}; diff --git a/rehlds/dlls/animation.h b/rehlds/dlls/animation.h new file mode 100644 index 0000000..7728167 --- /dev/null +++ b/rehlds/dlls/animation.h @@ -0,0 +1,47 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef ANIMATION_H +#define ANIMATION_H + +#define ACTIVITY_NOT_AVAILABLE -1 + +#ifndef MONSTEREVENT_H +#include "monsterevent.h" +#endif + +extern int IsSoundEvent( int eventNumber ); + +int LookupActivity( void *pmodel, entvars_t *pev, int activity ); +int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ); +int LookupSequence( void *pmodel, const char *label ); +void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed ); +int GetSequenceFlags( void *pmodel, entvars_t *pev ); +int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd ); +float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ); +float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ); +void GetEyePosition( void *pmodel, float *vecEyePosition ); +void SequencePrecache( void *pmodel, const char *pSequenceName ); +int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ); +void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ); +int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ); + +int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ); +int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ); + +// From /engine/studio.h +#define STUDIO_LOOPING 0x0001 + + +#endif //ANIMATION_H diff --git a/rehlds/dlls/basemonster.h b/rehlds/dlls/basemonster.h new file mode 100644 index 0000000..280e467 --- /dev/null +++ b/rehlds/dlls/basemonster.h @@ -0,0 +1,94 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef BASEMONSTER_H +#define BASEMONSTER_H + +class CBaseMonster : public CBaseToggle +{ +public: + Activity m_Activity;// what the monster is doing (animation) + Activity m_IdealActivity;// monster should switch to this activity + int m_LastHitGroup; // the last body region that took damage + int m_bitsDamageType; // what types of damage has monster (player) taken + BYTE m_rgbTimeBasedDamage[CDMG_TIMEBASED]; + MONSTERSTATE m_MonsterState;// monster's current state + MONSTERSTATE m_IdealMonsterState;// monster should change to this state + int m_afConditions; + int m_afMemory; + float m_flNextAttack; // cannot attack again until this time + EHANDLE m_hEnemy; // the entity that the monster is fighting. + EHANDLE m_hTargetEnt; // the entity that the monster is trying to reach + float m_flFieldOfView;// width of monster's field of view ( dot product ) + int m_bloodColor; // color of blood particless + Vector m_HackedGunPos; // HACK until we can query end of gun + Vector m_vecEnemyLKP;// last known position of enemy. (enemy's origin) + + + void KeyValue( KeyValueData *pkvd ); + + void MakeIdealYaw( Vector vecTarget ); + virtual float ChangeYaw ( int speed ); + virtual BOOL HasHumanGibs( void ); + virtual BOOL HasAlienGibs( void ); + virtual void FadeMonster( void ); // Called instead of GibMonster() when gibs are disabled + virtual void GibMonster( void ); + virtual Activity GetDeathActivity ( void ); + Activity GetSmallFlinchActivity( void ); + virtual void BecomeDead( void ); + BOOL ShouldGibMonster( int iGib ); + void CallGibMonster( void ); + virtual BOOL ShouldFadeOnDeath( void ); + BOOL FCheckAITrigger( void );// checks and, if necessary, fires the monster's trigger target. + virtual int IRelationship ( CBaseEntity *pTarget ); + virtual int TakeHealth( float flHealth, int bitsDamageType ); + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + int DeadTakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + float DamageForce( float damage ); + virtual void Killed( entvars_t *pevAttacker, int iGib ); + virtual void PainSound ( void ) { return; }; + + void RadiusDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); + void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ); + + inline void SetConditions( int iConditions ) { m_afConditions |= iConditions; } + inline void ClearConditions( int iConditions ) { m_afConditions &= ~iConditions; } + inline BOOL HasConditions( int iConditions ) { if ( m_afConditions & iConditions ) return TRUE; return FALSE; } + inline BOOL HasAllConditions( int iConditions ) { if ( (m_afConditions & iConditions) == iConditions ) return TRUE; return FALSE; } + + inline void Remember( int iMemory ) { m_afMemory |= iMemory; } + inline void Forget( int iMemory ) { m_afMemory &= ~iMemory; } + inline BOOL HasMemory( int iMemory ) { if ( m_afMemory & iMemory ) return TRUE; return FALSE; } + inline BOOL HasAllMemories( int iMemory ) { if ( (m_afMemory & iMemory) == iMemory ) return TRUE; return FALSE; } + + // This will stop animation until you call ResetSequenceInfo() at some point in the future + inline void StopAnimation( void ) { pev->framerate = 0; } + + virtual void ReportAIState( void ); + virtual void MonsterInitDead( void ); // Call after animation/pose is set up + void EXPORT CorpseFallThink( void ); + + virtual void Look ( int iDistance );// basic sight function for monsters + virtual CBaseEntity* BestVisibleEnemy ( void );// finds best visible enemy for attack + CBaseEntity *CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ); + virtual BOOL FInViewCone ( CBaseEntity *pEntity );// see if pEntity is in monster's view cone + virtual BOOL FInViewCone ( Vector *pOrigin );// see if given location is in monster's view cone + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + void MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ); + virtual BOOL IsAlive( void ) { return (pev->deadflag != DEAD_DEAD); } + +}; + + +#endif diff --git a/rehlds/dlls/cbase.h b/rehlds/dlls/cbase.h new file mode 100644 index 0000000..6bc9669 --- /dev/null +++ b/rehlds/dlls/cbase.h @@ -0,0 +1,802 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +/* + +Class Hierachy + +CBaseEntity + CBaseDelay + CBaseToggle + CBaseItem + CBaseMonster + CBaseCycler + CBasePlayer + CBaseGroup +*/ + +#define MAX_PATH_SIZE 10 // max number of nodes available for a path. + +// These are caps bits to indicate what an object's capabilities (currently used for save/restore and level transitions) +#define FCAP_CUSTOMSAVE 0x00000001 +#define FCAP_ACROSS_TRANSITION 0x00000002 // should transfer between transitions +#define FCAP_MUST_SPAWN 0x00000004 // Spawn after restore +#define FCAP_DONT_SAVE 0x80000000 // Don't save this +#define FCAP_IMPULSE_USE 0x00000008 // can be used by the player +#define FCAP_CONTINUOUS_USE 0x00000010 // can be used by the player +#define FCAP_ONOFF_USE 0x00000020 // can be used by the player +#define FCAP_DIRECTIONAL_USE 0x00000040 // Player sends +/- 1 when using (currently only tracktrains) +#define FCAP_MASTER 0x00000080 // Can be used to "master" other entities (like multisource) + +// UNDONE: This will ignore transition volumes (trigger_transition), but not the PVS!!! +#define FCAP_FORCE_TRANSITION 0x00000080 // ALWAYS goes across transitions + +#include "archtypes.h" // DAL +#include "saverestore.h" +#include "schedule.h" + +#ifndef MONSTEREVENT_H +#include "monsterevent.h" +#endif + +// C functions for external declarations that call the appropriate C++ methods + +#ifndef CBASE_DLLEXPORT +#ifdef _WIN32 +#define CBASE_DLLEXPORT _declspec( dllexport ) +#else +#define CBASE_DLLEXPORT __attribute__ ((visibility("default"))) +#endif +#endif + +#define EXPORT CBASE_DLLEXPORT + +extern "C" CBASE_DLLEXPORT int GetEntityAPI( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); +extern "C" CBASE_DLLEXPORT int GetEntityAPI2( DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion ); + +extern int DispatchSpawn( edict_t *pent ); +extern void DispatchKeyValue( edict_t *pentKeyvalue, KeyValueData *pkvd ); +extern void DispatchTouch( edict_t *pentTouched, edict_t *pentOther ); +extern void DispatchUse( edict_t *pentUsed, edict_t *pentOther ); +extern void DispatchThink( edict_t *pent ); +extern void DispatchBlocked( edict_t *pentBlocked, edict_t *pentOther ); +extern void DispatchSave( edict_t *pent, SAVERESTOREDATA *pSaveData ); +extern int DispatchRestore( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); +extern void DispatchObjectCollsionBox( edict_t *pent ); +extern void SaveWriteFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); +extern void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); +extern void SaveGlobalState( SAVERESTOREDATA *pSaveData ); +extern void RestoreGlobalState( SAVERESTOREDATA *pSaveData ); +extern void ResetGlobalState( void ); + +typedef enum { USE_OFF = 0, USE_ON = 1, USE_SET = 2, USE_TOGGLE = 3 } USE_TYPE; + +extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +typedef void (CBaseEntity::*BASEPTR)(void); +typedef void (CBaseEntity::*ENTITYFUNCPTR)(CBaseEntity *pOther ); +typedef void (CBaseEntity::*USEPTR)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + +// For CLASSIFY +#define CLASS_NONE 0 +#define CLASS_MACHINE 1 +#define CLASS_PLAYER 2 +#define CLASS_HUMAN_PASSIVE 3 +#define CLASS_HUMAN_MILITARY 4 +#define CLASS_ALIEN_MILITARY 5 +#define CLASS_ALIEN_PASSIVE 6 +#define CLASS_ALIEN_MONSTER 7 +#define CLASS_ALIEN_PREY 8 +#define CLASS_ALIEN_PREDATOR 9 +#define CLASS_INSECT 10 +#define CLASS_PLAYER_ALLY 11 +#define CLASS_PLAYER_BIOWEAPON 12 // hornets and snarks.launched by players +#define CLASS_ALIEN_BIOWEAPON 13 // hornets and snarks.launched by the alien menace +#define CLASS_BARNACLE 99 // special because no one pays attention to it, and it eats a wide cross-section of creatures. + +class CBaseEntity; +class CBaseMonster; +class CBasePlayerItem; +class CSquadMonster; + + +#define SF_NORESPAWN ( 1 << 30 )// !!!set this bit on guns and stuff that should never respawn. + +// +// EHANDLE. Safe way to point to CBaseEntities who may die between frames +// +class EHANDLE +{ +private: + edict_t *m_pent; + int m_serialnumber; +public: + edict_t *Get( void ); + edict_t *Set( edict_t *pent ); + + operator int (); + + operator CBaseEntity *(); + + CBaseEntity * operator = (CBaseEntity *pEntity); + CBaseEntity * operator ->(); +}; + + +// +// Base Entity. All entity types derive from this +// +class CBaseEntity +{ +public: + // Constructor. Set engine to use C/C++ callback functions + // pointers to engine data + entvars_t *pev; // Don't need to save/restore this pointer, the engine resets it + + // path corners + CBaseEntity *m_pGoalEnt;// path corner we are heading towards + CBaseEntity *m_pLink;// used for temporary link-list operations. + + // initialization functions + virtual void Spawn( void ) { return; } + virtual void Precache( void ) { return; } + virtual void KeyValue( KeyValueData* pkvd) { pkvd->fHandled = FALSE; } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + virtual int ObjectCaps( void ) { return FCAP_ACROSS_TRANSITION; } + virtual void Activate( void ) {} + + // Setup the object->object collision box (pev->mins / pev->maxs is the object->world collision box) + virtual void SetObjectCollisionBox( void ); + +// Classify - returns the type of group (i.e, "houndeye", or "human military" so that monsters with different classnames +// still realize that they are teammates. (overridden for monsters that form groups) + virtual int Classify ( void ) { return CLASS_NONE; }; + virtual void DeathNotice ( entvars_t *pevChild ) {}// monster maker children use this to tell the monster maker that they have died. + + + static TYPEDESCRIPTION m_SaveData[]; + + virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + virtual int TakeHealth( float flHealth, int bitsDamageType ); + virtual void Killed( entvars_t *pevAttacker, int iGib ); + virtual int BloodColor( void ) { return DONT_BLEED; } + virtual void TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); + virtual BOOL IsTriggered( CBaseEntity *pActivator ) {return TRUE;} + virtual CBaseMonster *MyMonsterPointer( void ) { return NULL;} + virtual CSquadMonster *MySquadMonsterPointer( void ) { return NULL;} + virtual int GetToggleState( void ) { return TS_AT_TOP; } + virtual void AddPoints( int score, BOOL bAllowNegativeScore ) {} + virtual void AddPointsToTeam( int score, BOOL bAllowNegativeScore ) {} + virtual BOOL AddPlayerItem( CBasePlayerItem *pItem ) { return 0; } + virtual BOOL RemovePlayerItem( CBasePlayerItem *pItem ) { return 0; } + virtual int GiveAmmo( int iAmount, char *szName, int iMax ) { return -1; }; + virtual float GetDelay( void ) { return 0; } + virtual int IsMoving( void ) { return pev->velocity != g_vecZero; } + virtual void OverrideReset( void ) {} + virtual int DamageDecal( int bitsDamageType ); + // This is ONLY used by the node graph to test movement through a door + virtual void SetToggleState( int state ) {} + virtual void StartSneaking( void ) {} + virtual void StopSneaking( void ) {} + virtual BOOL OnControls( entvars_t *pev ) { return FALSE; } + virtual BOOL IsSneaking( void ) { return FALSE; } + virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; } + virtual BOOL IsBSPModel( void ) { return pev->solid == SOLID_BSP || pev->movetype == MOVETYPE_PUSHSTEP; } + virtual BOOL ReflectGauss( void ) { return ( IsBSPModel() && !pev->takedamage ); } + virtual BOOL HasTarget( string_t targetname ) { return FStrEq(STRING(targetname), STRING(pev->targetname) ); } + virtual BOOL IsInWorld( void ); + virtual BOOL IsPlayer( void ) { return FALSE; } + virtual BOOL IsNetClient( void ) { return FALSE; } + virtual const char *TeamID( void ) { return ""; } + + +// virtual void SetActivator( CBaseEntity *pActivator ) {} + virtual CBaseEntity *GetNextTarget( void ); + + // fundamental callbacks + void (CBaseEntity ::*m_pfnThink)(void); + void (CBaseEntity ::*m_pfnTouch)( CBaseEntity *pOther ); + void (CBaseEntity ::*m_pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void (CBaseEntity ::*m_pfnBlocked)( CBaseEntity *pOther ); + + virtual void Think( void ) { if (m_pfnThink) (this->*m_pfnThink)(); }; + virtual void Touch( CBaseEntity *pOther ) { if (m_pfnTouch) (this->*m_pfnTouch)( pOther ); }; + virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) + { + if (m_pfnUse) + (this->*m_pfnUse)( pActivator, pCaller, useType, value ); + } + virtual void Blocked( CBaseEntity *pOther ) { if (m_pfnBlocked) (this->*m_pfnBlocked)( pOther ); }; + + // allow engine to allocate instance data + void *operator new( size_t stAllocateBlock, entvars_t *pev ) + { + return (void *)ALLOC_PRIVATE(ENT(pev), stAllocateBlock); + }; + + // don't use this. +#if _MSC_VER >= 1200 // only build this code if MSVC++ 6.0 or higher + void operator delete(void *pMem, entvars_t *pev) + { + pev->flags |= FL_KILLME; + }; +#endif + + void UpdateOnRemove( void ); + + // common member functions + void EXPORT SUB_Remove( void ); + void EXPORT SUB_DoNothing( void ); + void EXPORT SUB_StartFadeOut ( void ); + void EXPORT SUB_FadeOut ( void ); + void EXPORT SUB_CallUseToggle( void ) { this->Use( this, this, USE_TOGGLE, 0 ); } + int ShouldToggle( USE_TYPE useType, BOOL currentState ); + void FireBullets( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL ); + Vector FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq = 4, int iDamage = 0, entvars_t *pevAttacker = NULL, int shared_rand = 0 ); + + virtual CBaseEntity *Respawn( void ) { return NULL; } + + void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ); + // Do the bounding boxes of these two intersect? + int Intersects( CBaseEntity *pOther ); + void MakeDormant( void ); + int IsDormant( void ); + BOOL IsLockedByMaster( void ) { return FALSE; } + + static CBaseEntity *Instance( edict_t *pent ) + { + if ( !pent ) + pent = ENT(0); + CBaseEntity *pEnt = (CBaseEntity *)GET_PRIVATE(pent); + return pEnt; + } + + static CBaseEntity *Instance( entvars_t *pev ) { return Instance( ENT( pev ) ); } + static CBaseEntity *Instance( int eoffset) { return Instance( ENT( eoffset) ); } + + CBaseMonster *GetMonsterPointer( entvars_t *pevMonster ) + { + CBaseEntity *pEntity = Instance( pevMonster ); + if ( pEntity ) + return pEntity->MyMonsterPointer(); + return NULL; + } + CBaseMonster *GetMonsterPointer( edict_t *pentMonster ) + { + CBaseEntity *pEntity = Instance( pentMonster ); + if ( pEntity ) + return pEntity->MyMonsterPointer(); + return NULL; + } + + + // Ugly code to lookup all functions to make sure they are exported when set. +#ifdef _DEBUG + void FunctionCheck( void *pFunction, char *name ) + { + if (pFunction && !NAME_FOR_FUNCTION((uint32)pFunction) ) + ALERT( at_error, "No EXPORT: %s:%s (%08lx)\n", STRING(pev->classname), name, (uint32)pFunction ); + } + + BASEPTR ThinkSet( BASEPTR func, char *name ) + { + m_pfnThink = func; + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnThink)))), name ); + return func; + } + ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) + { + m_pfnTouch = func; + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnTouch)))), name ); + return func; + } + USEPTR UseSet( USEPTR func, char *name ) + { + m_pfnUse = func; + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnUse)))), name ); + return func; + } + ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) + { + m_pfnBlocked = func; + FunctionCheck( (void *)*((int *)((char *)this + ( offsetof(CBaseEntity,m_pfnBlocked)))), name ); + return func; + } + +#endif + + + // virtual functions used by a few classes + + // used by monsters that are created by the MonsterMaker + virtual void UpdateOwner( void ) { return; }; + + + // + static CBaseEntity *Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner = NULL ); + + virtual BOOL FBecomeProne( void ) {return FALSE;}; + edict_t *edict() { return ENT( pev ); }; + EOFFSET eoffset( ) { return OFFSET( pev ); }; + int entindex( ) { return ENTINDEX( edict() ); }; + + virtual Vector Center( ) { return (pev->absmax + pev->absmin) * 0.5; }; // center point of entity + virtual Vector EyePosition( ) { return pev->origin + pev->view_ofs; }; // position of eyes + virtual Vector EarPosition( ) { return pev->origin + pev->view_ofs; }; // position of ears + virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ); }; // position to shoot at + + virtual int Illumination( ) { return GETENTITYILLUM( ENT( pev ) ); }; + + virtual BOOL FVisible ( CBaseEntity *pEntity ); + virtual BOOL FVisible ( const Vector &vecOrigin ); + + //We use this variables to store each ammo count. + int ammo_9mm; + int ammo_357; + int ammo_bolts; + int ammo_buckshot; + int ammo_rockets; + int ammo_uranium; + int ammo_hornets; + int ammo_argrens; + //Special stuff for grenades and satchels. + float m_flStartThrow; + float m_flReleaseThrow; + int m_chargeReady; + int m_fInAttack; + + enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; + int m_fireState; +}; + + + +// Ugly technique to override base member functions +// Normally it's illegal to cast a pointer to a member function of a derived class to a pointer to a +// member function of a base class. static_cast is a sleezy way around that problem. + +#ifdef _DEBUG + +#define SetThink( a ) ThinkSet( static_cast (a), #a ) +#define SetTouch( a ) TouchSet( static_cast (a), #a ) +#define SetUse( a ) UseSet( static_cast (a), #a ) +#define SetBlocked( a ) BlockedSet( static_cast (a), #a ) + +#else + +#define SetThink( a ) m_pfnThink = static_cast (a) +#define SetTouch( a ) m_pfnTouch = static_cast (a) +#define SetUse( a ) m_pfnUse = static_cast (a) +#define SetBlocked( a ) m_pfnBlocked = static_cast (a) + +#endif + + +class CPointEntity : public CBaseEntity +{ +public: + void Spawn( void ); + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } +private: +}; + + +typedef struct locksounds // sounds that doors and buttons make when locked/unlocked +{ + string_t sLockedSound; // sound a door makes when it's locked + string_t sLockedSentence; // sentence group played when door is locked + string_t sUnlockedSound; // sound a door makes when it's unlocked + string_t sUnlockedSentence; // sentence group played when door is unlocked + + int iLockedSentence; // which sentence in sentence group to play next + int iUnlockedSentence; // which sentence in sentence group to play next + + float flwaitSound; // time delay between playing consecutive 'locked/unlocked' sounds + float flwaitSentence; // time delay between playing consecutive sentences + BYTE bEOFLocked; // true if hit end of list of locked sentences + BYTE bEOFUnlocked; // true if hit end of list of unlocked sentences +} locksound_t; + +void PlayLockSounds(entvars_t *pev, locksound_t *pls, int flocked, int fbutton); + +// +// MultiSouce +// + +#define MAX_MULTI_TARGETS 16 // maximum number of targets a single multi_manager entity may be assigned. +#define MS_MAX_TARGETS 32 + +class CMultiSource : public CPointEntity +{ +public: + void Spawn( ); + void KeyValue( KeyValueData *pkvd ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int ObjectCaps( void ) { return (CPointEntity::ObjectCaps() | FCAP_MASTER); } + BOOL IsTriggered( CBaseEntity *pActivator ); + void EXPORT Register( void ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + EHANDLE m_rgEntities[MS_MAX_TARGETS]; + int m_rgTriggered[MS_MAX_TARGETS]; + + int m_iTotal; + string_t m_globalstate; +}; + + +// +// generic Delay entity. +// +class CBaseDelay : public CBaseEntity +{ +public: + float m_flDelay; + int m_iszKillTarget; + + virtual void KeyValue( KeyValueData* pkvd); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + // common member functions + void SUB_UseTargets( CBaseEntity *pActivator, USE_TYPE useType, float value ); + void EXPORT DelayThink( void ); +}; + + +class CBaseAnimating : public CBaseDelay +{ +public: + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + // Basic Monster Animation functions + float StudioFrameAdvance( float flInterval = 0.0 ); // accumulate animation frame time from last time called until now + int GetSequenceFlags( void ); + int LookupActivity ( int activity ); + int LookupActivityHeaviest ( int activity ); + int LookupSequence ( const char *label ); + void ResetSequenceInfo ( ); + void DispatchAnimEvents ( float flFutureInterval = 0.1 ); // Handle events that have happend since last time called up until X seconds into the future + virtual void HandleAnimEvent( MonsterEvent_t *pEvent ) { return; }; + float SetBoneController ( int iController, float flValue ); + void InitBoneControllers ( void ); + float SetBlending ( int iBlender, float flValue ); + void GetBonePosition ( int iBone, Vector &origin, Vector &angles ); + void GetAutomovement( Vector &origin, Vector &angles, float flInterval = 0.1 ); + int FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ); + void GetAttachment ( int iAttachment, Vector &origin, Vector &angles ); + void SetBodygroup( int iGroup, int iValue ); + int GetBodygroup( int iGroup ); + int ExtractBbox( int sequence, float *mins, float *maxs ); + void SetSequenceBox( void ); + + // animation needs + float m_flFrameRate; // computed FPS for current sequence + float m_flGroundSpeed; // computed linear movement rate for current sequence + float m_flLastEventCheck; // last time the event list was checked + BOOL m_fSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry + BOOL m_fSequenceLoops; // true if the sequence loops +}; + + +// +// generic Toggle entity. +// +#define SF_ITEM_USE_ONLY 256 // ITEM_USE_ONLY = BUTTON_USE_ONLY = DOOR_USE_ONLY!!! + +class CBaseToggle : public CBaseAnimating +{ +public: + void KeyValue( KeyValueData *pkvd ); + + TOGGLE_STATE m_toggle_state; + float m_flActivateFinished;//like attack_finished, but for doors + float m_flMoveDistance;// how far a door should slide or rotate + float m_flWait; + float m_flLip; + float m_flTWidth;// for plats + float m_flTLength;// for plats + + Vector m_vecPosition1; + Vector m_vecPosition2; + Vector m_vecAngle1; + Vector m_vecAngle2; + + int m_cTriggersLeft; // trigger_counter only, # of activations remaining + float m_flHeight; + EHANDLE m_hActivator; + void (CBaseToggle::*m_pfnCallWhenMoveDone)(void); + Vector m_vecFinalDest; + Vector m_vecFinalAngle; + + int m_bitsDamageInflict; // DMG_ damage type that the door or tigger does + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + + virtual int GetToggleState( void ) { return m_toggle_state; } + virtual float GetDelay( void ) { return m_flWait; } + + // common member functions + void LinearMove( Vector vecDest, float flSpeed ); + void EXPORT LinearMoveDone( void ); + void AngularMove( Vector vecDestAngle, float flSpeed ); + void EXPORT AngularMoveDone( void ); + BOOL IsLockedByMaster( void ); + + static float AxisValue( int flags, const Vector &angles ); + static void AxisDir( entvars_t *pev ); + static float AxisDelta( int flags, const Vector &angle1, const Vector &angle2 ); + + string_t m_sMaster; // If this button has a master switch, this is the targetname. + // A master switch must be of the multisource type. If all + // of the switches in the multisource have been triggered, then + // the button will be allowed to operate. Otherwise, it will be + // deactivated. +}; +#define SetMoveDone( a ) m_pfnCallWhenMoveDone = static_cast (a) + + +// people gib if their health is <= this at the time of death +#define GIB_HEALTH_VALUE -30 + +#define ROUTE_SIZE 8 // how many waypoints a monster can store at one time +#define MAX_OLD_ENEMIES 4 // how many old enemies to remember + +#define bits_CAP_DUCK ( 1 << 0 )// crouch +#define bits_CAP_JUMP ( 1 << 1 )// jump/leap +#define bits_CAP_STRAFE ( 1 << 2 )// strafe ( walk/run sideways) +#define bits_CAP_SQUAD ( 1 << 3 )// can form squads +#define bits_CAP_SWIM ( 1 << 4 )// proficiently navigate in water +#define bits_CAP_CLIMB ( 1 << 5 )// climb ladders/ropes +#define bits_CAP_USE ( 1 << 6 )// open doors/push buttons/pull levers +#define bits_CAP_HEAR ( 1 << 7 )// can hear forced sounds +#define bits_CAP_AUTO_DOORS ( 1 << 8 )// can trigger auto doors +#define bits_CAP_OPEN_DOORS ( 1 << 9 )// can open manual doors +#define bits_CAP_TURN_HEAD ( 1 << 10)// can turn head, always bone controller 0 + +#define bits_CAP_RANGE_ATTACK1 ( 1 << 11)// can do a range attack 1 +#define bits_CAP_RANGE_ATTACK2 ( 1 << 12)// can do a range attack 2 +#define bits_CAP_MELEE_ATTACK1 ( 1 << 13)// can do a melee attack 1 +#define bits_CAP_MELEE_ATTACK2 ( 1 << 14)// can do a melee attack 2 + +#define bits_CAP_FLY ( 1 << 15)// can fly, move all around + +#define bits_CAP_DOORS_GROUP (bits_CAP_USE | bits_CAP_AUTO_DOORS | bits_CAP_OPEN_DOORS) + +// used by suit voice to indicate damage sustained and repaired type to player + +// instant damage + +#define DMG_GENERIC 0 // generic damage was done +#define DMG_CRUSH (1 << 0) // crushed by falling or moving object +#define DMG_BULLET (1 << 1) // shot +#define DMG_SLASH (1 << 2) // cut, clawed, stabbed +#define DMG_BURN (1 << 3) // heat burned +#define DMG_FREEZE (1 << 4) // frozen +#define DMG_FALL (1 << 5) // fell too far +#define DMG_BLAST (1 << 6) // explosive blast damage +#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt +#define DMG_SHOCK (1 << 8) // electric shock +#define DMG_SONIC (1 << 9) // sound pulse shockwave +#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam +#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death +#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death. +#define DMG_DROWN (1 << 14) // Drowning +// time-based damage +#define DMG_TIMEBASED (~(0x3fff)) // mask for time-based damage + +#define DMG_PARALYZE (1 << 15) // slows affected creature down +#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad +#define DMG_POISON (1 << 17) // blood poisioning +#define DMG_RADIATION (1 << 18) // radiation exposure +#define DMG_DROWNRECOVER (1 << 19) // drowning recovery +#define DMG_ACID (1 << 20) // toxic chemicals or acid burns +#define DMG_SLOWBURN (1 << 21) // in an oven +#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer +#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) + +// these are the damage types that are allowed to gib corpses +#define DMG_GIB_CORPSE ( DMG_CRUSH | DMG_FALL | DMG_BLAST | DMG_SONIC | DMG_CLUB ) + +// these are the damage types that have client hud art +#define DMG_SHOWNHUD (DMG_POISON | DMG_ACID | DMG_FREEZE | DMG_SLOWFREEZE | DMG_DROWN | DMG_BURN | DMG_SLOWBURN | DMG_NERVEGAS | DMG_RADIATION | DMG_SHOCK) + +// NOTE: tweak these values based on gameplay feedback: + +#define PARALYZE_DURATION 2 // number of 2 second intervals to take damage +#define PARALYZE_DAMAGE 1.0 // damage to take each 2 second interval + +#define NERVEGAS_DURATION 2 +#define NERVEGAS_DAMAGE 5.0 + +#define POISON_DURATION 5 +#define POISON_DAMAGE 2.0 + +#define RADIATION_DURATION 2 +#define RADIATION_DAMAGE 1.0 + +#define ACID_DURATION 2 +#define ACID_DAMAGE 5.0 + +#define SLOWBURN_DURATION 2 +#define SLOWBURN_DAMAGE 1.0 + +#define SLOWFREEZE_DURATION 2 +#define SLOWFREEZE_DAMAGE 1.0 + + +#define itbd_Paralyze 0 +#define itbd_NerveGas 1 +#define itbd_Poison 2 +#define itbd_Radiation 3 +#define itbd_DrownRecover 4 +#define itbd_Acid 5 +#define itbd_SlowBurn 6 +#define itbd_SlowFreeze 7 +#define CDMG_TIMEBASED 8 + +// when calling KILLED(), a value that governs gib behavior is expected to be +// one of these three values +#define GIB_NORMAL 0// gib if entity was overkilled +#define GIB_NEVER 1// never gib, no matter how much death damage is done ( freezing, etc ) +#define GIB_ALWAYS 2// always gib ( Houndeye Shock, Barnacle Bite ) + +class CBaseMonster; +class CCineMonster; +class CSound; + +#include "basemonster.h" + + +char *ButtonSound( int sound ); // get string of button sound number + + +// +// Generic Button +// +class CBaseButton : public CBaseToggle +{ +public: + void Spawn( void ); + virtual void Precache( void ); + void RotSpawn( void ); + virtual void KeyValue( KeyValueData* pkvd); + + void ButtonActivate( ); + void SparkSoundCache( void ); + + void EXPORT ButtonShot( void ); + void EXPORT ButtonTouch( CBaseEntity *pOther ); + void EXPORT ButtonSpark ( void ); + void EXPORT TriggerAndWait( void ); + void EXPORT ButtonReturn( void ); + void EXPORT ButtonBackHome( void ); + void EXPORT ButtonUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + enum BUTTON_CODE { BUTTON_NOTHING, BUTTON_ACTIVATE, BUTTON_RETURN }; + BUTTON_CODE ButtonResponseToTouch( void ); + + static TYPEDESCRIPTION m_SaveData[]; + // Buttons that don't take damage can be IMPULSE used + virtual int ObjectCaps( void ) { return (CBaseToggle:: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | (pev->takedamage?0:FCAP_IMPULSE_USE); } + + BOOL m_fStayPushed; // button stays pushed in until touched again? + BOOL m_fRotating; // a rotating button? default is a sliding button. + + string_t m_strChangeTarget; // if this field is not null, this is an index into the engine string array. + // when this button is touched, it's target entity's TARGET field will be set + // to the button's ChangeTarget. This allows you to make a func_train switch paths, etc. + + locksound_t m_ls; // door lock sounds + + BYTE m_bLockedSound; // ordinals from entity selection + BYTE m_bLockedSentence; + BYTE m_bUnlockedSound; + BYTE m_bUnlockedSentence; + int m_sounds; +}; + +// +// Weapons +// + +#define BAD_WEAPON 0x00007FFF + +// +// Converts a entvars_t * to a class pointer +// It will allocate the class and entity if necessary +// +template T * GetClassPtr( T *a ) +{ + entvars_t *pev = (entvars_t *)a; + + // allocate entity if necessary + if (pev == NULL) + pev = VARS(CREATE_ENTITY()); + + // get the private data + a = (T *)GET_PRIVATE(ENT(pev)); + + if (a == NULL) + { + // allocate private data + a = new(pev) T; + a->pev = pev; + } + return a; +} + + +/* +bit_PUSHBRUSH_DATA | bit_TOGGLE_DATA +bit_MONSTER_DATA +bit_DELAY_DATA +bit_TOGGLE_DATA | bit_DELAY_DATA | bit_MONSTER_DATA +bit_PLAYER_DATA | bit_MONSTER_DATA +bit_MONSTER_DATA | CYCLER_DATA +bit_LIGHT_DATA +path_corner_data +bit_MONSTER_DATA | wildcard_data +bit_MONSTER_DATA | bit_GROUP_DATA +boid_flock_data +boid_data +CYCLER_DATA +bit_ITEM_DATA +bit_ITEM_DATA | func_hud_data +bit_TOGGLE_DATA | bit_ITEM_DATA +EOFFSET +env_sound_data +env_sound_data +push_trigger_data +*/ + +#define TRACER_FREQ 4 // Tracers fire every 4 bullets + +typedef struct _SelAmmo +{ + BYTE Ammo1Type; + BYTE Ammo1; + BYTE Ammo2Type; + BYTE Ammo2; +} SelAmmo; + + +// this moved here from world.cpp, to allow classes to be derived from it +//======================= +// CWorld +// +// This spawns first when each level begins. +//======================= +class CWorld : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); +}; diff --git a/rehlds/dlls/cdll_dll.h b/rehlds/dlls/cdll_dll.h new file mode 100644 index 0000000..6fb5e98 --- /dev/null +++ b/rehlds/dlls/cdll_dll.h @@ -0,0 +1,46 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cdll_dll.h + +// this file is included by both the game-dll and the client-dll, + +#ifndef CDLL_DLL_H +#define CDLL_DLL_H + +#define MAX_WEAPONS 32 // ??? + +#define MAX_WEAPON_SLOTS 5 // hud item selection slots +#define MAX_ITEM_TYPES 6 // hud item selection slots + +#define MAX_ITEMS 5 // hard coded item types + +#define HIDEHUD_WEAPONS ( 1<<0 ) +#define HIDEHUD_FLASHLIGHT ( 1<<1 ) +#define HIDEHUD_ALL ( 1<<2 ) +#define HIDEHUD_HEALTH ( 1<<3 ) + +#define MAX_AMMO_TYPES 32 // ??? +#define MAX_AMMO_SLOTS 32 // not really slots + +#define HUD_PRINTNOTIFY 1 +#define HUD_PRINTCONSOLE 2 +#define HUD_PRINTTALK 3 +#define HUD_PRINTCENTER 4 + + +#define WEAPON_SUIT 31 + +#endif diff --git a/rehlds/dlls/client.h b/rehlds/dlls/client.h new file mode 100644 index 0000000..2e0b38e --- /dev/null +++ b/rehlds/dlls/client.h @@ -0,0 +1,65 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CLIENT_H +#define CLIENT_H + +extern void respawn( entvars_t* pev, BOOL fCopyCorpse ); +extern BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); +extern void ClientDisconnect( edict_t *pEntity ); +extern void ClientKill( edict_t *pEntity ); +extern void ClientPutInServer( edict_t *pEntity ); +extern void ClientCommand( edict_t *pEntity ); +extern void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ); +extern void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ); +extern void ServerDeactivate( void ); +extern void StartFrame( void ); +extern void PlayerPostThink( edict_t *pEntity ); +extern void PlayerPreThink( edict_t *pEntity ); +extern void ParmsNewLevel( void ); +extern void ParmsChangeLevel( void ); + +extern void ClientPrecache( void ); + +extern const char *GetGameDescription( void ); +extern void PlayerCustomization( edict_t *pEntity, customization_t *pCust ); + +extern void SpectatorConnect ( edict_t *pEntity ); +extern void SpectatorDisconnect ( edict_t *pEntity ); +extern void SpectatorThink ( edict_t *pEntity ); + +extern void Sys_Error( const char *error_string ); + +extern void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ); +extern void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); +extern int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ); +extern void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); +extern void RegisterEncoders( void ); + +extern int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ); + +extern void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); +extern void CmdEnd ( const edict_t *player ); + +extern int ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); + +extern int GetHullBounds( int hullnumber, float *mins, float *maxs ); + +extern void CreateInstancedBaselines ( void ); + +extern int InconsistentFile( const edict_t *player, const char *filename, char *disconnect_message ); + +extern int AllowLagCompensation( void ); + +#endif // CLIENT_H diff --git a/rehlds/dlls/decals.h b/rehlds/dlls/decals.h new file mode 100644 index 0000000..3185649 --- /dev/null +++ b/rehlds/dlls/decals.h @@ -0,0 +1,84 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef DECALS_H +#define DECALS_H + +// +// Dynamic Decals +// +enum decal_e +{ + DECAL_GUNSHOT1 = 0, + DECAL_GUNSHOT2, + DECAL_GUNSHOT3, + DECAL_GUNSHOT4, + DECAL_GUNSHOT5, + DECAL_LAMBDA1, + DECAL_LAMBDA2, + DECAL_LAMBDA3, + DECAL_LAMBDA4, + DECAL_LAMBDA5, + DECAL_LAMBDA6, + DECAL_SCORCH1, + DECAL_SCORCH2, + DECAL_BLOOD1, + DECAL_BLOOD2, + DECAL_BLOOD3, + DECAL_BLOOD4, + DECAL_BLOOD5, + DECAL_BLOOD6, + DECAL_YBLOOD1, + DECAL_YBLOOD2, + DECAL_YBLOOD3, + DECAL_YBLOOD4, + DECAL_YBLOOD5, + DECAL_YBLOOD6, + DECAL_GLASSBREAK1, + DECAL_GLASSBREAK2, + DECAL_GLASSBREAK3, + DECAL_BIGSHOT1, + DECAL_BIGSHOT2, + DECAL_BIGSHOT3, + DECAL_BIGSHOT4, + DECAL_BIGSHOT5, + DECAL_SPIT1, + DECAL_SPIT2, + DECAL_BPROOF1, // Bulletproof glass decal + DECAL_GARGSTOMP1, // Gargantua stomp crack + DECAL_SMALLSCORCH1, // Small scorch mark + DECAL_SMALLSCORCH2, // Small scorch mark + DECAL_SMALLSCORCH3, // Small scorch mark + DECAL_MOMMABIRTH, // Big momma birth splatter + DECAL_MOMMASPLAT, +}; + +typedef struct +{ + char *name; + short entityIndex; + byte depth; + byte flags; + vec3_t position; +} DECALLIST; + +typedef struct +{ + char *name; + int index; +} DLL_DECALLIST; + +extern DLL_DECALLIST gDecals[]; + +#endif // DECALS_H diff --git a/rehlds/dlls/doors.h b/rehlds/dlls/doors.h new file mode 100644 index 0000000..55a853f --- /dev/null +++ b/rehlds/dlls/doors.h @@ -0,0 +1,33 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef DOORS_H +#define DOORS_H + +// doors +#define SF_DOOR_ROTATE_Y 0 +#define SF_DOOR_START_OPEN 1 +#define SF_DOOR_ROTATE_BACKWARDS 2 +#define SF_DOOR_PASSABLE 8 +#define SF_DOOR_ONEWAY 16 +#define SF_DOOR_NO_AUTO_RETURN 32 +#define SF_DOOR_ROTATE_Z 64 +#define SF_DOOR_ROTATE_X 128 +#define SF_DOOR_USE_ONLY 256 // door must be opened by player's use button. +#define SF_DOOR_NOMONSTERS 512 // Monster can't open +#define SF_DOOR_SILENT 0x80000000 + + + +#endif //DOORS_H diff --git a/rehlds/dlls/effects.h b/rehlds/dlls/effects.h new file mode 100644 index 0000000..ac1516d --- /dev/null +++ b/rehlds/dlls/effects.h @@ -0,0 +1,209 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef EFFECTS_H +#define EFFECTS_H + +#define SF_BEAM_STARTON 0x0001 +#define SF_BEAM_TOGGLE 0x0002 +#define SF_BEAM_RANDOM 0x0004 +#define SF_BEAM_RING 0x0008 +#define SF_BEAM_SPARKSTART 0x0010 +#define SF_BEAM_SPARKEND 0x0020 +#define SF_BEAM_DECALS 0x0040 +#define SF_BEAM_SHADEIN 0x0080 +#define SF_BEAM_SHADEOUT 0x0100 +#define SF_BEAM_TEMPORARY 0x8000 + +#define SF_SPRITE_STARTON 0x0001 +#define SF_SPRITE_ONCE 0x0002 +#define SF_SPRITE_TEMPORARY 0x8000 + +class CSprite : public CPointEntity +{ +public: + void Spawn( void ); + void Precache( void ); + + int ObjectCaps( void ) + { + int flags = 0; + if ( pev->spawnflags & SF_SPRITE_TEMPORARY ) + flags = FCAP_DONT_SAVE; + return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; + } + void EXPORT AnimateThink( void ); + void EXPORT ExpandThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void Animate( float frames ); + void Expand( float scaleSpeed, float fadeSpeed ); + void SpriteInit( const char *pSpriteName, const Vector &origin ); + + inline void SetAttachment( edict_t *pEntity, int attachment ) + { + if ( pEntity ) + { + pev->skin = ENTINDEX(pEntity); + pev->body = attachment; + pev->aiment = pEntity; + pev->movetype = MOVETYPE_FOLLOW; + } + } + void TurnOff( void ); + void TurnOn( void ); + inline float Frames( void ) { return m_maxFrame; } + inline void SetTransparency( int rendermode, int r, int g, int b, int a, int fx ) + { + pev->rendermode = rendermode; + pev->rendercolor.x = r; + pev->rendercolor.y = g; + pev->rendercolor.z = b; + pev->renderamt = a; + pev->renderfx = fx; + } + inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } + inline void SetScale( float scale ) { pev->scale = scale; } + inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } + inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } + + inline void AnimateAndDie( float framerate ) + { + SetThink(&CSprite::AnimateUntilDead); + pev->framerate = framerate; + pev->dmgtime = gpGlobals->time + (m_maxFrame / framerate); + pev->nextthink = gpGlobals->time; + } + + void EXPORT AnimateUntilDead( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + static CSprite *SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ); + +private: + + float m_lastTime; + float m_maxFrame; +}; + + +class CBeam : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + int ObjectCaps( void ) + { + int flags = 0; + if ( pev->spawnflags & SF_BEAM_TEMPORARY ) + flags = FCAP_DONT_SAVE; + return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | flags; + } + + void EXPORT TriggerTouch( CBaseEntity *pOther ); + + // These functions are here to show the way beams are encoded as entities. + // Encoding beams as entities simplifies their management in the client/server architecture + inline void SetType( int type ) { pev->rendermode = (pev->rendermode & 0xF0) | (type&0x0F); } + inline void SetFlags( int flags ) { pev->rendermode = (pev->rendermode & 0x0F) | (flags&0xF0); } + inline void SetStartPos( const Vector& pos ) { pev->origin = pos; } + inline void SetEndPos( const Vector& pos ) { pev->angles = pos; } + void SetStartEntity( int entityIndex ); + void SetEndEntity( int entityIndex ); + + inline void SetStartAttachment( int attachment ) { pev->sequence = (pev->sequence & 0x0FFF) | ((attachment&0xF)<<12); } + inline void SetEndAttachment( int attachment ) { pev->skin = (pev->skin & 0x0FFF) | ((attachment&0xF)<<12); } + + inline void SetTexture( int spriteIndex ) { pev->modelindex = spriteIndex; } + inline void SetWidth( int width ) { pev->scale = width; } + inline void SetNoise( int amplitude ) { pev->body = amplitude; } + inline void SetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } + inline void SetBrightness( int brightness ) { pev->renderamt = brightness; } + inline void SetFrame( float frame ) { pev->frame = frame; } + inline void SetScrollRate( int speed ) { pev->animtime = speed; } + + inline int GetType( void ) { return pev->rendermode & 0x0F; } + inline int GetFlags( void ) { return pev->rendermode & 0xF0; } + inline int GetStartEntity( void ) { return pev->sequence & 0xFFF; } + inline int GetEndEntity( void ) { return pev->skin & 0xFFF; } + + const Vector &GetStartPos( void ); + const Vector &GetEndPos( void ); + + Vector Center( void ) { return (GetStartPos() + GetEndPos()) * 0.5; }; // center point of beam + + inline int GetTexture( void ) { return pev->modelindex; } + inline int GetWidth( void ) { return pev->scale; } + inline int GetNoise( void ) { return pev->body; } + // inline void GetColor( int r, int g, int b ) { pev->rendercolor.x = r; pev->rendercolor.y = g; pev->rendercolor.z = b; } + inline int GetBrightness( void ) { return pev->renderamt; } + inline int GetFrame( void ) { return pev->frame; } + inline int GetScrollRate( void ) { return pev->animtime; } + + // Call after you change start/end positions + void RelinkBeam( void ); +// void SetObjectCollisionBox( void ); + + void DoSparks( const Vector &start, const Vector &end ); + CBaseEntity *RandomTargetname( const char *szName ); + void BeamDamage( TraceResult *ptr ); + // Init after BeamCreate() + void BeamInit( const char *pSpriteName, int width ); + void PointsInit( const Vector &start, const Vector &end ); + void PointEntInit( const Vector &start, int endIndex ); + void EntsInit( int startIndex, int endIndex ); + void HoseInit( const Vector &start, const Vector &direction ); + + static CBeam *BeamCreate( const char *pSpriteName, int width ); + + inline void LiveForTime( float time ) { SetThink(&CBeam::SUB_Remove); pev->nextthink = gpGlobals->time + time; } + inline void BeamDamageInstant( TraceResult *ptr, float damage ) + { + pev->dmg = damage; + pev->dmgtime = gpGlobals->time - 1; + BeamDamage(ptr); + } +}; + + +#define SF_MESSAGE_ONCE 0x0001 // Fade in, not out +#define SF_MESSAGE_ALL 0x0002 // Send to all clients + + +class CLaser : public CBeam +{ +public: + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData *pkvd ); + + void TurnOn( void ); + void TurnOff( void ); + int IsOn( void ); + + void FireAtPoint( TraceResult &point ); + + void EXPORT StrikeThink( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + CSprite *m_pSprite; + int m_iszSpriteName; + Vector m_firePosition; +}; + +#endif //EFFECTS_H diff --git a/rehlds/dlls/enginecallback.h b/rehlds/dlls/enginecallback.h new file mode 100644 index 0000000..32925f3 --- /dev/null +++ b/rehlds/dlls/enginecallback.h @@ -0,0 +1,160 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef ENGINECALLBACK_H +#define ENGINECALLBACK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "event_flags.h" + +// Must be provided by user of this code +extern enginefuncs_t g_engfuncs; + +// The actual engine callbacks +#define GETPLAYERUSERID (*g_engfuncs.pfnGetPlayerUserId) +#define PRECACHE_MODEL (*g_engfuncs.pfnPrecacheModel) +#define PRECACHE_SOUND (*g_engfuncs.pfnPrecacheSound) +#define PRECACHE_GENERIC (*g_engfuncs.pfnPrecacheGeneric) +#define SET_MODEL (*g_engfuncs.pfnSetModel) +#define MODEL_INDEX (*g_engfuncs.pfnModelIndex) +#define MODEL_FRAMES (*g_engfuncs.pfnModelFrames) +#define SET_SIZE (*g_engfuncs.pfnSetSize) +#define CHANGE_LEVEL (*g_engfuncs.pfnChangeLevel) +#define GET_SPAWN_PARMS (*g_engfuncs.pfnGetSpawnParms) +#define SAVE_SPAWN_PARMS (*g_engfuncs.pfnSaveSpawnParms) +#define VEC_TO_YAW (*g_engfuncs.pfnVecToYaw) +#define VEC_TO_ANGLES (*g_engfuncs.pfnVecToAngles) +#define MOVE_TO_ORIGIN (*g_engfuncs.pfnMoveToOrigin) +#define oldCHANGE_YAW (*g_engfuncs.pfnChangeYaw) +#define CHANGE_PITCH (*g_engfuncs.pfnChangePitch) +#define MAKE_VECTORS (*g_engfuncs.pfnMakeVectors) +#define CREATE_ENTITY (*g_engfuncs.pfnCreateEntity) +#define REMOVE_ENTITY (*g_engfuncs.pfnRemoveEntity) +#define CREATE_NAMED_ENTITY (*g_engfuncs.pfnCreateNamedEntity) +#define MAKE_STATIC (*g_engfuncs.pfnMakeStatic) +#define ENT_IS_ON_FLOOR (*g_engfuncs.pfnEntIsOnFloor) +#define DROP_TO_FLOOR (*g_engfuncs.pfnDropToFloor) +#define WALK_MOVE (*g_engfuncs.pfnWalkMove) +#define SET_ORIGIN (*g_engfuncs.pfnSetOrigin) +#define EMIT_SOUND_DYN2 (*g_engfuncs.pfnEmitSound) +#define BUILD_SOUND_MSG (*g_engfuncs.pfnBuildSoundMsg) +#define TRACE_LINE (*g_engfuncs.pfnTraceLine) +#define TRACE_TOSS (*g_engfuncs.pfnTraceToss) +#define TRACE_MONSTER_HULL (*g_engfuncs.pfnTraceMonsterHull) +#define TRACE_HULL (*g_engfuncs.pfnTraceHull) +#define GET_AIM_VECTOR (*g_engfuncs.pfnGetAimVector) +#define SERVER_COMMAND (*g_engfuncs.pfnServerCommand) +#define SERVER_EXECUTE (*g_engfuncs.pfnServerExecute) +#define CLIENT_COMMAND (*g_engfuncs.pfnClientCommand) +#define PARTICLE_EFFECT (*g_engfuncs.pfnParticleEffect) +#define LIGHT_STYLE (*g_engfuncs.pfnLightStyle) +#define DECAL_INDEX (*g_engfuncs.pfnDecalIndex) +#define POINT_CONTENTS (*g_engfuncs.pfnPointContents) +#define CRC32_INIT (*g_engfuncs.pfnCRC32_Init) +#define CRC32_PROCESS_BUFFER (*g_engfuncs.pfnCRC32_ProcessBuffer) +#define CRC32_PROCESS_BYTE (*g_engfuncs.pfnCRC32_ProcessByte) +#define CRC32_FINAL (*g_engfuncs.pfnCRC32_Final) +#define RANDOM_LONG (*g_engfuncs.pfnRandomLong) +#define RANDOM_FLOAT (*g_engfuncs.pfnRandomFloat) +#define GETPLAYERAUTHID (*g_engfuncs.pfnGetPlayerAuthId) + +inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NULL, edict_t *ed = NULL ) { + (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ed); +} +#define MESSAGE_END (*g_engfuncs.pfnMessageEnd) +#define WRITE_BYTE (*g_engfuncs.pfnWriteByte) +#define WRITE_CHAR (*g_engfuncs.pfnWriteChar) +#define WRITE_SHORT (*g_engfuncs.pfnWriteShort) +#define WRITE_LONG (*g_engfuncs.pfnWriteLong) +#define WRITE_ANGLE (*g_engfuncs.pfnWriteAngle) +#define WRITE_COORD (*g_engfuncs.pfnWriteCoord) +#define WRITE_STRING (*g_engfuncs.pfnWriteString) +#define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity) +#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister) +#define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat) +#define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString) +#define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat) +#define CVAR_SET_STRING (*g_engfuncs.pfnCVarSetString) +#define CVAR_GET_POINTER (*g_engfuncs.pfnCVarGetPointer) +#define ALERT (*g_engfuncs.pfnAlertMessage) +#define ENGINE_FPRINTF (*g_engfuncs.pfnEngineFprintf) +#define ALLOC_PRIVATE (*g_engfuncs.pfnPvAllocEntPrivateData) +inline void *GET_PRIVATE( edict_t *pent ) +{ + if ( pent ) + return pent->pvPrivateData; + return NULL; +} + +#define FREE_PRIVATE (*g_engfuncs.pfnFreeEntPrivateData) +//#define STRING (*g_engfuncs.pfnSzFromIndex) +#define ALLOC_STRING (*g_engfuncs.pfnAllocString) +#define FIND_ENTITY_BY_STRING (*g_engfuncs.pfnFindEntityByString) +#define GETENTITYILLUM (*g_engfuncs.pfnGetEntityIllum) +#define FIND_ENTITY_IN_SPHERE (*g_engfuncs.pfnFindEntityInSphere) +#define FIND_CLIENT_IN_PVS (*g_engfuncs.pfnFindClientInPVS) +#define EMIT_AMBIENT_SOUND (*g_engfuncs.pfnEmitAmbientSound) +#define GET_MODEL_PTR (*g_engfuncs.pfnGetModelPtr) +#define REG_USER_MSG (*g_engfuncs.pfnRegUserMsg) +#define GET_BONE_POSITION (*g_engfuncs.pfnGetBonePosition) +#define FUNCTION_FROM_NAME (*g_engfuncs.pfnFunctionFromName) +#define NAME_FOR_FUNCTION (*g_engfuncs.pfnNameForFunction) +#define TRACE_TEXTURE (*g_engfuncs.pfnTraceTexture) +#define CLIENT_PRINTF (*g_engfuncs.pfnClientPrintf) +#define CMD_ARGS (*g_engfuncs.pfnCmd_Args) +#define CMD_ARGC (*g_engfuncs.pfnCmd_Argc) +#define CMD_ARGV (*g_engfuncs.pfnCmd_Argv) +#define GET_ATTACHMENT (*g_engfuncs.pfnGetAttachment) +#define SET_VIEW (*g_engfuncs.pfnSetView) +#define SET_CROSSHAIRANGLE (*g_engfuncs.pfnCrosshairAngle) +#define LOAD_FILE_FOR_ME (*g_engfuncs.pfnLoadFileForMe) +#define FREE_FILE (*g_engfuncs.pfnFreeFile) +#define COMPARE_FILE_TIME (*g_engfuncs.pfnCompareFileTime) +#define GET_GAME_DIR (*g_engfuncs.pfnGetGameDir) +#define IS_MAP_VALID (*g_engfuncs.pfnIsMapValid) +#define NUMBER_OF_ENTITIES (*g_engfuncs.pfnNumberOfEntities) +#define IS_DEDICATED_SERVER (*g_engfuncs.pfnIsDedicatedServer) + +#define PRECACHE_EVENT (*g_engfuncs.pfnPrecacheEvent) +#define PLAYBACK_EVENT_FULL (*g_engfuncs.pfnPlaybackEvent) + +#define ENGINE_SET_PVS (*g_engfuncs.pfnSetFatPVS) +#define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS) + +#define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility) + +#define DELTA_SET ( *g_engfuncs.pfnDeltaSetField ) +#define DELTA_UNSET ( *g_engfuncs.pfnDeltaUnsetField ) +#define DELTA_ADDENCODER ( *g_engfuncs.pfnDeltaAddEncoder ) +#define ENGINE_CURRENT_PLAYER ( *g_engfuncs.pfnGetCurrentPlayer ) + +#define ENGINE_CANSKIP ( *g_engfuncs.pfnCanSkipPlayer ) + +#define DELTA_FINDFIELD ( *g_engfuncs.pfnDeltaFindField ) +#define DELTA_SETBYINDEX ( *g_engfuncs.pfnDeltaSetFieldByIndex ) +#define DELTA_UNSETBYINDEX ( *g_engfuncs.pfnDeltaUnsetFieldByIndex ) + +#define ENGINE_GETPHYSINFO ( *g_engfuncs.pfnGetPhysicsInfoString ) + +#define ENGINE_SETGROUPMASK ( *g_engfuncs.pfnSetGroupMask ) + +#define ENGINE_INSTANCE_BASELINE ( *g_engfuncs.pfnCreateInstancedBaseline ) + +#define ENGINE_FORCE_UNMODIFIED ( *g_engfuncs.pfnForceUnmodified ) + +#define PLAYER_CNX_STATS ( *g_engfuncs.pfnGetPlayerStats ) + +#endif //ENGINECALLBACK_H diff --git a/rehlds/dlls/explode.h b/rehlds/dlls/explode.h new file mode 100644 index 0000000..3d8c410 --- /dev/null +++ b/rehlds/dlls/explode.h @@ -0,0 +1,32 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef EXPLODE_H +#define EXPLODE_H + + +#define SF_ENVEXPLOSION_NODAMAGE ( 1 << 0 ) // when set, ENV_EXPLOSION will not actually inflict damage +#define SF_ENVEXPLOSION_REPEATABLE ( 1 << 1 ) // can this entity be refired? +#define SF_ENVEXPLOSION_NOFIREBALL ( 1 << 2 ) // don't draw the fireball +#define SF_ENVEXPLOSION_NOSMOKE ( 1 << 3 ) // don't draw the smoke +#define SF_ENVEXPLOSION_NODECAL ( 1 << 4 ) // don't make a scorch mark +#define SF_ENVEXPLOSION_NOSPARKS ( 1 << 5 ) // don't make a scorch mark + +extern DLL_GLOBAL short g_sModelIndexFireball; +extern DLL_GLOBAL short g_sModelIndexSmoke; + + +extern void ExplosionCreate( const Vector ¢er, const Vector &angles, edict_t *pOwner, int magnitude, BOOL doDamage ); + +#endif //EXPLODE_H diff --git a/rehlds/dlls/extdll.h b/rehlds/dlls/extdll.h new file mode 100644 index 0000000..0129810 --- /dev/null +++ b/rehlds/dlls/extdll.h @@ -0,0 +1,94 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef EXTDLL_H +#define EXTDLL_H + + +// +// Global header file for extension DLLs +// + +// Allow "DEBUG" in addition to default "_DEBUG" +#ifdef _DEBUG +#define DEBUG 1 +#endif + +// Silence certain warnings +#pragma warning(disable : 4244) // int or float down-conversion +#pragma warning(disable : 4305) // int or float data truncation +#pragma warning(disable : 4201) // nameless struct/union +#pragma warning(disable : 4514) // unreferenced inline function removed +#pragma warning(disable : 4100) // unreferenced formal parameter + +#include "archtypes.h" // DAL + +// Prevent tons of unused windows definitions +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define NOWINRES +#define NOSERVICE +#define NOMCX +#define NOIME +#include "winsani_in.h" +#include "windows.h" +#include "winsani_out.h" +#else // _WIN32 +#ifndef TRUE +#define FALSE 0 +#define TRUE (!FALSE) +#endif //TRUE +typedef uint32 ULONG; +typedef unsigned char BYTE; +typedef int BOOL; +#ifndef MAX_PATH +#define MAX_PATH PATH_MAX +#endif // MAX_PATH +#include +#include +#include // memset +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) +#endif +#endif //_WIN32 + +// Misc C-runtime library headers +#include "stdio.h" +#include "stdlib.h" +#include "math.h" + +// Header file containing definition of globalvars_t and entvars_t +typedef unsigned int func_t; // +typedef unsigned int string_t; // from engine's pr_comp.h; +typedef float vec_t; // needed before including progdefs.h + +// Vector class +#include "vector.h" + +// Shared engine/DLL constants +#include "const.h" +#include "progdefs.h" +#include "edict.h" + +// Shared header describing protocol between engine and DLLs +#include "eiface.h" + +// Shared header between the client DLL and the game DLLs +#include "cdll_dll.h" + +#endif //EXTDLL_H diff --git a/rehlds/dlls/func_break.h b/rehlds/dlls/func_break.h new file mode 100644 index 0000000..2441f75 --- /dev/null +++ b/rehlds/dlls/func_break.h @@ -0,0 +1,74 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef FUNC_BREAK_H +#define FUNC_BREAK_H + +typedef enum { expRandom, expDirected} Explosions; +typedef enum { matGlass = 0, matWood, matMetal, matFlesh, matCinderBlock, matCeilingTile, matComputer, matUnbreakableGlass, matRocks, matNone, matLastMaterial } Materials; + +#define NUM_SHARDS 6 // this many shards spawned when breakable objects break; + +class CBreakable : public CBaseDelay +{ +public: + // basic functions + void Spawn( void ); + void Precache( void ); + void KeyValue( KeyValueData* pkvd); + void EXPORT BreakTouch( CBaseEntity *pOther ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void DamageSound( void ); + + // breakables use an overridden takedamage + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ); + // To spark when hit + void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ); + + BOOL IsBreakable( void ); + BOOL SparkWhenHit( void ); + + int DamageDecal( int bitsDamageType ); + + void EXPORT Die( void ); + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION); } + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + inline BOOL Explodable( void ) { return ExplosionMagnitude() > 0; } + inline int ExplosionMagnitude( void ) { return pev->impulse; } + inline void ExplosionSetMagnitude( int magnitude ) { pev->impulse = magnitude; } + + static void MaterialSoundPrecache( Materials precacheMaterial ); + static void MaterialSoundRandom( edict_t *pEdict, Materials soundMaterial, float volume ); + static const char **MaterialSoundList( Materials precacheMaterial, int &soundCount ); + + static const char *pSoundsWood[]; + static const char *pSoundsFlesh[]; + static const char *pSoundsGlass[]; + static const char *pSoundsMetal[]; + static const char *pSoundsConcrete[]; + static const char *pSpawnObjects[]; + + static TYPEDESCRIPTION m_SaveData[]; + + Materials m_Material; + Explosions m_Explosion; + int m_idShard; + float m_angle; + int m_iszGibModel; + int m_iszSpawnObject; +}; + +#endif // FUNC_BREAK_H diff --git a/rehlds/dlls/game.h b/rehlds/dlls/game.h new file mode 100644 index 0000000..7bd9dce --- /dev/null +++ b/rehlds/dlls/game.h @@ -0,0 +1,45 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef GAME_H +#define GAME_H + +extern void GameDLLInit( void ); + + +extern cvar_t displaysoundlist; + +// multiplayer server rules +extern cvar_t teamplay; +extern cvar_t fraglimit; +extern cvar_t timelimit; +extern cvar_t friendlyfire; +extern cvar_t falldamage; +extern cvar_t weaponstay; +extern cvar_t forcerespawn; +extern cvar_t flashlight; +extern cvar_t aimcrosshair; +extern cvar_t decalfrequency; +extern cvar_t teamlist; +extern cvar_t teamoverride; +extern cvar_t defaultteam; +extern cvar_t allowmonsters; + +// Engine Cvars +extern cvar_t *g_psv_gravity; +extern cvar_t *g_psv_aim; +extern cvar_t *g_footsteps; + +#endif // GAME_H diff --git a/rehlds/dlls/gamerules.h b/rehlds/dlls/gamerules.h new file mode 100644 index 0000000..2e85304 --- /dev/null +++ b/rehlds/dlls/gamerules.h @@ -0,0 +1,360 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// GameRules +//========================================================= + +//#include "weapons.h" +//#include "items.h" +class CBasePlayerItem; +class CBasePlayer; +class CItem; +class CBasePlayerAmmo; + +// weapon respawning return codes +enum +{ + GR_NONE = 0, + + GR_WEAPON_RESPAWN_YES, + GR_WEAPON_RESPAWN_NO, + + GR_AMMO_RESPAWN_YES, + GR_AMMO_RESPAWN_NO, + + GR_ITEM_RESPAWN_YES, + GR_ITEM_RESPAWN_NO, + + GR_PLR_DROP_GUN_ALL, + GR_PLR_DROP_GUN_ACTIVE, + GR_PLR_DROP_GUN_NO, + + GR_PLR_DROP_AMMO_ALL, + GR_PLR_DROP_AMMO_ACTIVE, + GR_PLR_DROP_AMMO_NO, +}; + +// Player relationship return codes +enum +{ + GR_NOTTEAMMATE = 0, + GR_TEAMMATE, + GR_ENEMY, + GR_ALLY, + GR_NEUTRAL, +}; + +class CGameRules +{ +public: + virtual void RefreshSkillData( void );// fill skill data struct with proper values + virtual void Think( void ) = 0;// GR_Think - runs every server frame, should handle any timer tasks, periodic events, etc. + virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ) = 0; // Can this item spawn (eg monsters don't spawn in deathmatch). + + virtual BOOL FAllowFlashlight( void ) = 0;// Are players allowed to switch on their flashlight? + virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// should the player switch to this weapon? + virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) = 0;// I can't use this weapon anymore, get me the next best one. + +// Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer( void ) = 0;// is this a multiplayer game? (either coop or deathmatch) + virtual BOOL IsDeathmatch( void ) = 0;//is this a deathmatch game? + virtual BOOL IsTeamplay( void ) { return FALSE; };// is this deathmatch game being played with team rules? + virtual BOOL IsCoOp( void ) = 0;// is this a coop game? + virtual const char *GetGameDescription( void ) { return "Half-Life"; } // this is the game name that gets seen in the server browser + +// Client connection/disconnection + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) = 0;// a client just connected to the server (player hasn't spawned yet) + virtual void InitHUD( CBasePlayer *pl ) = 0; // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ) = 0;// a client just disconnected from the server + virtual void UpdateGameMode( CBasePlayer *pPlayer ) {} // the client needs to be informed of the current game mode + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ) = 0;// this client just hit the ground after a fall. How much damage? + virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) {return TRUE;};// can this player take damage from this attacker? + virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) { return TRUE; } + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ) = 0;// called by CBasePlayer::Spawn just before releasing player into the game + virtual void PlayerThink( CBasePlayer *pPlayer ) = 0; // called by CBasePlayer::PreThink every frame, before physics are run and after keys are accepted + virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ) = 0;// is this player allowed to respawn now? + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ) = 0;// When in the future will this player be able to spawn? + virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer );// Place this player on their spawnspot and face them the proper direction. + + virtual BOOL AllowAutoTargetCrosshair( void ) { return TRUE; }; + virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { return FALSE; }; // handles the user commands; returns TRUE if command handled properly + virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) {} // the player has changed userinfo; can change it now + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) = 0;// how many points do I award whoever kills this player? + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) = 0;// Called each time a player dies + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor )= 0;// Call this from within a GameRules class to report an obituary. +// Weapon retrieval + virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? + virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ) = 0;// Called each time a player picks up a weapon from the ground + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ) = 0;// should this weapon respawn? + virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ) = 0;// when may this weapon respawn? + virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ) = 0; // can i respawn now, and if not, when should i try again? + virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ) = 0;// where in the world should this weapon respawn? + +// Item retrieval + virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// is this player allowed to take this item? + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ) = 0;// call each time a player picks up an item (battery, healthkit, longjump) + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ) = 0;// Should this item respawn? + virtual float FlItemRespawnTime( CItem *pItem ) = 0;// when may this item respawn? + virtual Vector VecItemRespawnSpot( CItem *pItem ) = 0;// where in the world should this item respawn? + +// Ammo retrieval + virtual BOOL CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int iMaxCarry );// can this player take more of this ammo? + virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ) = 0;// called each time a player picks up some ammo in the world + +// Ammo spawn/respawn control + virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ) = 0;// should this ammo item respawn? + virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ) = 0;// when should this ammo item respawn? + virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ) = 0;// where in the world should this ammo item respawn? + // by default, everything spawns + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ) = 0;// how long until a depleted HealthCharger recharges itself? + virtual float FlHEVChargerRechargeTime( void ) { return 0; }// how long until a depleted HealthCharger recharges itself? + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ) = 0;// what do I do with a player's weapons when he's killed? + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ) = 0;// Do I drop ammo when the player dies? How much? + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) = 0;// what team is this entity on? + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) = 0;// What is the player's relationship with this entity? + virtual int GetTeamIndex( const char *pTeamName ) { return -1; } + virtual const char *GetIndexedTeamName( int teamIndex ) { return ""; } + virtual BOOL IsValidTeam( const char *pTeamName ) { return TRUE; } + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ) {} + virtual const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ) { return ""; } + +// Sounds + virtual BOOL PlayTextureSounds( void ) { return TRUE; } + virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ) { return TRUE; } + +// Monsters + virtual BOOL FAllowMonsters( void ) = 0;//are monsters allowed + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame( void ) {} +}; + +extern CGameRules *InstallGameRules( void ); + + +//========================================================= +// CHalfLifeRules - rules for the single player Half-Life +// game. +//========================================================= +class CHalfLifeRules : public CGameRules +{ +public: + CHalfLifeRules ( void ); + +// GR_Think + virtual void Think( void ); + virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); + virtual BOOL FAllowFlashlight( void ) { return TRUE; }; + + virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + +// Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer( void ); + virtual BOOL IsDeathmatch( void ); + virtual BOOL IsCoOp( void ); + +// Client connection/disconnection + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); + virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ); + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + virtual void PlayerThink( CBasePlayer *pPlayer ); + virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); + + virtual BOOL AllowAutoTargetCrosshair( void ); + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + +// Weapon retrieval + virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); + virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); + virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); + virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); + +// Item retrieval + virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ); + virtual float FlItemRespawnTime( CItem *pItem ); + virtual Vector VecItemRespawnSpot( CItem *pItem ); + +// Ammo retrieval + virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); + +// Ammo spawn/respawn control + virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); + virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); + virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ); + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); + +// Monsters + virtual BOOL FAllowMonsters( void ); + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";}; + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); +}; + +//========================================================= +// CHalfLifeMultiplay - rules for the basic half life multiplayer +// competition +//========================================================= +class CHalfLifeMultiplay : public CGameRules +{ +public: + CHalfLifeMultiplay(); + +// GR_Think + virtual void Think( void ); + virtual void RefreshSkillData( void ); + virtual BOOL IsAllowedToSpawn( CBaseEntity *pEntity ); + virtual BOOL FAllowFlashlight( void ); + + virtual BOOL FShouldSwitchWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + virtual BOOL GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + +// Functions to verify the single/multiplayer status of a game + virtual BOOL IsMultiplayer( void ); + virtual BOOL IsDeathmatch( void ); + virtual BOOL IsCoOp( void ); + +// Client connection/disconnection + // If ClientConnected returns FALSE, the connection is rejected and the user is provided the reason specified in + // svRejectReason + // Only the client's name and remote address are provided to the dll for verification. + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); + virtual void InitHUD( CBasePlayer *pl ); // the client dll is ready for updating + virtual void ClientDisconnected( edict_t *pClient ); + virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode + +// Client damage rules + virtual float FlPlayerFallDamage( CBasePlayer *pPlayer ); + virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); + +// Client spawn/respawn control + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + virtual void PlayerThink( CBasePlayer *pPlayer ); + virtual BOOL FPlayerCanRespawn( CBasePlayer *pPlayer ); + virtual float FlPlayerSpawnTime( CBasePlayer *pPlayer ); + virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer ); + + virtual BOOL AllowAutoTargetCrosshair( void ); + virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); + +// Client kills/scoring + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + +// Weapon retrieval + virtual void PlayerGotWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon ); + virtual BOOL CanHavePlayerItem( CBasePlayer *pPlayer, CBasePlayerItem *pWeapon );// The player is touching an CBasePlayerItem, do I give it to him? + +// Weapon spawn/respawn control + virtual int WeaponShouldRespawn( CBasePlayerItem *pWeapon ); + virtual float FlWeaponRespawnTime( CBasePlayerItem *pWeapon ); + virtual float FlWeaponTryRespawn( CBasePlayerItem *pWeapon ); + virtual Vector VecWeaponRespawnSpot( CBasePlayerItem *pWeapon ); + +// Item retrieval + virtual BOOL CanHaveItem( CBasePlayer *pPlayer, CItem *pItem ); + virtual void PlayerGotItem( CBasePlayer *pPlayer, CItem *pItem ); + +// Item spawn/respawn control + virtual int ItemShouldRespawn( CItem *pItem ); + virtual float FlItemRespawnTime( CItem *pItem ); + virtual Vector VecItemRespawnSpot( CItem *pItem ); + +// Ammo retrieval + virtual void PlayerGotAmmo( CBasePlayer *pPlayer, char *szName, int iCount ); + +// Ammo spawn/respawn control + virtual int AmmoShouldRespawn( CBasePlayerAmmo *pAmmo ); + virtual float FlAmmoRespawnTime( CBasePlayerAmmo *pAmmo ); + virtual Vector VecAmmoRespawnSpot( CBasePlayerAmmo *pAmmo ); + +// Healthcharger respawn control + virtual float FlHealthChargerRechargeTime( void ); + virtual float FlHEVChargerRechargeTime( void ); + +// What happens to a dead player's weapons + virtual int DeadPlayerWeapons( CBasePlayer *pPlayer ); + +// What happens to a dead player's ammo + virtual int DeadPlayerAmmo( CBasePlayer *pPlayer ); + +// Teamplay stuff + virtual const char *GetTeamID( CBaseEntity *pEntity ) {return "";} + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + + virtual BOOL PlayTextureSounds( void ) { return FALSE; } + virtual BOOL PlayFootstepSounds( CBasePlayer *pl, float fvol ); + +// Monsters + virtual BOOL FAllowMonsters( void ); + + // Immediately end a multiplayer game + virtual void EndMultiplayerGame( void ) { GoToIntermission(); } + +protected: + virtual void ChangeLevel( void ); + virtual void GoToIntermission( void ); + float m_flIntermissionEndTime; + BOOL m_iEndIntermissionButtonHit; + void SendMOTDToClient( edict_t *client ); +}; + +extern DLL_GLOBAL CGameRules* g_pGameRules; diff --git a/rehlds/dlls/hornet.h b/rehlds/dlls/hornet.h new file mode 100644 index 0000000..f069c3d --- /dev/null +++ b/rehlds/dlls/hornet.h @@ -0,0 +1,58 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// Hornets +//========================================================= + +//========================================================= +// Hornet Defines +//========================================================= +#define HORNET_TYPE_RED 0 +#define HORNET_TYPE_ORANGE 1 +#define HORNET_RED_SPEED (float)600 +#define HORNET_ORANGE_SPEED (float)800 +#define HORNET_BUZZ_VOLUME (float)0.8 + +extern int iHornetPuff; + +//========================================================= +// Hornet - this is the projectile that the Alien Grunt fires. +//========================================================= +class CHornet : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + int Classify ( void ); + int IRelationship ( CBaseEntity *pTarget ); + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + + void IgniteTrail( void ); + void EXPORT StartTrack ( void ); + void EXPORT StartDart ( void ); + void EXPORT TrackTarget ( void ); + void EXPORT TrackTouch ( CBaseEntity *pOther ); + void EXPORT DartTouch( CBaseEntity *pOther ); + void EXPORT DieTouch ( CBaseEntity *pOther ); + + int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ); + + float m_flStopAttack; + int m_iHornetType; + float m_flFlySpeed; +}; + diff --git a/rehlds/dlls/items.h b/rehlds/dlls/items.h new file mode 100644 index 0000000..04905fc --- /dev/null +++ b/rehlds/dlls/items.h @@ -0,0 +1,29 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef ITEMS_H +#define ITEMS_H + + +class CItem : public CBaseEntity +{ +public: + void Spawn( void ); + CBaseEntity* Respawn( void ); + void EXPORT ItemTouch( CBaseEntity *pOther ); + void EXPORT Materialize( void ); + virtual BOOL MyTouch( CBasePlayer *pPlayer ) { return FALSE; }; +}; + +#endif // ITEMS_H diff --git a/rehlds/dlls/maprules.h b/rehlds/dlls/maprules.h new file mode 100644 index 0000000..975dafa --- /dev/null +++ b/rehlds/dlls/maprules.h @@ -0,0 +1,22 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef MAPRULES_H +#define MAPRULES_H + + + +#endif // MAPRULES_H + diff --git a/rehlds/dlls/monsterevent.h b/rehlds/dlls/monsterevent.h new file mode 100644 index 0000000..58357e1 --- /dev/null +++ b/rehlds/dlls/monsterevent.h @@ -0,0 +1,34 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef MONSTEREVENT_H +#define MONSTEREVENT_H + +typedef struct +{ + int event; + char *options; +} MonsterEvent_t; + +#define EVENT_SPECIFIC 0 +#define EVENT_SCRIPTED 1000 +#define EVENT_SHARED 2000 +#define EVENT_CLIENT 5000 + +#define MONSTER_EVENT_BODYDROP_LIGHT 2001 +#define MONSTER_EVENT_BODYDROP_HEAVY 2002 + +#define MONSTER_EVENT_SWISHSOUND 2010 + +#endif // MONSTEREVENT_H diff --git a/rehlds/dlls/monsters.h b/rehlds/dlls/monsters.h new file mode 100644 index 0000000..f107510 --- /dev/null +++ b/rehlds/dlls/monsters.h @@ -0,0 +1,183 @@ +/*** +* +* Copyright (c) 1996-2001, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +#ifndef MONSTERS_H +#include "skill.h" +#define MONSTERS_H + +/* + +===== monsters.h ======================================================== + + Header file for monster-related utility code + +*/ + +// CHECKLOCALMOVE result types +#define LOCALMOVE_INVALID 0 // move is not possible +#define LOCALMOVE_INVALID_DONT_TRIANGULATE 1 // move is not possible, don't try to triangulate +#define LOCALMOVE_VALID 2 // move is possible + +// Hit Group standards +#define HITGROUP_GENERIC 0 +#define HITGROUP_HEAD 1 +#define HITGROUP_CHEST 2 +#define HITGROUP_STOMACH 3 +#define HITGROUP_LEFTARM 4 +#define HITGROUP_RIGHTARM 5 +#define HITGROUP_LEFTLEG 6 +#define HITGROUP_RIGHTLEG 7 + + +// Monster Spawnflags +#define SF_MONSTER_WAIT_TILL_SEEN 1// spawnflag that makes monsters wait until player can see them before attacking. +#define SF_MONSTER_GAG 2 // no idle noises from this monster +#define SF_MONSTER_HITMONSTERCLIP 4 +// 8 +#define SF_MONSTER_PRISONER 16 // monster won't attack anyone, no one will attacke him. +// 32 +// 64 +#define SF_MONSTER_WAIT_FOR_SCRIPT 128 //spawnflag that makes monsters wait to check for attacking until the script is done or they've been attacked +#define SF_MONSTER_PREDISASTER 256 //this is a predisaster scientist or barney. Influences how they speak. +#define SF_MONSTER_FADECORPSE 512 // Fade out corpse after death +#define SF_MONSTER_FALL_TO_GROUND 0x80000000 + +// specialty spawnflags +#define SF_MONSTER_TURRET_AUTOACTIVATE 32 +#define SF_MONSTER_TURRET_STARTINACTIVE 64 +#define SF_MONSTER_WAIT_UNTIL_PROVOKED 64 // don't attack the player unless provoked + + + +// MoveToOrigin stuff +#define MOVE_START_TURN_DIST 64 // when this far away from moveGoal, start turning to face next goal +#define MOVE_STUCK_DIST 32 // if a monster can't step this far, it is stuck. + + +// MoveToOrigin stuff +#define MOVE_NORMAL 0// normal move in the direction monster is facing +#define MOVE_STRAFE 1// moves in direction specified, no matter which way monster is facing + +// spawn flags 256 and above are already taken by the engine +extern void UTIL_MoveToOrigin( edict_t* pent, const Vector &vecGoal, float flDist, int iMoveType ); + +Vector VecCheckToss ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flGravityAdj = 1.0 ); +Vector VecCheckThrow ( entvars_t *pev, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj = 1.0 ); +extern DLL_GLOBAL Vector g_vecAttackDir; +extern DLL_GLOBAL CONSTANT float g_flMeleeRange; +extern DLL_GLOBAL CONSTANT float g_flMediumRange; +extern DLL_GLOBAL CONSTANT float g_flLongRange; +extern void EjectBrass (const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ); +extern void ExplodeModel( const Vector &vecOrigin, float speed, int model, int count ); + +BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget ); +BOOL FBoxVisible ( entvars_t *pevLooker, entvars_t *pevTarget, Vector &vecTargetOrigin, float flSize = 0.0 ); + +// monster to monster relationship types +#define R_AL -2 // (ALLY) pals. Good alternative to R_NO when applicable. +#define R_FR -1// (FEAR)will run +#define R_NO 0// (NO RELATIONSHIP) disregard +#define R_DL 1// (DISLIKE) will attack +#define R_HT 2// (HATE)will attack this character instead of any visible DISLIKEd characters +#define R_NM 3// (NEMESIS) A monster Will ALWAYS attack its nemsis, no matter what + + +// these bits represent the monster's memory +#define MEMORY_CLEAR 0 +#define bits_MEMORY_PROVOKED ( 1 << 0 )// right now only used for houndeyes. +#define bits_MEMORY_INCOVER ( 1 << 1 )// monster knows it is in a covered position. +#define bits_MEMORY_SUSPICIOUS ( 1 << 2 )// Ally is suspicious of the player, and will move to provoked more easily +#define bits_MEMORY_PATH_FINISHED ( 1 << 3 )// Finished monster path (just used by big momma for now) +#define bits_MEMORY_ON_PATH ( 1 << 4 )// Moving on a path +#define bits_MEMORY_MOVE_FAILED ( 1 << 5 )// Movement has already failed +#define bits_MEMORY_FLINCHED ( 1 << 6 )// Has already flinched +#define bits_MEMORY_KILLED ( 1 << 7 )// HACKHACK -- remember that I've already called my Killed() +#define bits_MEMORY_CUSTOM4 ( 1 << 28 ) // Monster-specific memory +#define bits_MEMORY_CUSTOM3 ( 1 << 29 ) // Monster-specific memory +#define bits_MEMORY_CUSTOM2 ( 1 << 30 ) // Monster-specific memory +#define bits_MEMORY_CUSTOM1 ( 1 << 31 ) // Monster-specific memory + +// trigger conditions for scripted AI +// these MUST match the CHOICES interface in halflife.fgd for the base monster +enum +{ + AITRIGGER_NONE = 0, + AITRIGGER_SEEPLAYER_ANGRY_AT_PLAYER, + AITRIGGER_TAKEDAMAGE, + AITRIGGER_HALFHEALTH, + AITRIGGER_DEATH, + AITRIGGER_SQUADMEMBERDIE, + AITRIGGER_SQUADLEADERDIE, + AITRIGGER_HEARWORLD, + AITRIGGER_HEARPLAYER, + AITRIGGER_HEARCOMBAT, + AITRIGGER_SEEPLAYER_UNCONDITIONAL, + AITRIGGER_SEEPLAYER_NOT_IN_COMBAT, +}; +/* + 0 : "No Trigger" + 1 : "See Player" + 2 : "Take Damage" + 3 : "50% Health Remaining" + 4 : "Death" + 5 : "Squad Member Dead" + 6 : "Squad Leader Dead" + 7 : "Hear World" + 8 : "Hear Player" + 9 : "Hear Combat" +*/ + +// +// A gib is a chunk of a body, or a piece of wood/metal/rocks/etc. +// +class CGib : public CBaseEntity +{ +public: + void Spawn( const char *szGibModel ); + void EXPORT BounceGibTouch ( CBaseEntity *pOther ); + void EXPORT StickyGibTouch ( CBaseEntity *pOther ); + void EXPORT WaitTillLand( void ); + void LimitVelocity( void ); + + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; } + static void SpawnHeadGib( entvars_t *pevVictim ); + static void SpawnRandomGibs( entvars_t *pevVictim, int cGibs, int human ); + static void SpawnStickyGibs( entvars_t *pevVictim, Vector vecOrigin, int cGibs ); + + int m_bloodColor; + int m_cBloodDecals; + int m_material; + float m_lifeTime; +}; + + +#define CUSTOM_SCHEDULES\ + virtual Schedule_t *ScheduleFromName( const char *pName );\ + static Schedule_t *m_scheduleList[]; + +#define DEFINE_CUSTOM_SCHEDULES(derivedClass)\ + Schedule_t *derivedClass::m_scheduleList[] = + +#define IMPLEMENT_CUSTOM_SCHEDULES(derivedClass, baseClass)\ + Schedule_t *derivedClass::ScheduleFromName( const char *pName )\ + {\ + Schedule_t *pSchedule = ScheduleInList( pName, m_scheduleList, ARRAYSIZE(m_scheduleList) );\ + if ( !pSchedule )\ + return baseClass::ScheduleFromName(pName);\ + return pSchedule;\ + } + + + +#endif //MONSTERS_H diff --git a/rehlds/dlls/nodes.h b/rehlds/dlls/nodes.h new file mode 100644 index 0000000..7447768 --- /dev/null +++ b/rehlds/dlls/nodes.h @@ -0,0 +1,379 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// nodes.h +//========================================================= + +#ifndef NODES_H +#define NODES_H + +//========================================================= +// DEFINE +//========================================================= +#define MAX_STACK_NODES 100 +#define NO_NODE -1 +#define MAX_NODE_HULLS 4 + +#define bits_NODE_LAND ( 1 << 0 ) // Land node, so nudge if necessary. +#define bits_NODE_AIR ( 1 << 1 ) // Air node, don't nudge. +#define bits_NODE_WATER ( 1 << 2 ) // Water node, don't nudge. +#define bits_NODE_GROUP_REALM (bits_NODE_LAND | bits_NODE_AIR | bits_NODE_WATER) + +//========================================================= +// Instance of a node. +//========================================================= +class CNode +{ +public: + Vector m_vecOrigin;// location of this node in space + Vector m_vecOriginPeek; // location of this node (LAND nodes are NODE_HEIGHT higher). + BYTE m_Region[3]; // Which of 256 regions do each of the coordinate belong? + int m_afNodeInfo;// bits that tell us more about this location + + int m_cNumLinks; // how many links this node has + int m_iFirstLink;// index of this node's first link in the link pool. + + // Where to start looking in the compressed routing table (offset into m_pRouteInfo). + // (4 hull sizes -- smallest to largest + fly/swim), and secondly, door capability. + // + int m_pNextBestNode[MAX_NODE_HULLS][2]; + + // Used in finding the shortest path. m_fClosestSoFar is -1 if not visited. + // Then it is the distance to the source. If another path uses this node + // and has a closer distance, then m_iPreviousNode is also updated. + // + float m_flClosestSoFar; // Used in finding the shortest path. + int m_iPreviousNode; + + short m_sHintType;// there is something interesting in the world at this node's position + short m_sHintActivity;// there is something interesting in the world at this node's position + float m_flHintYaw;// monster on this node should face this yaw to face the hint. +}; + +//========================================================= +// CLink - A link between 2 nodes +//========================================================= +#define bits_LINK_SMALL_HULL ( 1 << 0 )// headcrab box can fit through this connection +#define bits_LINK_HUMAN_HULL ( 1 << 1 )// player box can fit through this connection +#define bits_LINK_LARGE_HULL ( 1 << 2 )// big box can fit through this connection +#define bits_LINK_FLY_HULL ( 1 << 3 )// a flying big box can fit through this connection +#define bits_LINK_DISABLED ( 1 << 4 )// link is not valid when the set + +#define NODE_SMALL_HULL 0 +#define NODE_HUMAN_HULL 1 +#define NODE_LARGE_HULL 2 +#define NODE_FLY_HULL 3 + +class CLink +{ +public: + int m_iSrcNode;// the node that 'owns' this link ( keeps us from having to make reverse lookups ) + int m_iDestNode;// the node on the other end of the link. + + entvars_t *m_pLinkEnt;// the entity that blocks this connection (doors, etc) + + // m_szLinkEntModelname is not necessarily NULL terminated (so we can store it in a more alignment-friendly 4 bytes) + char m_szLinkEntModelname[ 4 ];// the unique name of the brush model that blocks the connection (this is kept for save/restore) + + int m_afLinkInfo;// information about this link + float m_flWeight;// length of the link line segment +}; + + +typedef struct +{ + int m_SortedBy[3]; + int m_CheckedEvent; +} DIST_INFO; + +typedef struct +{ + Vector v; + short n; // Nearest node or -1 if no node found. +} CACHE_ENTRY; + +//========================================================= +// CGraph +//========================================================= +#define GRAPH_VERSION (int)16// !!!increment this whever graph/node/link classes change, to obsolesce older disk files. +class CGraph +{ +public: + +// the graph has two flags, and should not be accessed unless both flags are TRUE! + BOOL m_fGraphPresent;// is the graph in memory? + BOOL m_fGraphPointersSet;// are the entity pointers for the graph all set? + BOOL m_fRoutingComplete; // are the optimal routes computed, yet? + + CNode *m_pNodes;// pointer to the memory block that contains all node info + CLink *m_pLinkPool;// big list of all node connections + char *m_pRouteInfo; // compressed routing information the nodes use. + + int m_cNodes;// total number of nodes + int m_cLinks;// total number of links + int m_nRouteInfo; // size of m_pRouteInfo in bytes. + + // Tables for making nearest node lookup faster. SortedBy provided nodes in a + // order of a particular coordinate. Instead of doing a binary search, RangeStart + // and RangeEnd let you get to the part of SortedBy that you are interested in. + // + // Once you have a point of interest, the only way you'll find a closer point is + // if at least one of the coordinates is closer than the ones you have now. So we + // search each range. After the search is exhausted, we know we have the closest + // node. + // +#define CACHE_SIZE 128 +#define NUM_RANGES 256 + DIST_INFO *m_di; // This is m_cNodes long, but the entries don't correspond to CNode entries. + int m_RangeStart[3][NUM_RANGES]; + int m_RangeEnd[3][NUM_RANGES]; + float m_flShortest; + int m_iNearest; + int m_minX, m_minY, m_minZ, m_maxX, m_maxY, m_maxZ; + int m_minBoxX, m_minBoxY, m_minBoxZ, m_maxBoxX, m_maxBoxY, m_maxBoxZ; + int m_CheckedCounter; + float m_RegionMin[3], m_RegionMax[3]; // The range of nodes. + CACHE_ENTRY m_Cache[CACHE_SIZE]; + + + int m_HashPrimes[16]; + short *m_pHashLinks; + int m_nHashLinks; + + + // kinda sleazy. In order to allow variety in active idles for monster groups in a room with more than one node, + // we keep track of the last node we searched from and store it here. Subsequent searches by other monsters will pick + // up where the last search stopped. + int m_iLastActiveIdleSearch; + + // another such system used to track the search for cover nodes, helps greatly with two monsters trying to get to the same node. + int m_iLastCoverSearch; + + // functions to create the graph + int LinkVisibleNodes ( CLink *pLinkPool, FILE *file, int *piBadNode ); + int RejectInlineLinks ( CLink *pLinkPool, FILE *file ); + int FindShortestPath ( int *piPath, int iStart, int iDest, int iHull, int afCapMask); + int FindNearestNode ( const Vector &vecOrigin, CBaseEntity *pEntity ); + int FindNearestNode ( const Vector &vecOrigin, int afNodeTypes ); + //int FindNearestLink ( const Vector &vecTestPoint, int *piNearestLink, BOOL *pfAlongLine ); + float PathLength( int iStart, int iDest, int iHull, int afCapMask ); + int NextNodeInRoute( int iCurrentNode, int iDest, int iHull, int iCap ); + + enum NODEQUERY { NODEGRAPH_DYNAMIC, NODEGRAPH_STATIC }; + // A static query means we're asking about the possiblity of handling this entity at ANY time + // A dynamic query means we're asking about it RIGHT NOW. So we should query the current state + int HandleLinkEnt ( int iNode, entvars_t *pevLinkEnt, int afCapMask, NODEQUERY queryType ); + entvars_t* LinkEntForLink ( CLink *pLink, CNode *pNode ); + void ShowNodeConnections ( int iNode ); + void InitGraph( void ); + int AllocNodes ( void ); + + int CheckNODFile(char *szMapName); + int FLoadGraph(char *szMapName); + int FSaveGraph(char *szMapName); + int FSetGraphPointers(void); + void CheckNode(Vector vecOrigin, int iNode); + + void BuildRegionTables(void); + void ComputeStaticRoutingTables(void); + void TestRoutingTables(void); + + void HashInsert(int iSrcNode, int iDestNode, int iKey); + void HashSearch(int iSrcNode, int iDestNode, int &iKey); + void HashChoosePrimes(int TableSize); + void BuildLinkLookups(void); + + void SortNodes(void); + + int HullIndex( const CBaseEntity *pEntity ); // what hull the monster uses + int NodeType( const CBaseEntity *pEntity ); // what node type the monster uses + inline int CapIndex( int afCapMask ) + { + if (afCapMask & (bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE)) + return 1; + return 0; + } + + + inline CNode &Node( int i ) + { +#ifdef _DEBUG + if ( !m_pNodes || i < 0 || i > m_cNodes ) + ALERT( at_error, "Bad Node!\n" ); +#endif + return m_pNodes[i]; + } + + inline CLink &Link( int i ) + { +#ifdef _DEBUG + if ( !m_pLinkPool || i < 0 || i > m_cLinks ) + ALERT( at_error, "Bad link!\n" ); +#endif + return m_pLinkPool[i]; + } + + inline CLink &NodeLink( int iNode, int iLink ) + { + return Link( Node( iNode ).m_iFirstLink + iLink ); + } + + inline CLink &NodeLink( const CNode &node, int iLink ) + { + return Link( node.m_iFirstLink + iLink ); + } + + inline int INodeLink ( int iNode, int iLink ) + { + return NodeLink( iNode, iLink ).m_iDestNode; + } + +#if 0 + inline CNode &SourceNode( int iNode, int iLink ) + { + return Node( NodeLink( iNode, iLink ).m_iSrcNode ); + } + + inline CNode &DestNode( int iNode, int iLink ) + { + return Node( NodeLink( iNode, iLink ).m_iDestNode ); + } + + inline CNode *PNodeLink ( int iNode, int iLink ) + { + return &DestNode( iNode, iLink ); + } +#endif +}; + +//========================================================= +// Nodes start out as ents in the level. The node graph +// is built, then these ents are discarded. +//========================================================= +class CNodeEnt : public CBaseEntity +{ + void Spawn( void ); + void KeyValue( KeyValueData *pkvd ); + virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + + short m_sHintType; + short m_sHintActivity; +}; + + +//========================================================= +// CStack - last in, first out. +//========================================================= +class CStack +{ +public: + CStack( void ); + void Push( int value ); + int Pop( void ); + int Top( void ); + int Empty( void ) { return m_level==0; } + int Size( void ) { return m_level; } + void CopyToArray ( int *piArray ); + +private: + int m_stack[ MAX_STACK_NODES ]; + int m_level; +}; + + +//========================================================= +// CQueue - first in, first out. +//========================================================= +class CQueue +{ +public: + + CQueue( void );// constructor + inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); } + inline int Empty ( void ) { return ( m_cSize == 0 ); } + //inline int Tail ( void ) { return ( m_queue[ m_tail ] ); } + inline int Size ( void ) { return ( m_cSize ); } + void Insert( int, float ); + int Remove( float & ); + +private: + int m_cSize; + struct tag_QUEUE_NODE + { + int Id; + float Priority; + } m_queue[ MAX_STACK_NODES ]; + int m_head; + int m_tail; +}; + +//========================================================= +// CQueuePriority - Priority queue (smallest item out first). +// +//========================================================= +class CQueuePriority +{ +public: + + CQueuePriority( void );// constructor + inline int Full ( void ) { return ( m_cSize == MAX_STACK_NODES ); } + inline int Empty ( void ) { return ( m_cSize == 0 ); } + //inline int Tail ( float & ) { return ( m_queue[ m_tail ].Id ); } + inline int Size ( void ) { return ( m_cSize ); } + void Insert( int, float ); + int Remove( float &); + +private: + int m_cSize; + struct tag_HEAP_NODE + { + int Id; + float Priority; + } m_heap[ MAX_STACK_NODES ]; + void Heap_SiftDown(int); + void Heap_SiftUp(void); + +}; + +//========================================================= +// hints - these MUST coincide with the HINTS listed under +// info_node in the FGD file! +//========================================================= +enum +{ + HINT_NONE = 0, + HINT_WORLD_DOOR, + HINT_WORLD_WINDOW, + HINT_WORLD_BUTTON, + HINT_WORLD_MACHINERY, + HINT_WORLD_LEDGE, + HINT_WORLD_LIGHT_SOURCE, + HINT_WORLD_HEAT_SOURCE, + HINT_WORLD_BLINKING_LIGHT, + HINT_WORLD_BRIGHT_COLORS, + HINT_WORLD_HUMAN_BLOOD, + HINT_WORLD_ALIEN_BLOOD, + + HINT_TACTICAL_EXIT = 100, + HINT_TACTICAL_VANTAGE, + HINT_TACTICAL_AMBUSH, + + HINT_STUKA_PERCH = 300, + HINT_STUKA_LANDING, +}; + +extern CGraph WorldGraph; + +#endif // NODES_H \ No newline at end of file diff --git a/rehlds/dlls/plane.h b/rehlds/dlls/plane.h new file mode 100644 index 0000000..a54f245 --- /dev/null +++ b/rehlds/dlls/plane.h @@ -0,0 +1,43 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PLANE_H +#define PLANE_H + +//========================================================= +// Plane +//========================================================= +class CPlane +{ +public: + CPlane ( void ); + + //========================================================= + // InitializePlane - Takes a normal for the plane and a + // point on the plane and + //========================================================= + void InitializePlane ( const Vector &vecNormal, const Vector &vecPoint ); + + //========================================================= + // PointInFront - determines whether the given vector is + // in front of the plane. + //========================================================= + BOOL PointInFront ( const Vector &vecPoint ); + + Vector m_vecNormal; + float m_flDist; + BOOL m_fInitialized; +}; + +#endif // PLANE_H diff --git a/rehlds/dlls/player.h b/rehlds/dlls/player.h new file mode 100644 index 0000000..0f90e73 --- /dev/null +++ b/rehlds/dlls/player.h @@ -0,0 +1,336 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PLAYER_H +#define PLAYER_H + + +#include "pm_materials.h" + + +#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet +#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet +#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. +#define PLAYER_MIN_BOUNCE_SPEED 200 +#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. + +// +// Player PHYSICS FLAGS bits +// +#define PFLAG_ONLADDER ( 1<<0 ) +#define PFLAG_ONSWING ( 1<<0 ) +#define PFLAG_ONTRAIN ( 1<<1 ) +#define PFLAG_ONBARNACLE ( 1<<2 ) +#define PFLAG_DUCKING ( 1<<3 ) // In the process of ducking, but totally squatted yet +#define PFLAG_USING ( 1<<4 ) // Using a continuous entity +#define PFLAG_OBSERVER ( 1<<5 ) // player is locked in stationary cam mode. Spectators can move, observers can't. + +// +// generic player +// +//----------------------------------------------------- +//This is Half-Life player entity +//----------------------------------------------------- +#define CSUITPLAYLIST 4 // max of 4 suit sentences queued up at any time + +#define SUIT_GROUP TRUE +#define SUIT_SENTENCE FALSE + +#define SUIT_REPEAT_OK 0 +#define SUIT_NEXT_IN_30SEC 30 +#define SUIT_NEXT_IN_1MIN 60 +#define SUIT_NEXT_IN_5MIN 300 +#define SUIT_NEXT_IN_10MIN 600 +#define SUIT_NEXT_IN_30MIN 1800 +#define SUIT_NEXT_IN_1HOUR 3600 + +#define CSUITNOREPEAT 32 + +#define SOUND_FLASHLIGHT_ON "items/flashlight1.wav" +#define SOUND_FLASHLIGHT_OFF "items/flashlight1.wav" + +#define TEAM_NAME_LENGTH 16 + +typedef enum +{ + PLAYER_IDLE, + PLAYER_WALK, + PLAYER_JUMP, + PLAYER_SUPERJUMP, + PLAYER_DIE, + PLAYER_ATTACK1, +} PLAYER_ANIM; + +#define MAX_ID_RANGE 2048 +#define SBAR_STRING_SIZE 128 + +enum sbar_data +{ + SBAR_ID_TARGETNAME = 1, + SBAR_ID_TARGETHEALTH, + SBAR_ID_TARGETARMOR, + SBAR_END, +}; + +#define CHAT_INTERVAL 1.0f + +class CBasePlayer : public CBaseMonster +{ +public: + + // Spectator camera + void Observer_FindNextPlayer( bool bReverse ); + void Observer_HandleButtons(); + void Observer_SetMode( int iMode ); + void Observer_CheckTarget(); + void Observer_CheckProperties(); + EHANDLE m_hObserverTarget; + float m_flNextObserverInput; + int m_iObserverWeapon; // weapon of current tracked target + int m_iObserverLastMode;// last used observer mode + int IsObserver() { return pev->iuser1; }; + int random_seed; // See that is shared between client & server for shared weapons code + + int m_iPlayerSound;// the index of the sound list slot reserved for this player + int m_iTargetVolume;// ideal sound volume. + int m_iWeaponVolume;// how loud the player's weapon is right now. + int m_iExtraSoundTypes;// additional classification for this weapon's sound + int m_iWeaponFlash;// brightness of the weapon flash + float m_flStopExtraSoundTime; + + float m_flFlashLightTime; // Time until next battery draw/Recharge + int m_iFlashBattery; // Flashlight Battery Draw + + int m_afButtonLast; + int m_afButtonPressed; + int m_afButtonReleased; + + edict_t *m_pentSndLast; // last sound entity to modify player room type + float m_flSndRoomtype; // last roomtype set by sound entity + float m_flSndRange; // dist from player to sound entity + + float m_flFallVelocity; + + int m_rgItems[MAX_ITEMS]; + int m_fKnownItem; // True when a new item needs to be added + int m_fNewAmmo; // True when a new item has been added + + unsigned int m_afPhysicsFlags; // physics flags - set when 'normal' physics should be revisited or overriden + float m_fNextSuicideTime; // the time after which the player can next use the suicide command + + +// these are time-sensitive things that we keep track of + float m_flTimeStepSound; // when the last stepping sound was made + float m_flTimeWeaponIdle; // when to play another weapon idle animation. + float m_flSwimTime; // how long player has been underwater + float m_flDuckTime; // how long we've been ducking + float m_flWallJumpTime; // how long until next walljump + + float m_flSuitUpdate; // when to play next suit update + int m_rgSuitPlayList[CSUITPLAYLIST];// next sentencenum to play for suit update + int m_iSuitPlayNext; // next sentence slot for queue storage; + int m_rgiSuitNoRepeat[CSUITNOREPEAT]; // suit sentence no repeat list + float m_rgflSuitNoRepeatTime[CSUITNOREPEAT]; // how long to wait before allowing repeat + int m_lastDamageAmount; // Last damage taken + float m_tbdPrev; // Time-based damage timer + + float m_flgeigerRange; // range to nearest radiation source + float m_flgeigerDelay; // delay per update of range msg to client + int m_igeigerRangePrev; + int m_iStepLeft; // alternate left/right foot stepping sound + char m_szTextureName[CBTEXTURENAMEMAX]; // current texture name we're standing on + char m_chTextureType; // current texture type + + int m_idrowndmg; // track drowning damage taken + int m_idrownrestored; // track drowning damage restored + + int m_bitsHUDDamage; // Damage bits for the current fame. These get sent to + // the hude via the DAMAGE message + BOOL m_fInitHUD; // True when deferred HUD restart msg needs to be sent + BOOL m_fGameHUDInitialized; + int m_iTrain; // Train control position + BOOL m_fWeapon; // Set this to FALSE to force a reset of the current weapon HUD info + + EHANDLE m_pTank; // the tank which the player is currently controlling, NULL if no tank + float m_fDeadTime; // the time at which the player died (used in PlayerDeathThink()) + + BOOL m_fNoPlayerSound; // a debugging feature. Player makes no sound if this is true. + BOOL m_fLongJump; // does this player have the longjump module? + + float m_tSneaking; + int m_iUpdateTime; // stores the number of frame ticks before sending HUD update messages + int m_iClientHealth; // the health currently known by the client. If this changes, send a new + int m_iClientBattery; // the Battery currently known by the client. If this changes, send a new + int m_iHideHUD; // the players hud weapon info is to be hidden + int m_iClientHideHUD; + int m_iFOV; // field of view + int m_iClientFOV; // client's known FOV + // usable player items + CBasePlayerItem *m_rgpPlayerItems[MAX_ITEM_TYPES]; + CBasePlayerItem *m_pActiveItem; + CBasePlayerItem *m_pClientActiveItem; // client version of the active item + CBasePlayerItem *m_pLastItem; + // shared ammo slots + int m_rgAmmo[MAX_AMMO_SLOTS]; + int m_rgAmmoLast[MAX_AMMO_SLOTS]; + + Vector m_vecAutoAim; + BOOL m_fOnTarget; + int m_iDeaths; + float m_iRespawnFrames; // used in PlayerDeathThink() to make sure players can always respawn + + int m_lastx, m_lasty; // These are the previous update's crosshair angles, DON"T SAVE/RESTORE + + int m_nCustomSprayFrames;// Custom clan logo frames for this player + float m_flNextDecalTime;// next time this player can spray a decal + + char m_szTeamName[TEAM_NAME_LENGTH]; + + virtual void Spawn( void ); + void Pain( void ); + +// virtual void Think( void ); + virtual void Jump( void ); + virtual void Duck( void ); + virtual void PreThink( void ); + virtual void PostThink( void ); + virtual Vector GetGunPosition( void ); + virtual int TakeHealth( float flHealth, int bitsDamageType ); + virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType); + virtual int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + virtual void Killed( entvars_t *pevAttacker, int iGib ); + virtual Vector BodyTarget( const Vector &posSrc ) { return Center( ) + pev->view_ofs * RANDOM_FLOAT( 0.5, 1.1 ); }; // position to shoot at + virtual void StartSneaking( void ) { m_tSneaking = gpGlobals->time - 1; } + virtual void StopSneaking( void ) { m_tSneaking = gpGlobals->time + 30; } + virtual BOOL IsSneaking( void ) { return m_tSneaking <= gpGlobals->time; } + virtual BOOL IsAlive( void ) { return (pev->deadflag == DEAD_NO) && pev->health > 0; } + virtual BOOL ShouldFadeOnDeath( void ) { return FALSE; } + virtual BOOL IsPlayer( void ) { return TRUE; } // Spectators should return FALSE for this, they aren't "players" as far as game logic is concerned + + virtual BOOL IsNetClient( void ) { return TRUE; } // Bots should return FALSE for this, they can't receive NET messages + // Spectators should return TRUE for this + virtual const char *TeamID( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + void RenewItems(void); + void PackDeadPlayerItems( void ); + void RemoveAllItems( BOOL removeSuit ); + BOOL SwitchWeapon( CBasePlayerItem *pWeapon ); + + // JOHN: sends custom messages if player HUD data has changed (eg health, ammo) + virtual void UpdateClientData( void ); + + static TYPEDESCRIPTION m_playerSaveData[]; + + // Player is moved across the transition by other means + virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual void Precache( void ); + BOOL IsOnLadder( void ); + BOOL FlashlightIsOn( void ); + void FlashlightTurnOn( void ); + void FlashlightTurnOff( void ); + + void UpdatePlayerSound ( void ); + void DeathSound ( void ); + + int Classify ( void ); + void SetAnimation( PLAYER_ANIM playerAnim ); + void SetWeaponAnimType( const char *szExtention ); + char m_szAnimExtention[32]; + + // custom player functions + virtual void ImpulseCommands( void ); + void CheatImpulseCommands( int iImpulse ); + + void StartDeathCam( void ); + void StartObserver( Vector vecPosition, Vector vecViewAngle ); + + void AddPoints( int score, BOOL bAllowNegativeScore ); + void AddPointsToTeam( int score, BOOL bAllowNegativeScore ); + BOOL AddPlayerItem( CBasePlayerItem *pItem ); + BOOL RemovePlayerItem( CBasePlayerItem *pItem ); + void DropPlayerItem ( char *pszItemName ); + BOOL HasPlayerItem( CBasePlayerItem *pCheckItem ); + BOOL HasNamedPlayerItem( const char *pszItemName ); + BOOL HasWeapons( void );// do I have ANY weapons? + void SelectPrevItem( int iItem ); + void SelectNextItem( int iItem ); + void SelectLastItem(void); + void SelectItem(const char *pstr); + void ItemPreFrame( void ); + void ItemPostFrame( void ); + void GiveNamedItem( const char *szName ); + void EnableControl(BOOL fControl); + + int GiveAmmo( int iAmount, char *szName, int iMax ); + void SendAmmoUpdate(void); + + void WaterMove( void ); + void EXPORT PlayerDeathThink( void ); + void PlayerUse( void ); + + void CheckSuitUpdate(); + void SetSuitUpdate(char *name, int fgroup, int iNoRepeat); + void UpdateGeigerCounter( void ); + void CheckTimeBasedDamage( void ); + + BOOL FBecomeProne ( void ); + void BarnacleVictimBitten ( entvars_t *pevBarnacle ); + void BarnacleVictimReleased ( void ); + static int GetAmmoIndex(const char *psz); + int AmmoInventory( int iAmmoIndex ); + int Illumination( void ); + + void ResetAutoaim( void ); + Vector GetAutoaimVector( float flDelta ); + Vector AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ); + + void ForceClientDllUpdate( void ); // Forces all client .dll specific data to be resent to client. + + void DeathMessage( entvars_t *pevKiller ); + + void SetCustomDecalFrames( int nFrames ); + int GetCustomDecalFrames( void ); + + void CBasePlayer::TabulateAmmo( void ); + + float m_flStartCharge; + float m_flAmmoStartCharge; + float m_flPlayAftershock; + float m_flNextAmmoBurn;// while charging, when to absorb another unit of player's ammo? + + //Player ID + void InitStatusBar( void ); + void UpdateStatusBar( void ); + int m_izSBarState[ SBAR_END ]; + float m_flNextSBarUpdateTime; + float m_flStatusBarDisappearDelay; + char m_SbarString0[ SBAR_STRING_SIZE ]; + char m_SbarString1[ SBAR_STRING_SIZE ]; + + float m_flNextChatTime; + +}; + +#define AUTOAIM_2DEGREES 0.0348994967025 +#define AUTOAIM_5DEGREES 0.08715574274766 +#define AUTOAIM_8DEGREES 0.1391731009601 +#define AUTOAIM_10DEGREES 0.1736481776669 + + +extern int gmsgHudText; +extern BOOL gInitHUD; + +#endif // PLAYER_H diff --git a/rehlds/dlls/saverestore.h b/rehlds/dlls/saverestore.h new file mode 100644 index 0000000..3814aaa --- /dev/null +++ b/rehlds/dlls/saverestore.h @@ -0,0 +1,169 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Implementation in UTIL.CPP +#ifndef SAVERESTORE_H +#define SAVERESTORE_H + +class CBaseEntity; + +class CSaveRestoreBuffer +{ +public: + CSaveRestoreBuffer( void ); + CSaveRestoreBuffer( SAVERESTOREDATA *pdata ); + ~CSaveRestoreBuffer( void ); + + int EntityIndex( entvars_t *pevLookup ); + int EntityIndex( edict_t *pentLookup ); + int EntityIndex( EOFFSET eoLookup ); + int EntityIndex( CBaseEntity *pEntity ); + + int EntityFlags( int entityIndex, int flags ) { return EntityFlagsSet( entityIndex, 0 ); } + int EntityFlagsSet( int entityIndex, int flags ); + + edict_t *EntityFromIndex( int entityIndex ); + + unsigned short TokenHash( const char *pszToken ); + +protected: + SAVERESTOREDATA *m_pdata; + void BufferRewind( int size ); + unsigned int HashString( const char *pszToken ); +}; + + +class CSave : public CSaveRestoreBuffer +{ +public: + CSave( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) {}; + + void WriteShort( const char *pname, const short *value, int count ); + void WriteInt( const char *pname, const int *value, int count ); // Save an int + void WriteFloat( const char *pname, const float *value, int count ); // Save a float + void WriteTime( const char *pname, const float *value, int count ); // Save a float (timevalue) + void WriteData( const char *pname, int size, const char *pdata ); // Save a binary data block + void WriteString( const char *pname, const char *pstring ); // Save a null-terminated string + void WriteString( const char *pname, const int *stringId, int count ); // Save a null-terminated string (engine string) + void WriteVector( const char *pname, const Vector &value ); // Save a vector + void WriteVector( const char *pname, const float *value, int count ); // Save a vector + void WritePositionVector( const char *pname, const Vector &value ); // Offset for landmark if necessary + void WritePositionVector( const char *pname, const float *value, int count ); // array of pos vectors + void WriteFunction( const char *pname, void **value, int count ); // Save a function pointer + int WriteEntVars( const char *pname, entvars_t *pev ); // Save entvars_t (entvars_t) + int WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); + +private: + int DataEmpty( const char *pdata, int size ); + void BufferField( const char *pname, int size, const char *pdata ); + void BufferString( char *pdata, int len ); + void BufferData( const char *pdata, int size ); + void BufferHeader( const char *pname, int size ); +}; + +typedef struct +{ + unsigned short size; + unsigned short token; + char *pData; +} HEADER; + +class CRestore : public CSaveRestoreBuffer +{ +public: + CRestore( SAVERESTOREDATA *pdata ) : CSaveRestoreBuffer( pdata ) { m_global = 0; m_precache = TRUE; } + int ReadEntVars( const char *pname, entvars_t *pev ); // entvars_t + int ReadFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount ); + int ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData ); + int ReadInt( void ); + short ReadShort( void ); + int ReadNamedInt( const char *pName ); + char *ReadNamedString( const char *pName ); + int Empty( void ) { return (m_pdata == NULL) || ((m_pdata->pCurrentData-m_pdata->pBaseData)>=m_pdata->bufferSize); } + inline void SetGlobalMode( int global ) { m_global = global; } + void PrecacheMode( BOOL mode ) { m_precache = mode; } + +private: + char *BufferPointer( void ); + void BufferReadBytes( char *pOutput, int size ); + void BufferSkipBytes( int bytes ); + int BufferSkipZString( void ); + int BufferCheckZString( const char *string ); + + void BufferReadHeader( HEADER *pheader ); + + int m_global; // Restoring a global entity? + BOOL m_precache; +}; + +#define MAX_ENTITYARRAY 64 + +//#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +#define IMPLEMENT_SAVERESTORE(derivedClass,baseClass) \ + int derivedClass::Save( CSave &save )\ + {\ + if ( !baseClass::Save(save) )\ + return 0;\ + return save.WriteFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ + }\ + int derivedClass::Restore( CRestore &restore )\ + {\ + if ( !baseClass::Restore(restore) )\ + return 0;\ + return restore.ReadFields( #derivedClass, this, m_SaveData, ARRAYSIZE(m_SaveData) );\ + } + + +typedef enum { GLOBAL_OFF = 0, GLOBAL_ON = 1, GLOBAL_DEAD = 2 } GLOBALESTATE; + +typedef struct globalentity_s globalentity_t; + +struct globalentity_s +{ + char name[64]; + char levelName[32]; + GLOBALESTATE state; + globalentity_t *pNext; +}; + +class CGlobalState +{ +public: + CGlobalState(); + void Reset( void ); + void ClearStates( void ); + void EntityAdd( string_t globalname, string_t mapName, GLOBALESTATE state ); + void EntitySetState( string_t globalname, GLOBALESTATE state ); + void EntityUpdate( string_t globalname, string_t mapname ); + const globalentity_t *EntityFromTable( string_t globalname ); + GLOBALESTATE EntityGetState( string_t globalname ); + int EntityInTable( string_t globalname ) { return (Find( globalname ) != NULL) ? 1 : 0; } + int Save( CSave &save ); + int Restore( CRestore &restore ); + static TYPEDESCRIPTION m_SaveData[]; + +//#ifdef _DEBUG + void DumpGlobals( void ); +//#endif + +private: + globalentity_t *Find( string_t globalname ); + globalentity_t *m_pList; + int m_listCount; +}; + +extern CGlobalState gGlobalState; + +#endif //SAVERESTORE_H diff --git a/rehlds/dlls/schedule.h b/rehlds/dlls/schedule.h new file mode 100644 index 0000000..7d9ff17 --- /dev/null +++ b/rehlds/dlls/schedule.h @@ -0,0 +1,290 @@ +/*** +* +* Copyright (c) 1996-2001, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* This source code contains proprietary and confidential information of +* Valve LLC and its suppliers. Access to this code is restricted to +* persons who have executed a written SDK license with Valve. Any access, +* use or distribution of this code by or to any unlicensed person is illegal. +* +****/ +//========================================================= +// Scheduling +//========================================================= + +#ifndef SCHEDULE_H +#define SCHEDULE_H + +#define TASKSTATUS_NEW 0 // Just started +#define TASKSTATUS_RUNNING 1 // Running task & movement +#define TASKSTATUS_RUNNING_MOVEMENT 2 // Just running movement +#define TASKSTATUS_RUNNING_TASK 3 // Just running task +#define TASKSTATUS_COMPLETE 4 // Completed, get next task + + +//========================================================= +// These are the schedule types +//========================================================= +typedef enum +{ + SCHED_NONE = 0, + SCHED_IDLE_STAND, + SCHED_IDLE_WALK, + SCHED_WAKE_ANGRY, + SCHED_WAKE_CALLED, + SCHED_ALERT_FACE, + SCHED_ALERT_SMALL_FLINCH, + SCHED_ALERT_BIG_FLINCH, + SCHED_ALERT_STAND, + SCHED_INVESTIGATE_SOUND, + SCHED_COMBAT_FACE, + SCHED_COMBAT_STAND, + SCHED_CHASE_ENEMY, + SCHED_CHASE_ENEMY_FAILED, + SCHED_VICTORY_DANCE, + SCHED_TARGET_FACE, + SCHED_TARGET_CHASE, + SCHED_SMALL_FLINCH, + SCHED_TAKE_COVER_FROM_ENEMY, + SCHED_TAKE_COVER_FROM_BEST_SOUND, + SCHED_TAKE_COVER_FROM_ORIGIN, + SCHED_COWER, // usually a last resort! + SCHED_MELEE_ATTACK1, + SCHED_MELEE_ATTACK2, + SCHED_RANGE_ATTACK1, + SCHED_RANGE_ATTACK2, + SCHED_SPECIAL_ATTACK1, + SCHED_SPECIAL_ATTACK2, + SCHED_STANDOFF, + SCHED_ARM_WEAPON, + SCHED_RELOAD, + SCHED_GUARD, + SCHED_AMBUSH, + SCHED_DIE, + SCHED_WAIT_TRIGGER, + SCHED_FOLLOW, + SCHED_SLEEP, + SCHED_WAKE, + SCHED_BARNACLE_VICTIM_GRAB, + SCHED_BARNACLE_VICTIM_CHOMP, + SCHED_AISCRIPT, + SCHED_FAIL, + + LAST_COMMON_SCHEDULE // Leave this at the bottom +} SCHEDULE_TYPE; + +//========================================================= +// These are the shared tasks +//========================================================= +typedef enum +{ + TASK_INVALID = 0, + TASK_WAIT, + TASK_WAIT_FACE_ENEMY, + TASK_WAIT_PVS, + TASK_SUGGEST_STATE, + TASK_WALK_TO_TARGET, + TASK_RUN_TO_TARGET, + TASK_MOVE_TO_TARGET_RANGE, + TASK_GET_PATH_TO_ENEMY, + TASK_GET_PATH_TO_ENEMY_LKP, + TASK_GET_PATH_TO_ENEMY_CORPSE, + TASK_GET_PATH_TO_LEADER, + TASK_GET_PATH_TO_SPOT, + TASK_GET_PATH_TO_TARGET, + TASK_GET_PATH_TO_HINTNODE, + TASK_GET_PATH_TO_LASTPOSITION, + TASK_GET_PATH_TO_BESTSOUND, + TASK_GET_PATH_TO_BESTSCENT, + TASK_RUN_PATH, + TASK_WALK_PATH, + TASK_STRAFE_PATH, + TASK_CLEAR_MOVE_WAIT, + TASK_STORE_LASTPOSITION, + TASK_CLEAR_LASTPOSITION, + TASK_PLAY_ACTIVE_IDLE, + TASK_FIND_HINTNODE, + TASK_CLEAR_HINTNODE, + TASK_SMALL_FLINCH, + TASK_FACE_IDEAL, + TASK_FACE_ROUTE, + TASK_FACE_ENEMY, + TASK_FACE_HINTNODE, + TASK_FACE_TARGET, + TASK_FACE_LASTPOSITION, + TASK_RANGE_ATTACK1, + TASK_RANGE_ATTACK2, + TASK_MELEE_ATTACK1, + TASK_MELEE_ATTACK2, + TASK_RELOAD, + TASK_RANGE_ATTACK1_NOTURN, + TASK_RANGE_ATTACK2_NOTURN, + TASK_MELEE_ATTACK1_NOTURN, + TASK_MELEE_ATTACK2_NOTURN, + TASK_RELOAD_NOTURN, + TASK_SPECIAL_ATTACK1, + TASK_SPECIAL_ATTACK2, + TASK_CROUCH, + TASK_STAND, + TASK_GUARD, + TASK_STEP_LEFT, + TASK_STEP_RIGHT, + TASK_STEP_FORWARD, + TASK_STEP_BACK, + TASK_DODGE_LEFT, + TASK_DODGE_RIGHT, + TASK_SOUND_ANGRY, + TASK_SOUND_DEATH, + TASK_SET_ACTIVITY, + TASK_SET_SCHEDULE, + TASK_SET_FAIL_SCHEDULE, + TASK_CLEAR_FAIL_SCHEDULE, + TASK_PLAY_SEQUENCE, + TASK_PLAY_SEQUENCE_FACE_ENEMY, + TASK_PLAY_SEQUENCE_FACE_TARGET, + TASK_SOUND_IDLE, + TASK_SOUND_WAKE, + TASK_SOUND_PAIN, + TASK_SOUND_DIE, + TASK_FIND_COVER_FROM_BEST_SOUND,// tries lateral cover first, then node cover + TASK_FIND_COVER_FROM_ENEMY,// tries lateral cover first, then node cover + TASK_FIND_LATERAL_COVER_FROM_ENEMY, + TASK_FIND_NODE_COVER_FROM_ENEMY, + TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY,// data for this one is the MAXIMUM acceptable distance to the cover. + TASK_FIND_FAR_NODE_COVER_FROM_ENEMY,// data for this one is there MINIMUM aceptable distance to the cover. + TASK_FIND_COVER_FROM_ORIGIN, + TASK_EAT, + TASK_DIE, + TASK_WAIT_FOR_SCRIPT, + TASK_PLAY_SCRIPT, + TASK_ENABLE_SCRIPT, + TASK_PLANT_ON_SCRIPT, + TASK_FACE_SCRIPT, + TASK_WAIT_RANDOM, + TASK_WAIT_INDEFINITE, + TASK_STOP_MOVING, + TASK_TURN_LEFT, + TASK_TURN_RIGHT, + TASK_REMEMBER, + TASK_FORGET, + TASK_WAIT_FOR_MOVEMENT, // wait until MovementIsComplete() + LAST_COMMON_TASK, // LEAVE THIS AT THE BOTTOM!! (sjb) +} SHARED_TASKS; + + +// These go in the flData member of the TASK_WALK_TO_TARGET, TASK_RUN_TO_TARGET +enum +{ + TARGET_MOVE_NORMAL = 0, + TARGET_MOVE_SCRIPTED = 1, +}; + + +// A goal should be used for a task that requires several schedules to complete. +// The goal index should indicate which schedule (ordinally) the monster is running. +// That way, when tasks fail, the AI can make decisions based on the context of the +// current goal and sequence rather than just the current schedule. +enum +{ + GOAL_ATTACK_ENEMY, + GOAL_MOVE, + GOAL_TAKE_COVER, + GOAL_MOVE_TARGET, + GOAL_EAT, +}; + +// an array of tasks is a task list +// an array of schedules is a schedule list +struct Task_t +{ + + int iTask; + float flData; +}; + +struct Schedule_t +{ + + Task_t *pTasklist; + int cTasks; + int iInterruptMask;// a bit mask of conditions that can interrupt this schedule + + // a more specific mask that indicates which TYPES of sounds will interrupt the schedule in the + // event that the schedule is broken by COND_HEAR_SOUND + int iSoundMask; + const char *pName; +}; + +// an array of waypoints makes up the monster's route. +// !!!LATER- this declaration doesn't belong in this file. +struct WayPoint_t +{ + Vector vecLocation; + int iType; +}; + +// these MoveFlag values are assigned to a WayPoint's TYPE in order to demonstrate the +// type of movement the monster should use to get there. +#define bits_MF_TO_TARGETENT ( 1 << 0 ) // local move to targetent. +#define bits_MF_TO_ENEMY ( 1 << 1 ) // local move to enemy +#define bits_MF_TO_COVER ( 1 << 2 ) // local move to a hiding place +#define bits_MF_TO_DETOUR ( 1 << 3 ) // local move to detour point. +#define bits_MF_TO_PATHCORNER ( 1 << 4 ) // local move to a path corner +#define bits_MF_TO_NODE ( 1 << 5 ) // local move to a node +#define bits_MF_TO_LOCATION ( 1 << 6 ) // local move to an arbitrary point +#define bits_MF_IS_GOAL ( 1 << 7 ) // this waypoint is the goal of the whole move. +#define bits_MF_DONT_SIMPLIFY ( 1 << 8 ) // Don't let the route code simplify this waypoint + +// If you define any flags that aren't _TO_ flags, add them here so we can mask +// them off when doing compares. +#define bits_MF_NOT_TO_MASK (bits_MF_IS_GOAL | bits_MF_DONT_SIMPLIFY) + +#define MOVEGOAL_NONE (0) +#define MOVEGOAL_TARGETENT (bits_MF_TO_TARGETENT) +#define MOVEGOAL_ENEMY (bits_MF_TO_ENEMY) +#define MOVEGOAL_PATHCORNER (bits_MF_TO_PATHCORNER) +#define MOVEGOAL_LOCATION (bits_MF_TO_LOCATION) +#define MOVEGOAL_NODE (bits_MF_TO_NODE) + +// these bits represent conditions that may befall the monster, of which some are allowed +// to interrupt certain schedules. +#define bits_COND_NO_AMMO_LOADED ( 1 << 0 ) // weapon needs to be reloaded! +#define bits_COND_SEE_HATE ( 1 << 1 ) // see something that you hate +#define bits_COND_SEE_FEAR ( 1 << 2 ) // see something that you are afraid of +#define bits_COND_SEE_DISLIKE ( 1 << 3 ) // see something that you dislike +#define bits_COND_SEE_ENEMY ( 1 << 4 ) // target entity is in full view. +#define bits_COND_ENEMY_OCCLUDED ( 1 << 5 ) // target entity occluded by the world +#define bits_COND_SMELL_FOOD ( 1 << 6 ) +#define bits_COND_ENEMY_TOOFAR ( 1 << 7 ) +#define bits_COND_LIGHT_DAMAGE ( 1 << 8 ) // hurt a little +#define bits_COND_HEAVY_DAMAGE ( 1 << 9 ) // hurt a lot +#define bits_COND_CAN_RANGE_ATTACK1 ( 1 << 10) +#define bits_COND_CAN_MELEE_ATTACK1 ( 1 << 11) +#define bits_COND_CAN_RANGE_ATTACK2 ( 1 << 12) +#define bits_COND_CAN_MELEE_ATTACK2 ( 1 << 13) +// #define bits_COND_CAN_RANGE_ATTACK3 ( 1 << 14) +#define bits_COND_PROVOKED ( 1 << 15) +#define bits_COND_NEW_ENEMY ( 1 << 16) +#define bits_COND_HEAR_SOUND ( 1 << 17) // there is an interesting sound +#define bits_COND_SMELL ( 1 << 18) // there is an interesting scent +#define bits_COND_ENEMY_FACING_ME ( 1 << 19) // enemy is facing me +#define bits_COND_ENEMY_DEAD ( 1 << 20) // enemy was killed. If you get this in combat, try to find another enemy. If you get it in alert, victory dance. +#define bits_COND_SEE_CLIENT ( 1 << 21) // see a client +#define bits_COND_SEE_NEMESIS ( 1 << 22) // see my nemesis + +#define bits_COND_SPECIAL1 ( 1 << 28) // Defined by individual monster +#define bits_COND_SPECIAL2 ( 1 << 29) // Defined by individual monster + +#define bits_COND_TASK_FAILED ( 1 << 30) +#define bits_COND_SCHEDULE_DONE ( 1 << 31) + + +#define bits_COND_ALL_SPECIAL (bits_COND_SPECIAL1 | bits_COND_SPECIAL2) + +#define bits_COND_CAN_ATTACK (bits_COND_CAN_RANGE_ATTACK1 | bits_COND_CAN_MELEE_ATTACK1 | bits_COND_CAN_RANGE_ATTACK2 | bits_COND_CAN_MELEE_ATTACK2) + +#endif // SCHEDULE_H diff --git a/rehlds/dlls/scriptevent.h b/rehlds/dlls/scriptevent.h new file mode 100644 index 0000000..9a02bd6 --- /dev/null +++ b/rehlds/dlls/scriptevent.h @@ -0,0 +1,29 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef SCRIPTEVENT_H +#define SCRIPTEVENT_H + +#define SCRIPT_EVENT_DEAD 1000 // character is now dead +#define SCRIPT_EVENT_NOINTERRUPT 1001 // does not allow interrupt +#define SCRIPT_EVENT_CANINTERRUPT 1002 // will allow interrupt +#define SCRIPT_EVENT_FIREEVENT 1003 // event now fires +#define SCRIPT_EVENT_SOUND 1004 // Play named wave file (on CHAN_BODY) +#define SCRIPT_EVENT_SENTENCE 1005 // Play named sentence +#define SCRIPT_EVENT_INAIR 1006 // Leave the character in air at the end of the sequence (don't find the floor) +#define SCRIPT_EVENT_ENDANIMATION 1007 // Set the animation by name after the sequence completes +#define SCRIPT_EVENT_SOUND_VOICE 1008 // Play named wave file (on CHAN_VOICE) +#define SCRIPT_EVENT_SENTENCE_RND1 1009 // Play sentence group 25% of the time +#define SCRIPT_EVENT_NOT_DEAD 1010 // Bring back to life (for life/death sequences) +#endif //SCRIPTEVENT_H diff --git a/rehlds/dlls/skill.h b/rehlds/dlls/skill.h new file mode 100644 index 0000000..4434071 --- /dev/null +++ b/rehlds/dlls/skill.h @@ -0,0 +1,147 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// skill.h - skill level concerns +//========================================================= + +struct skilldata_t +{ + + int iSkillLevel; // game skill level + +// Monster Health & Damage + float agruntHealth; + float agruntDmgPunch; + + float apacheHealth; + + float barneyHealth; + + float bigmommaHealthFactor; // Multiply each node's health by this + float bigmommaDmgSlash; // melee attack damage + float bigmommaDmgBlast; // mortar attack damage + float bigmommaRadiusBlast; // mortar attack radius + + float bullsquidHealth; + float bullsquidDmgBite; + float bullsquidDmgWhip; + float bullsquidDmgSpit; + + float gargantuaHealth; + float gargantuaDmgSlash; + float gargantuaDmgFire; + float gargantuaDmgStomp; + + float hassassinHealth; + + float headcrabHealth; + float headcrabDmgBite; + + float hgruntHealth; + float hgruntDmgKick; + float hgruntShotgunPellets; + float hgruntGrenadeSpeed; + + float houndeyeHealth; + float houndeyeDmgBlast; + + float slaveHealth; + float slaveDmgClaw; + float slaveDmgClawrake; + float slaveDmgZap; + + float ichthyosaurHealth; + float ichthyosaurDmgShake; + + float leechHealth; + float leechDmgBite; + + float controllerHealth; + float controllerDmgZap; + float controllerSpeedBall; + float controllerDmgBall; + + float nihilanthHealth; + float nihilanthZap; + + float scientistHealth; + + float snarkHealth; + float snarkDmgBite; + float snarkDmgPop; + + float zombieHealth; + float zombieDmgOneSlash; + float zombieDmgBothSlash; + + float turretHealth; + float miniturretHealth; + float sentryHealth; + + +// Player Weapons + float plrDmgCrowbar; + float plrDmg9MM; + float plrDmg357; + float plrDmgMP5; + float plrDmgM203Grenade; + float plrDmgBuckshot; + float plrDmgCrossbowClient; + float plrDmgCrossbowMonster; + float plrDmgRPG; + float plrDmgGauss; + float plrDmgEgonNarrow; + float plrDmgEgonWide; + float plrDmgHornet; + float plrDmgHandGrenade; + float plrDmgSatchel; + float plrDmgTripmine; + +// weapons shared by monsters + float monDmg9MM; + float monDmgMP5; + float monDmg12MM; + float monDmgHornet; + +// health/suit charge + float suitchargerCapacity; + float batteryCapacity; + float healthchargerCapacity; + float healthkitCapacity; + float scientistHeal; + +// monster damage adj + float monHead; + float monChest; + float monStomach; + float monLeg; + float monArm; + +// player damage adj + float plrHead; + float plrChest; + float plrStomach; + float plrLeg; + float plrArm; +}; + +extern DLL_GLOBAL skilldata_t gSkillData; +float GetSkillCvar( char *pName ); + +extern DLL_GLOBAL int g_iSkillLevel; + +#define SKILL_EASY 1 +#define SKILL_MEDIUM 2 +#define SKILL_HARD 3 diff --git a/rehlds/dlls/soundent.h b/rehlds/dlls/soundent.h new file mode 100644 index 0000000..2393cb4 --- /dev/null +++ b/rehlds/dlls/soundent.h @@ -0,0 +1,95 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +//========================================================= +// Soundent.h - the entity that spawns when the world +// spawns, and handles the world's active and free sound +// lists. +//========================================================= + +#define MAX_WORLD_SOUNDS 64 // maximum number of sounds handled by the world at one time. + +#define bits_SOUND_NONE 0 +#define bits_SOUND_COMBAT ( 1 << 0 )// gunshots, explosions +#define bits_SOUND_WORLD ( 1 << 1 )// door opening/closing, glass breaking +#define bits_SOUND_PLAYER ( 1 << 2 )// all noises generated by player. walking, shooting, falling, splashing +#define bits_SOUND_CARCASS ( 1 << 3 )// dead body +#define bits_SOUND_MEAT ( 1 << 4 )// gib or pork chop +#define bits_SOUND_DANGER ( 1 << 5 )// pending danger. Grenade that is about to explode, explosive barrel that is damaged, falling crate +#define bits_SOUND_GARBAGE ( 1 << 6 )// trash cans, banana peels, old fast food bags. + +#define bits_ALL_SOUNDS 0xFFFFFFFF + +#define SOUNDLIST_EMPTY -1 + +#define SOUNDLISTTYPE_FREE 1// identifiers passed to functions that can operate on either list, to indicate which list to operate on. +#define SOUNDLISTTYPE_ACTIVE 2 + +#define SOUND_NEVER_EXPIRE -1 // with this set as a sound's ExpireTime, the sound will never expire. + +//========================================================= +// CSound - an instance of a sound in the world. +//========================================================= +class CSound +{ +public: + + void Clear ( void ); + void Reset ( void ); + + Vector m_vecOrigin; // sound's location in space + int m_iType; // what type of sound this is + int m_iVolume; // how loud the sound is + float m_flExpireTime; // when the sound should be purged from the list + int m_iNext; // index of next sound in this list ( Active or Free ) + int m_iNextAudible; // temporary link that monsters use to build a list of audible sounds + + BOOL FIsSound( void ); + BOOL FIsScent( void ); +}; + +//========================================================= +// CSoundEnt - a single instance of this entity spawns when +// the world spawns. The SoundEnt's job is to update the +// world's Free and Active sound lists. +//========================================================= +class CSoundEnt : public CBaseEntity +{ +public: + + void Precache ( void ); + void Spawn( void ); + void Think( void ); + void Initialize ( void ); + + static void InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ); + static void FreeSound ( int iSound, int iPrevious ); + static int ActiveList( void );// return the head of the active list + static int FreeList( void );// return the head of the free list + static CSound* SoundPointerForIndex( int iIndex );// return a pointer for this index in the sound list + static int ClientSoundIndex ( edict_t *pClient ); + + BOOL IsEmpty( void ) { return m_iActiveSound == SOUNDLIST_EMPTY; } + int ISoundsInList ( int iListType ); + int IAllocSound ( void ); + virtual int ObjectCaps( void ) { return FCAP_DONT_SAVE; } + + int m_iFreeSound; // index of the first sound in the free sound list + int m_iActiveSound; // indes of the first sound in the active sound list + int m_cLastActiveSounds; // keeps track of the number of active sounds at the last update. (for diagnostic work) + BOOL m_fShowReport; // if true, dump information about free/active sounds. + +private: + CSound m_SoundPool[ MAX_WORLD_SOUNDS ]; +}; diff --git a/rehlds/dlls/spectator.h b/rehlds/dlls/spectator.h new file mode 100644 index 0000000..1a2c11f --- /dev/null +++ b/rehlds/dlls/spectator.h @@ -0,0 +1,27 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Spectator.h + +class CBaseSpectator : public CBaseEntity +{ +public: + void Spawn(); + void SpectatorConnect(void); + void SpectatorDisconnect(void); + void SpectatorThink(void); + +private: + void SpectatorImpulseCommand(void); +}; diff --git a/rehlds/dlls/talkmonster.h b/rehlds/dlls/talkmonster.h new file mode 100644 index 0000000..34fc40e --- /dev/null +++ b/rehlds/dlls/talkmonster.h @@ -0,0 +1,26 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef TALKMONSTER_H +#define TALKMONSTER_H + +class CTalkMonster : public CBaseMonster +{ +public: + static float g_talkWaitTime; + +}; + +#endif //TALKMONSTER_H diff --git a/rehlds/dlls/teamplay_gamerules.h b/rehlds/dlls/teamplay_gamerules.h new file mode 100644 index 0000000..c7c351e --- /dev/null +++ b/rehlds/dlls/teamplay_gamerules.h @@ -0,0 +1,57 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// teamplay_gamerules.h +// + +#define MAX_TEAMNAME_LENGTH 16 +#define MAX_TEAMS 32 + +#define TEAMPLAY_TEAMLISTLENGTH MAX_TEAMS*MAX_TEAMNAME_LENGTH + +class CHalfLifeTeamplay : public CHalfLifeMultiplay +{ +public: + CHalfLifeTeamplay(); + + virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); + virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); + virtual BOOL IsTeamplay( void ); + virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual const char *GetTeamID( CBaseEntity *pEntity ); + virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void InitHUD( CBasePlayer *pl ); + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); + virtual const char *GetGameDescription( void ) { return "HL Teamplay"; } // this is the game name that gets seen in the server browser + virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + virtual void Think ( void ); + virtual int GetTeamIndex( const char *pTeamName ); + virtual const char *GetIndexedTeamName( int teamIndex ); + virtual BOOL IsValidTeam( const char *pTeamName ); + const char *SetDefaultPlayerTeam( CBasePlayer *pPlayer ); + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, const char *pTeamName, BOOL bKill, BOOL bGib ); + +private: + void RecountTeams( bool bResendInfo = FALSE ); + const char *TeamWithFewestPlayers( void ); + + BOOL m_DisableDeathMessages; + BOOL m_DisableDeathPenalty; + BOOL m_teamLimit; // This means the server set only some teams as valid + char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; +}; diff --git a/rehlds/dlls/trains.h b/rehlds/dlls/trains.h new file mode 100644 index 0000000..4ee4411 --- /dev/null +++ b/rehlds/dlls/trains.h @@ -0,0 +1,127 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef TRAINS_H +#define TRAINS_H + +// Tracktrain spawn flags +#define SF_TRACKTRAIN_NOPITCH 0x0001 +#define SF_TRACKTRAIN_NOCONTROL 0x0002 +#define SF_TRACKTRAIN_FORWARDONLY 0x0004 +#define SF_TRACKTRAIN_PASSABLE 0x0008 + +// Spawnflag for CPathTrack +#define SF_PATH_DISABLED 0x00000001 +#define SF_PATH_FIREONCE 0x00000002 +#define SF_PATH_ALTREVERSE 0x00000004 +#define SF_PATH_DISABLE_TRAIN 0x00000008 +#define SF_PATH_ALTERNATE 0x00008000 + +// Spawnflags of CPathCorner +#define SF_CORNER_WAITFORTRIG 0x001 +#define SF_CORNER_TELEPORT 0x002 +#define SF_CORNER_FIREONCE 0x004 + +//#define PATH_SPARKLE_DEBUG 1 // This makes a particle effect around path_track entities for debugging +class CPathTrack : public CPointEntity +{ +public: + void Spawn( void ); + void Activate( void ); + void KeyValue( KeyValueData* pkvd); + + void SetPrevious( CPathTrack *pprevious ); + void Link( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + + CPathTrack *ValidPath( CPathTrack *ppath, int testFlag ); // Returns ppath if enabled, NULL otherwise + void Project( CPathTrack *pstart, CPathTrack *pend, Vector *origin, float dist ); + + static CPathTrack *Instance( edict_t *pent ); + + CPathTrack *LookAhead( Vector *origin, float dist, int move ); + CPathTrack *Nearest( Vector origin ); + + CPathTrack *GetNext( void ); + CPathTrack *GetPrevious( void ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; +#if PATH_SPARKLE_DEBUG + void EXPORT Sparkle(void); +#endif + + float m_length; + string_t m_altName; + CPathTrack *m_pnext; + CPathTrack *m_pprevious; + CPathTrack *m_paltpath; +}; + + +class CFuncTrackTrain : public CBaseEntity +{ +public: + void Spawn( void ); + void Precache( void ); + + void Blocked( CBaseEntity *pOther ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void KeyValue( KeyValueData* pkvd ); + + void EXPORT Next( void ); + void EXPORT Find( void ); + void EXPORT NearestPath( void ); + void EXPORT DeadEnd( void ); + + void NextThink( float thinkTime, BOOL alwaysThink ); + + void SetTrack( CPathTrack *track ) { m_ppath = track->Nearest(pev->origin); } + void SetControls( entvars_t *pevControls ); + BOOL OnControls( entvars_t *pev ); + + void StopSound ( void ); + void UpdateSound ( void ); + + static CFuncTrackTrain *Instance( edict_t *pent ); + + virtual int Save( CSave &save ); + virtual int Restore( CRestore &restore ); + + static TYPEDESCRIPTION m_SaveData[]; + virtual int ObjectCaps( void ) { return (CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DIRECTIONAL_USE; } + + virtual void OverrideReset( void ); + + CPathTrack *m_ppath; + float m_length; + float m_height; + float m_speed; + float m_dir; + float m_startSpeed; + Vector m_controlMins; + Vector m_controlMaxs; + int m_soundPlaying; + int m_sounds; + float m_flVolume; + float m_flBank; + float m_oldSpeed; + +private: + unsigned short m_usAdjustPitch; +}; + +#endif diff --git a/rehlds/dlls/util.h b/rehlds/dlls/util.h new file mode 100644 index 0000000..2f7b8c8 --- /dev/null +++ b/rehlds/dlls/util.h @@ -0,0 +1,547 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "archtypes.h" // DAL + +// +// Misc utility code +// +#ifndef ACTIVITY_H +#include "activity.h" +#endif + +#ifndef ENGINECALLBACK_H +#include "enginecallback.h" +#endif +inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ); // implementation later in this file + +extern globalvars_t *gpGlobals; + +// Use this instead of ALLOC_STRING on constant strings +#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (unsigned int)(offset))) +#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0))) + +inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) +{ + return FIND_ENTITY_BY_STRING(entStart, "classname", pszName); +} + +inline edict_t *FIND_ENTITY_BY_TARGETNAME(edict_t *entStart, const char *pszName) +{ + return FIND_ENTITY_BY_STRING(entStart, "targetname", pszName); +} + +// for doing a reverse lookup. Say you have a door, and want to find its button. +inline edict_t *FIND_ENTITY_BY_TARGET(edict_t *entStart, const char *pszName) +{ + return FIND_ENTITY_BY_STRING(entStart, "target", pszName); +} + +// Keeps clutter down a bit, when writing key-value pairs +#define WRITEKEY_INT(pf, szKeyName, iKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%d\"\n", szKeyName, iKeyValue) +#define WRITEKEY_FLOAT(pf, szKeyName, flKeyValue) \ + ENGINE_FPRINTF(pf, "\"%s\" \"%f\"\n", szKeyName, flKeyValue) +#define WRITEKEY_STRING(pf, szKeyName, szKeyValue) \ + ENGINE_FPRINTF(pf, "\"%s\" \"%s\"\n", szKeyName, szKeyValue) +#define WRITEKEY_VECTOR(pf, szKeyName, flX, flY, flZ) \ + ENGINE_FPRINTF(pf, "\"%s\" \"%f %f %f\"\n", szKeyName, flX, flY, flZ) + +// Keeps clutter down a bit, when using a float as a bit-vector +#define SetBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits)) +#define ClearBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits)) +#define FBitSet(flBitVector, bit) ((int)(flBitVector) & (bit)) + +// Makes these more explicit, and easier to find +#define FILE_GLOBAL static +#define DLL_GLOBAL + +// Until we figure out why "const" gives the compiler problems, we'll just have to use +// this bogus "empty" define to mark things as constant. +#define CONSTANT + +// More explicit than "int" +typedef int EOFFSET; + +// In case it's not alread defined +typedef int BOOL; + +// In case this ever changes +#define M_PI 3.14159265358979323846 + +// Keeps clutter down a bit, when declaring external entity/global method prototypes +#define DECLARE_GLOBAL_METHOD(MethodName) extern void UTIL_DLLEXPORT MethodName( void ) +#define GLOBAL_METHOD(funcname) void UTIL_DLLEXPORT funcname(void) + +#ifndef UTIL_DLLEXPORT +#ifdef _WIN32 +#define UTIL_DLLEXPORT _declspec( dllexport ) +#else +#define UTIL_DLLEXPORT __attribute__ ((visibility("default"))) +#endif +#endif + +// This is the glue that hooks .MAP entity class names to our CPP classes +// The _declspec forces them to be exported by name so we can do a lookup with GetProcAddress() +// The function is used to intialize / allocate the object for the entity +#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) \ + extern "C" UTIL_DLLEXPORT void mapClassName( entvars_t *pev ); \ + void mapClassName( entvars_t *pev ) { GetClassPtr( (DLLClassName *)pev ); } + + +// +// Conversion among the three types of "entity", including identity-conversions. +// +#ifdef DEBUG + extern edict_t *DBG_EntOfVars(const entvars_t *pev); + inline edict_t *ENT(const entvars_t *pev) { return DBG_EntOfVars(pev); } +#else + inline edict_t *ENT(const entvars_t *pev) { return pev->pContainingEntity; } +#endif +inline edict_t *ENT(edict_t *pent) { return pent; } +inline edict_t *ENT(EOFFSET eoffset) { return (*g_engfuncs.pfnPEntityOfEntOffset)(eoffset); } +inline EOFFSET OFFSET(EOFFSET eoffset) { return eoffset; } +inline EOFFSET OFFSET(const edict_t *pent) +{ +#if _DEBUG + if ( !pent ) + ALERT( at_error, "Bad ent in OFFSET()\n" ); +#endif + return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); +} +inline EOFFSET OFFSET(entvars_t *pev) +{ +#if _DEBUG + if ( !pev ) + ALERT( at_error, "Bad pev in OFFSET()\n" ); +#endif + return OFFSET(ENT(pev)); +} +inline entvars_t *VARS(entvars_t *pev) { return pev; } + +inline entvars_t *VARS(edict_t *pent) +{ + if ( !pent ) + return NULL; + + return &pent->v; +} + +inline entvars_t* VARS(EOFFSET eoffset) { return VARS(ENT(eoffset)); } +inline int ENTINDEX(edict_t *pEdict) { return (*g_engfuncs.pfnIndexOfEdict)(pEdict); } +inline edict_t* INDEXENT( int iEdictNum ) { return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); } +inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent ) { + (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ENT(ent)); +} + +// Testing the three types of "entity" for nullity +#define eoNullEntity 0 +inline BOOL FNullEnt(EOFFSET eoffset) { return eoffset == 0; } +inline BOOL FNullEnt(const edict_t* pent) { return pent == NULL || FNullEnt(OFFSET(pent)); } +inline BOOL FNullEnt(entvars_t* pev) { return pev == NULL || FNullEnt(OFFSET(pev)); } + +// Testing strings for nullity +#define iStringNull 0 +inline BOOL FStringNull(int iString) { return iString == iStringNull; } + +#define cchMapNameMost 32 + +// Dot products for view cone checking +#define VIEW_FIELD_FULL (float)-1.0 // +-180 degrees +#define VIEW_FIELD_WIDE (float)-0.7 // +-135 degrees 0.1 // +-85 degrees, used for full FOV checks +#define VIEW_FIELD_NARROW (float)0.7 // +-45 degrees, more narrow check used to set up ranged attacks +#define VIEW_FIELD_ULTRA_NARROW (float)0.9 // +-25 degrees, more narrow check used to set up ranged attacks + +// All monsters need this data +#define DONT_BLEED -1 +#define BLOOD_COLOR_RED (BYTE)247 +#define BLOOD_COLOR_YELLOW (BYTE)195 +#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW + +typedef enum +{ + + MONSTERSTATE_NONE = 0, + MONSTERSTATE_IDLE, + MONSTERSTATE_COMBAT, + MONSTERSTATE_ALERT, + MONSTERSTATE_HUNT, + MONSTERSTATE_PRONE, + MONSTERSTATE_SCRIPT, + MONSTERSTATE_PLAYDEAD, + MONSTERSTATE_DEAD + +} MONSTERSTATE; + + + +// Things that toggle (buttons/triggers/doors) need this +typedef enum + { + TS_AT_TOP, + TS_AT_BOTTOM, + TS_GOING_UP, + TS_GOING_DOWN + } TOGGLE_STATE; + +// Misc useful +inline BOOL FStrEq(const char*sz1, const char*sz2) + { return (strcmp(sz1, sz2) == 0); } +inline BOOL FClassnameIs(edict_t* pent, const char* szClassname) + { return FStrEq(STRING(VARS(pent)->classname), szClassname); } +inline BOOL FClassnameIs(entvars_t* pev, const char* szClassname) + { return FStrEq(STRING(pev->classname), szClassname); } + +class CBaseEntity; + +// Misc. Prototypes +extern void UTIL_SetSize (entvars_t* pev, const Vector &vecMin, const Vector &vecMax); +extern float UTIL_VecToYaw (const Vector &vec); +extern Vector UTIL_VecToAngles (const Vector &vec); +extern float UTIL_AngleMod (float a); +extern float UTIL_AngleDiff ( float destAngle, float srcAngle ); + +extern CBaseEntity *UTIL_FindEntityInSphere(CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius); +extern CBaseEntity *UTIL_FindEntityByString(CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue ); +extern CBaseEntity *UTIL_FindEntityByClassname(CBaseEntity *pStartEntity, const char *szName ); +extern CBaseEntity *UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName ); +extern CBaseEntity *UTIL_FindEntityGeneric(const char *szName, Vector &vecSrc, float flRadius ); + +// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected +// otherwise returns NULL +// Index is 1 based +extern CBaseEntity *UTIL_PlayerByIndex( int playerIndex ); + +#define UTIL_EntitiesInPVS(pent) (*g_engfuncs.pfnEntitiesInPVS)(pent) +extern void UTIL_MakeVectors (const Vector &vecAngles); + +// Pass in an array of pointers and an array size, it fills the array and returns the number inserted +extern int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ); +extern int UTIL_EntitiesInBox( CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask ); + +inline void UTIL_MakeVectorsPrivate( const Vector &vecAngles, float *p_vForward, float *p_vRight, float *p_vUp ) +{ + g_engfuncs.pfnAngleVectors( vecAngles, p_vForward, p_vRight, p_vUp ); +} + +extern void UTIL_MakeAimVectors ( const Vector &vecAngles ); // like MakeVectors, but assumes pitch isn't inverted +extern void UTIL_MakeInvVectors ( const Vector &vec, globalvars_t *pgv ); + +extern void UTIL_SetOrigin ( entvars_t* pev, const Vector &vecOrigin ); +extern void UTIL_EmitAmbientSound ( edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch ); +extern void UTIL_ParticleEffect ( const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount ); +extern void UTIL_ScreenShake ( const Vector ¢er, float amplitude, float frequency, float duration, float radius ); +extern void UTIL_ScreenShakeAll ( const Vector ¢er, float amplitude, float frequency, float duration ); +extern void UTIL_ShowMessage ( const char *pString, CBaseEntity *pPlayer ); +extern void UTIL_ShowMessageAll ( const char *pString ); +extern void UTIL_ScreenFadeAll ( const Vector &color, float fadeTime, float holdTime, int alpha, int flags ); +extern void UTIL_ScreenFade ( CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags ); + +typedef enum { ignore_monsters=1, dont_ignore_monsters=0, missile=2 } IGNORE_MONSTERS; +typedef enum { ignore_glass=1, dont_ignore_glass=0 } IGNORE_GLASS; +extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr); +extern void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr); +typedef enum { point_hull=0, human_hull=1, large_hull=2, head_hull=3 } __HLSDK_HULL_TYPE; +extern void UTIL_TraceHull (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr); +extern TraceResult UTIL_GetGlobalTrace (void); +extern void UTIL_TraceModel (const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr); +extern Vector UTIL_GetAimVector (edict_t* pent, float flSpeed); +extern int UTIL_PointContents (const Vector &vec); + +extern int UTIL_IsMasterTriggered (string_t sMaster, CBaseEntity *pActivator); +extern void UTIL_BloodStream( const Vector &origin, const Vector &direction, int color, int amount ); +extern void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ); +extern Vector UTIL_RandomBloodVector( void ); +extern BOOL UTIL_ShouldShowBlood( int bloodColor ); +extern void UTIL_BloodDecalTrace( TraceResult *pTrace, int bloodColor ); +extern void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ); +extern void UTIL_PlayerDecalTrace( TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom ); +extern void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ); +extern void UTIL_Sparks( const Vector &position ); +extern void UTIL_Ricochet( const Vector &position, float scale ); +extern void UTIL_StringToVector( float *pVector, const char *pString ); +extern void UTIL_StringToIntArray( int *pVector, int count, const char *pString ); +extern Vector UTIL_ClampVectorToBox( const Vector &input, const Vector &clampSize ); +extern float UTIL_Approach( float target, float value, float speed ); +extern float UTIL_ApproachAngle( float target, float value, float speed ); +extern float UTIL_AngleDistance( float next, float cur ); + +extern char *UTIL_VarArgs( char *format, ... ); +extern void UTIL_Remove( CBaseEntity *pEntity ); +extern BOOL UTIL_IsValidEntity( edict_t *pent ); +extern BOOL UTIL_TeamsMatch( const char *pTeamName1, const char *pTeamName2 ); + +// Use for ease-in, ease-out style interpolation (accel/decel) +extern float UTIL_SplineFraction( float value, float scale ); + +// Search for water transition along a vertical line +extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); +extern void UTIL_Bubbles( Vector mins, Vector maxs, int count ); +extern void UTIL_BubbleTrail( Vector from, Vector to, int count ); + +// allows precacheing of other entities +extern void UTIL_PrecacheOther( const char *szClassname ); + +// prints a message to each client +extern void UTIL_ClientPrintAll( int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); +inline void UTIL_CenterPrintAll( const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ) +{ + UTIL_ClientPrintAll( HUD_PRINTCENTER, msg_name, param1, param2, param3, param4 ); +} + +class CBasePlayerItem; +class CBasePlayer; +extern BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ); + +// prints messages through the HUD +extern void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL ); + +// prints a message to the HUD say (chat) +extern void UTIL_SayText( const char *pText, CBaseEntity *pEntity ); +extern void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ); + + +typedef struct hudtextparms_s +{ + float x; + float y; + int effect; + byte r1, g1, b1, a1; + byte r2, g2, b2, a2; + float fadeinTime; + float fadeoutTime; + float holdTime; + float fxTime; + int channel; +} hudtextparms_t; + +// prints as transparent 'title' to the HUD +extern void UTIL_HudMessageAll( const hudtextparms_t &textparms, const char *pMessage ); +extern void UTIL_HudMessage( CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage ); + +// for handy use with ClientPrint params +extern char *UTIL_dtos1( int d ); +extern char *UTIL_dtos2( int d ); +extern char *UTIL_dtos3( int d ); +extern char *UTIL_dtos4( int d ); + +// Writes message to console with timestamp and FragLog header. +extern void UTIL_LogPrintf( char *fmt, ... ); +extern void UTIL_ServerPrintf( const char *fmt, ... ); + +// Sorta like FInViewCone, but for nonmonsters. +extern float UTIL_DotPoints ( const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir ); + +extern void UTIL_StripToken( const char *pKey, char *pDest );// for redundant keynames + +// Misc functions +extern void SetMovedir(entvars_t* pev); +extern Vector VecBModelOrigin( entvars_t* pevBModel ); +extern int BuildChangeList( LEVELLIST *pLevelList, int maxList ); + +// +// How did I ever live without ASSERT? +// +#ifdef DEBUG +void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage); +#define ASSERT(f) DBG_AssertFunction(f, #f, __FILE__, __LINE__, NULL) +#define ASSERTSZ(f, sz) DBG_AssertFunction(f, #f, __FILE__, __LINE__, sz) +#else // !DEBUG +#define ASSERT(f) +#define ASSERTSZ(f, sz) +#endif // !DEBUG + + +extern DLL_GLOBAL const Vector g_vecZero; + +// +// Constants that were used only by QC (maybe not used at all now) +// +// Un-comment only as needed +// +#define LANGUAGE_ENGLISH 0 +#define LANGUAGE_GERMAN 1 +#define LANGUAGE_FRENCH 2 +#define LANGUAGE_BRITISH 3 + +extern DLL_GLOBAL int g_Language; + +#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation +#define AMBIENT_SOUND_EVERYWHERE 1 +#define AMBIENT_SOUND_SMALLRADIUS 2 +#define AMBIENT_SOUND_MEDIUMRADIUS 4 +#define AMBIENT_SOUND_LARGERADIUS 8 +#define AMBIENT_SOUND_START_SILENT 16 +#define AMBIENT_SOUND_NOT_LOOPING 32 + +#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements + +#define SND_SPAWNING (1<<8) // duplicated in protocol.h we're spawing, used in some cases for ambients +#define SND_STOP (1<<5) // duplicated in protocol.h stop sound +#define SND_CHANGE_VOL (1<<6) // duplicated in protocol.h change sound vol +#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch + +#define LFO_SQUARE 1 +#define LFO_TRIANGLE 2 +#define LFO_RANDOM 3 + +// func_rotating +#define SF_BRUSH_ROTATE_Y_AXIS 0 +#define SF_BRUSH_ROTATE_INSTANT 1 +#define SF_BRUSH_ROTATE_BACKWARDS 2 +#define SF_BRUSH_ROTATE_Z_AXIS 4 +#define SF_BRUSH_ROTATE_X_AXIS 8 +#define SF_PENDULUM_AUTO_RETURN 16 +#define SF_PENDULUM_PASSABLE 32 + + +#define SF_BRUSH_ROTATE_SMALLRADIUS 128 +#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256 +#define SF_BRUSH_ROTATE_LARGERADIUS 512 + +#define PUSH_BLOCK_ONLY_X 1 +#define PUSH_BLOCK_ONLY_Y 2 + +#define VEC_HULL_MIN Vector(-16, -16, -36) +#define VEC_HULL_MAX Vector( 16, 16, 36) +#define VEC_HUMAN_HULL_MIN Vector( -16, -16, 0 ) +#define VEC_HUMAN_HULL_MAX Vector( 16, 16, 72 ) +#define VEC_HUMAN_HULL_DUCK Vector( 16, 16, 36 ) + +#define VEC_VIEW Vector( 0, 0, 28 ) + +#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) +#define VEC_DUCK_HULL_MAX Vector( 16, 16, 18) +#define VEC_DUCK_VIEW Vector( 0, 0, 12 ) + +#define SVC_TEMPENTITY 23 +#define SVC_INTERMISSION 30 +#define SVC_CDTRACK 32 +#define SVC_WEAPONANIM 35 +#define SVC_ROOMTYPE 37 +#define SVC_DIRECTOR 51 + + + +// triggers +#define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger +#define SF_TRIGGER_NOCLIENTS 2// players not allowed to fire this trigger +#define SF_TRIGGER_PUSHABLES 4// only pushables can fire this trigger + +// func breakable +#define SF_BREAK_TRIGGER_ONLY 1// may only be broken by trigger +#define SF_BREAK_TOUCH 2// can be 'crashed through' by running player (plate glass) +#define SF_BREAK_PRESSURE 4// can be broken by a player standing on it +#define SF_BREAK_CROWBAR 256// instant break if hit with crowbar + +// func_pushable (it's also func_breakable, so don't collide with those flags) +#define SF_PUSH_BREAKABLE 128 + +#define SF_LIGHT_START_OFF 1 + +#define SPAWNFLAG_NOMESSAGE 1 +#define SPAWNFLAG_NOTOUCH 1 +#define SPAWNFLAG_DROIDONLY 4 + +#define SPAWNFLAG_USEONLY 1 // can't be touched, must be used (buttons) + +#define TELE_PLAYER_ONLY 1 +#define TELE_SILENT 2 + +#define SF_TRIG_PUSH_ONCE 1 + + +// Sound Utilities + +// sentence groups +#define CBSENTENCENAME_MAX 16 +#define CVOXFILESENTENCEMAX 1536 // max number of sentences in game. NOTE: this must match + // CVOXFILESENTENCEMAX in engine\sound.h!!! + +extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX]; +extern int gcallsentences; + +int USENTENCEG_Pick(int isentenceg, char *szfound); +int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset); +void USENTENCEG_InitLRU(unsigned char *plru, int count); + +void SENTENCEG_Init(); +void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick); +int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch); +int SENTENCEG_PlayRndSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch); +int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch, int ipick, int freset); +int SENTENCEG_GetIndex(const char *szrootname); +int SENTENCEG_Lookup(const char *sample, char *sentencenum); + +void TEXTURETYPE_Init(); +char TEXTURETYPE_Find(char *name); +float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType); + +// NOTE: use EMIT_SOUND_DYN to set the pitch of a sound. Pitch of 100 +// is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100 +// down to 1 is a lower pitch. 150 to 70 is the realistic range. +// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as +// fast as EMIT_SOUND (the pitchshift mixer is not native coded). + +void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, + int flags, int pitch); + + +inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation) +{ + EMIT_SOUND_DYN(entity, channel, sample, volume, attenuation, 0, PITCH_NORM); +} + +inline void STOP_SOUND(edict_t *entity, int channel, const char *sample) +{ + EMIT_SOUND_DYN(entity, channel, sample, 0, 0, SND_STOP, PITCH_NORM); +} + +void EMIT_SOUND_SUIT(edict_t *entity, const char *sample); +void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg); +void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname); + +#define PRECACHE_SOUND_ARRAY( a ) \ + { for (int i = 0; i < ARRAYSIZE( a ); i++ ) PRECACHE_SOUND((char *) a [i]); } + +#define EMIT_SOUND_ARRAY_DYN( chan, array ) \ + EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, ATTN_NORM, 0, RANDOM_LONG(95,105) ); + +#define RANDOM_SOUND_ARRAY( array ) (array) [ RANDOM_LONG(0,ARRAYSIZE( (array) )-1) ] + +#define PLAYBACK_EVENT( flags, who, index ) PLAYBACK_EVENT_FULL( flags, who, index, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); +#define PLAYBACK_EVENT_DELAY( flags, who, index, delay ) PLAYBACK_EVENT_FULL( flags, who, index, delay, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); + +#define GROUP_OP_AND 0 +#define GROUP_OP_NAND 1 + +extern int g_groupmask; +extern int g_groupop; + +class UTIL_GroupTrace +{ +public: + UTIL_GroupTrace( int groupmask, int op ); + ~UTIL_GroupTrace( void ); + +private: + int m_oldgroupmask, m_oldgroupop; +}; + +void UTIL_SetGroupTrace( int groupmask, int op ); +void UTIL_UnsetGroupTrace( void ); + +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); + +float UTIL_WeaponTimeBase( void ); diff --git a/rehlds/dlls/vector.h b/rehlds/dlls/vector.h new file mode 100644 index 0000000..5d0d743 --- /dev/null +++ b/rehlds/dlls/vector.h @@ -0,0 +1,113 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef VECTOR_H +#define VECTOR_H + + +//========================================================= +// 2DVector - used for many pathfinding and many other +// operations that are treated as planar rather than 3d. +//========================================================= +class Vector2D +{ +public: + inline Vector2D(void): x(0.0), y(0.0) { } + inline Vector2D(float X, float Y): x(0.0), y(0.0) { x = X; y = Y; } + inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); } + inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); } + inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); } + inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); } + + inline float Length(void) const { return sqrt(x*x + y*y ); } + + inline Vector2D Normalize ( void ) const + { + // Vector2D vec2; + + float flLen = Length(); + if ( flLen == 0 ) + { + return Vector2D( 0, 0 ); + } + else + { + flLen = 1 / flLen; + return Vector2D( x * flLen, y * flLen ); + } + } + + vec_t x, y; +}; + +inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); } +inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; } + +//========================================================= +// 3D Vector +//========================================================= +class Vector // same data-layout as engine's vec3_t, +{ // which is a vec_t[3] +public: + // Construction/destruction + inline Vector(void): x(0.0), y(0.0), z(0.0) { } + inline Vector(float X, float Y, float Z): x(0.0), y(0.0), z(0.0) { x = X; y = Y; z = Z; } + //inline Vector(double X, double Y, double Z) { x = (float)X; y = (float)Y; z = (float)Z; } + //inline Vector(int X, int Y, int Z) { x = (float)X; y = (float)Y; z = (float)Z; } + inline Vector(const Vector& v): x(0.0), y(0.0), z(0.0) { x = v.x; y = v.y; z = v.z; } + inline Vector(float rgfl[3]): x(0.0), y(0.0), z(0.0) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } + + // Operators + inline Vector operator-(void) const { return Vector(-x,-y,-z); } + inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; } + inline int operator!=(const Vector& v) const { return !(*this==v); } + inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); } + inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); } + inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); } + inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); } + + // Methods + inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; } + inline float Length(void) const { return sqrt(x*x + y*y + z*z); } + operator float *() { return &x; } // Vectors will now automatically convert to float * when needed + operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed + inline Vector Normalize(void) const + { + float flLen = Length(); + if (flLen == 0) return Vector(0,0,1); // ???? + flLen = 1 / flLen; + return Vector(x * flLen, y * flLen, z * flLen); + } + + inline Vector2D Make2D ( void ) const + { + Vector2D Vec2; + + Vec2.x = x; + Vec2.y = y; + + return Vec2; + } + inline float Length2D(void) const { return sqrt(x*x + y*y); } + + // Members + vec_t x, y, z; +}; + +inline Vector operator*(float fl, const Vector& v) { return v * fl; } +inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); } +inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); } + +#endif diff --git a/rehlds/dlls/weapons.h b/rehlds/dlls/weapons.h new file mode 100644 index 0000000..47ec6b9 --- /dev/null +++ b/rehlds/dlls/weapons.h @@ -0,0 +1,1019 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef WEAPONS_H +#define WEAPONS_H + +#include "effects.h" + +class CBasePlayer; +extern int gmsgWeapPickup; + +void DeactivateSatchels( CBasePlayer *pOwner ); + +// Contact Grenade / Timed grenade / Satchel Charge +class CGrenade : public CBaseMonster +{ +public: + void Spawn( void ); + + typedef enum { SATCHEL_DETONATE = 0, SATCHEL_RELEASE } SATCHELCODE; + + static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ); + static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); + static CGrenade *ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ); + static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code ); + + void Explode( Vector vecSrc, Vector vecAim ); + void Explode( TraceResult *pTrace, int bitsDamageType ); + void EXPORT Smoke( void ); + + void EXPORT BounceTouch( CBaseEntity *pOther ); + void EXPORT SlideTouch( CBaseEntity *pOther ); + void EXPORT ExplodeTouch( CBaseEntity *pOther ); + void EXPORT DangerSoundThink( void ); + void EXPORT PreDetonate( void ); + void EXPORT Detonate( void ); + void EXPORT DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + void EXPORT TumbleThink( void ); + + virtual void BounceSound( void ); + virtual int BloodColor( void ) { return DONT_BLEED; } + virtual void Killed( entvars_t *pevAttacker, int iGib ); + + BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet. +}; + + +// constant items +#define ITEM_HEALTHKIT 1 +#define ITEM_ANTIDOTE 2 +#define ITEM_SECURITY 3 +#define ITEM_BATTERY 4 + +#define WEAPON_NONE 0 +#define WEAPON_CROWBAR 1 +#define WEAPON_GLOCK 2 +#define WEAPON_PYTHON 3 +#define WEAPON_MP5 4 +#define WEAPON_CHAINGUN 5 +#define WEAPON_CROSSBOW 6 +#define WEAPON_SHOTGUN 7 +#define WEAPON_RPG 8 +#define WEAPON_GAUSS 9 +#define WEAPON_EGON 10 +#define WEAPON_HORNETGUN 11 +#define WEAPON_HANDGRENADE 12 +#define WEAPON_TRIPMINE 13 +#define WEAPON_SATCHEL 14 +#define WEAPON_SNARK 15 + +#define WEAPON_ALLWEAPONS (~(1<absmin = pev->origin + Vector(-16, -16, -5); + pev->absmax = pev->origin + Vector(16, 16, 28); + } + + void PrimaryAttack( void ); + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + void WeaponIdle( void ); + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + unsigned short m_usTripFire; + +}; + +class CSqueak : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 5; } + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + BOOL Deploy( void ); + void Holster( int skiplocal = 0 ); + void WeaponIdle( void ); + int m_fJustThrown; + + virtual BOOL UseDecrement( void ) + { +#if defined( CLIENT_WEAPONS ) + return TRUE; +#else + return FALSE; +#endif + } + +private: + unsigned short m_usSnarkFire; +}; + + +#endif // WEAPONS_H diff --git a/rehlds/engine/APIProxy.h b/rehlds/engine/APIProxy.h new file mode 100644 index 0000000..4e42c05 --- /dev/null +++ b/rehlds/engine/APIProxy.h @@ -0,0 +1,939 @@ +#ifndef __APIPROXY__ +#define __APIPROXY__ + +#include "netadr.h" +#include "Sequence.h" + + +#ifndef _WIN32 +#include "enums.h" +#endif + +#define MAX_ALIAS_NAME 32 + +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; +} cmdalias_t; + + +// ******************************************************** +// Functions exported by the client .dll +// ******************************************************** + +// Function type declarations for client exports +typedef int (*INITIALIZE_FUNC) (struct cl_enginefuncs_s*, int); +typedef void (*HUD_INIT_FUNC) (void); +typedef int (*HUD_VIDINIT_FUNC) (void); +typedef int (*HUD_REDRAW_FUNC) (float, int); +typedef int (*HUD_UPDATECLIENTDATA_FUNC) (struct client_data_s*, float); +typedef void (*HUD_RESET_FUNC) (void); +typedef void (*HUD_CLIENTMOVE_FUNC) (struct playermove_s *ppmove, qboolean server); +typedef void (*HUD_CLIENTMOVEINIT_FUNC) (struct playermove_s *ppmove); +typedef char (*HUD_TEXTURETYPE_FUNC) (char *name); +typedef void (*HUD_IN_ACTIVATEMOUSE_FUNC) (void); +typedef void (*HUD_IN_DEACTIVATEMOUSE_FUNC) (void); +typedef void (*HUD_IN_MOUSEEVENT_FUNC) (int mstate); +typedef void (*HUD_IN_CLEARSTATES_FUNC) (void); +typedef void (*HUD_IN_ACCUMULATE_FUNC) (void); +typedef void (*HUD_CL_CREATEMOVE_FUNC) (float frametime, struct usercmd_s *cmd, int active); +typedef int (*HUD_CL_ISTHIRDPERSON_FUNC) (void); +typedef void (*HUD_CL_GETCAMERAOFFSETS_FUNC) (float *ofs); +typedef struct kbutton_s * (*HUD_KB_FIND_FUNC) (const char *name); +typedef void (*HUD_CAMTHINK_FUNC) (void); +typedef void (*HUD_CALCREF_FUNC) (struct ref_params_s *pparams); +typedef int (*HUD_ADDENTITY_FUNC) (int type, struct cl_entity_s *ent, const char *modelname); +typedef void (*HUD_CREATEENTITIES_FUNC) (void); +typedef void (*HUD_DRAWNORMALTRIS_FUNC) (void); +typedef void (*HUD_DRAWTRANSTRIS_FUNC) (void); +typedef void (*HUD_STUDIOEVENT_FUNC) (const struct mstudioevent_s *event, const struct cl_entity_s *entity); +typedef void (*HUD_POSTRUNCMD_FUNC) (struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed); +typedef void (*HUD_SHUTDOWN_FUNC) (void); +typedef void (*HUD_TXFERLOCALOVERRIDES_FUNC) (struct entity_state_s *state, const struct clientdata_s *client); +typedef void (*HUD_PROCESSPLAYERSTATE_FUNC) (struct entity_state_s *dst, const struct entity_state_s *src); +typedef void (*HUD_TXFERPREDICTIONDATA_FUNC) (struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd); +typedef void (*HUD_DEMOREAD_FUNC) (int size, unsigned char *buffer); +typedef int (*HUD_CONNECTIONLESS_FUNC) (const struct netadr_s *net_from_, const char *args, char *response_buffer, int *response_buffer_size); +typedef int (*HUD_GETHULLBOUNDS_FUNC) (int hullnumber, float *mins, float *maxs); +typedef void (*HUD_FRAME_FUNC) (double); +typedef int (*HUD_KEY_EVENT_FUNC) (int eventcode, int keynum, const char *pszCurrentBinding); +typedef void (*HUD_TEMPENTUPDATE_FUNC) (double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int(*Callback_AddVisibleEntity)(struct cl_entity_s *pEntity), void(*Callback_TempEntPlaySound)(struct tempent_s *pTemp, float damp)); +typedef struct cl_entity_s *(*HUD_GETUSERENTITY_FUNC) (int index); +typedef void (*HUD_VOICESTATUS_FUNC) (int entindex, qboolean bTalking); +typedef void (*HUD_DIRECTORMESSAGE_FUNC) (int iSize, void *pbuf); +typedef int (*HUD_STUDIO_INTERFACE_FUNC) (int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio); +typedef void (*HUD_CHATINPUTPOSITION_FUNC) (int *x, int *y); +typedef int (*HUD_GETPLAYERTEAM) (int iplayer); +typedef void * (*CLIENTFACTORY) (); // this should be CreateInterfaceFn but that means including interface.h + // which is a C++ file and some of the client files a C only... + // so we return a void * which we then do a typecast on later. + + +// Pointers to the exported client functions themselves +typedef struct +{ + INITIALIZE_FUNC pInitFunc; + HUD_INIT_FUNC pHudInitFunc; + HUD_VIDINIT_FUNC pHudVidInitFunc; + HUD_REDRAW_FUNC pHudRedrawFunc; + HUD_UPDATECLIENTDATA_FUNC pHudUpdateClientDataFunc; + HUD_RESET_FUNC pHudResetFunc; + HUD_CLIENTMOVE_FUNC pClientMove; + HUD_CLIENTMOVEINIT_FUNC pClientMoveInit; + HUD_TEXTURETYPE_FUNC pClientTextureType; + HUD_IN_ACTIVATEMOUSE_FUNC pIN_ActivateMouse; + HUD_IN_DEACTIVATEMOUSE_FUNC pIN_DeactivateMouse; + HUD_IN_MOUSEEVENT_FUNC pIN_MouseEvent; + HUD_IN_CLEARSTATES_FUNC pIN_ClearStates; + HUD_IN_ACCUMULATE_FUNC pIN_Accumulate; + HUD_CL_CREATEMOVE_FUNC pCL_CreateMove; + HUD_CL_ISTHIRDPERSON_FUNC pCL_IsThirdPerson; + HUD_CL_GETCAMERAOFFSETS_FUNC pCL_GetCameraOffsets; + HUD_KB_FIND_FUNC pFindKey; + HUD_CAMTHINK_FUNC pCamThink; + HUD_CALCREF_FUNC pCalcRefdef; + HUD_ADDENTITY_FUNC pAddEntity; + HUD_CREATEENTITIES_FUNC pCreateEntities; + HUD_DRAWNORMALTRIS_FUNC pDrawNormalTriangles; + HUD_DRAWTRANSTRIS_FUNC pDrawTransparentTriangles; + HUD_STUDIOEVENT_FUNC pStudioEvent; + HUD_POSTRUNCMD_FUNC pPostRunCmd; + HUD_SHUTDOWN_FUNC pShutdown; + HUD_TXFERLOCALOVERRIDES_FUNC pTxferLocalOverrides; + HUD_PROCESSPLAYERSTATE_FUNC pProcessPlayerState; + HUD_TXFERPREDICTIONDATA_FUNC pTxferPredictionData; + HUD_DEMOREAD_FUNC pReadDemoBuffer; + HUD_CONNECTIONLESS_FUNC pConnectionlessPacket; + HUD_GETHULLBOUNDS_FUNC pGetHullBounds; + HUD_FRAME_FUNC pHudFrame; + HUD_KEY_EVENT_FUNC pKeyEvent; + HUD_TEMPENTUPDATE_FUNC pTempEntUpdate; + HUD_GETUSERENTITY_FUNC pGetUserEntity; + HUD_VOICESTATUS_FUNC pVoiceStatus; // Possibly null on old client dlls. + HUD_DIRECTORMESSAGE_FUNC pDirectorMessage; // Possibly null on old client dlls. + HUD_STUDIO_INTERFACE_FUNC pStudioInterface; // Not used by all clients + HUD_CHATINPUTPOSITION_FUNC pChatInputPosition; // Not used by all clients + HUD_GETPLAYERTEAM pGetPlayerTeam; // Not used by all clients + CLIENTFACTORY pClientFactory; +} cldll_func_t; + +// Function type declarations for client destination functions +typedef void(*DST_INITIALIZE_FUNC) (struct cl_enginefuncs_s**, int *); +typedef void(*DST_HUD_INIT_FUNC) (void); +typedef void(*DST_HUD_VIDINIT_FUNC) (void); +typedef void(*DST_HUD_REDRAW_FUNC) (float*, int*); +typedef void(*DST_HUD_UPDATECLIENTDATA_FUNC) (struct client_data_s**, float*); +typedef void(*DST_HUD_RESET_FUNC) (void); +typedef void(*DST_HUD_CLIENTMOVE_FUNC) (struct playermove_s **, qboolean *); +typedef void(*DST_HUD_CLIENTMOVEINIT_FUNC) (struct playermove_s **); +typedef void(*DST_HUD_TEXTURETYPE_FUNC) (char **); +typedef void(*DST_HUD_IN_ACTIVATEMOUSE_FUNC) (void); +typedef void(*DST_HUD_IN_DEACTIVATEMOUSE_FUNC) (void); +typedef void(*DST_HUD_IN_MOUSEEVENT_FUNC) (int *); +typedef void(*DST_HUD_IN_CLEARSTATES_FUNC) (void); +typedef void(*DST_HUD_IN_ACCUMULATE_FUNC) (void); +typedef void(*DST_HUD_CL_CREATEMOVE_FUNC) (float *, struct usercmd_s **, int *); +typedef void(*DST_HUD_CL_ISTHIRDPERSON_FUNC) (void); +typedef void(*DST_HUD_CL_GETCAMERAOFFSETS_FUNC) (float **); +typedef void(*DST_HUD_KB_FIND_FUNC) (const char **); +typedef void(*DST_HUD_CAMTHINK_FUNC) (void); +typedef void(*DST_HUD_CALCREF_FUNC) (struct ref_params_s **); +typedef void(*DST_HUD_ADDENTITY_FUNC) (int *, struct cl_entity_s **, const char **); +typedef void(*DST_HUD_CREATEENTITIES_FUNC) (void); +typedef void(*DST_HUD_DRAWNORMALTRIS_FUNC) (void); +typedef void(*DST_HUD_DRAWTRANSTRIS_FUNC) (void); +typedef void(*DST_HUD_STUDIOEVENT_FUNC) (const struct mstudioevent_s **, const struct cl_entity_s **); +typedef void(*DST_HUD_POSTRUNCMD_FUNC) (struct local_state_s **, struct local_state_s **, struct usercmd_s **, int *, double *, unsigned int *); +typedef void(*DST_HUD_SHUTDOWN_FUNC) (void); +typedef void(*DST_HUD_TXFERLOCALOVERRIDES_FUNC) (struct entity_state_s **, const struct clientdata_s **); +typedef void(*DST_HUD_PROCESSPLAYERSTATE_FUNC) (struct entity_state_s **, const struct entity_state_s **); +typedef void(*DST_HUD_TXFERPREDICTIONDATA_FUNC) (struct entity_state_s **, const struct entity_state_s **, struct clientdata_s **, const struct clientdata_s **, struct weapon_data_s **, const struct weapon_data_s **); +typedef void(*DST_HUD_DEMOREAD_FUNC) (int *, unsigned char **); +typedef void(*DST_HUD_CONNECTIONLESS_FUNC) (const struct netadr_s **, const char **, char **, int **); +typedef void(*DST_HUD_GETHULLBOUNDS_FUNC) (int *, float **, float **); +typedef void(*DST_HUD_FRAME_FUNC) (double *); +typedef void(*DST_HUD_KEY_EVENT_FUNC) (int *, int *, const char **); +typedef void(*DST_HUD_TEMPENTUPDATE_FUNC) (double *, double *, double *, struct tempent_s ***, struct tempent_s ***, int(**Callback_AddVisibleEntity)(struct cl_entity_s *pEntity), void(**Callback_TempEntPlaySound)(struct tempent_s *pTemp, float damp)); +typedef void(*DST_HUD_GETUSERENTITY_FUNC) (int *); +typedef void(*DST_HUD_VOICESTATUS_FUNC) (int *, qboolean *); +typedef void(*DST_HUD_DIRECTORMESSAGE_FUNC) (int *, void **); +typedef void(*DST_HUD_STUDIO_INTERFACE_FUNC) (int *, struct r_studio_interface_s ***, struct engine_studio_api_s **); +typedef void(*DST_HUD_CHATINPUTPOSITION_FUNC) (int **, int **); +typedef void(*DST_HUD_GETPLAYERTEAM) (int); + +// Pointers to the client destination functions +typedef struct +{ + DST_INITIALIZE_FUNC pInitFunc; + DST_HUD_INIT_FUNC pHudInitFunc; + DST_HUD_VIDINIT_FUNC pHudVidInitFunc; + DST_HUD_REDRAW_FUNC pHudRedrawFunc; + DST_HUD_UPDATECLIENTDATA_FUNC pHudUpdateClientDataFunc; + DST_HUD_RESET_FUNC pHudResetFunc; + DST_HUD_CLIENTMOVE_FUNC pClientMove; + DST_HUD_CLIENTMOVEINIT_FUNC pClientMoveInit; + DST_HUD_TEXTURETYPE_FUNC pClientTextureType; + DST_HUD_IN_ACTIVATEMOUSE_FUNC pIN_ActivateMouse; + DST_HUD_IN_DEACTIVATEMOUSE_FUNC pIN_DeactivateMouse; + DST_HUD_IN_MOUSEEVENT_FUNC pIN_MouseEvent; + DST_HUD_IN_CLEARSTATES_FUNC pIN_ClearStates; + DST_HUD_IN_ACCUMULATE_FUNC pIN_Accumulate; + DST_HUD_CL_CREATEMOVE_FUNC pCL_CreateMove; + DST_HUD_CL_ISTHIRDPERSON_FUNC pCL_IsThirdPerson; + DST_HUD_CL_GETCAMERAOFFSETS_FUNC pCL_GetCameraOffsets; + DST_HUD_KB_FIND_FUNC pFindKey; + DST_HUD_CAMTHINK_FUNC pCamThink; + DST_HUD_CALCREF_FUNC pCalcRefdef; + DST_HUD_ADDENTITY_FUNC pAddEntity; + DST_HUD_CREATEENTITIES_FUNC pCreateEntities; + DST_HUD_DRAWNORMALTRIS_FUNC pDrawNormalTriangles; + DST_HUD_DRAWTRANSTRIS_FUNC pDrawTransparentTriangles; + DST_HUD_STUDIOEVENT_FUNC pStudioEvent; + DST_HUD_POSTRUNCMD_FUNC pPostRunCmd; + DST_HUD_SHUTDOWN_FUNC pShutdown; + DST_HUD_TXFERLOCALOVERRIDES_FUNC pTxferLocalOverrides; + DST_HUD_PROCESSPLAYERSTATE_FUNC pProcessPlayerState; + DST_HUD_TXFERPREDICTIONDATA_FUNC pTxferPredictionData; + DST_HUD_DEMOREAD_FUNC pReadDemoBuffer; + DST_HUD_CONNECTIONLESS_FUNC pConnectionlessPacket; + DST_HUD_GETHULLBOUNDS_FUNC pGetHullBounds; + DST_HUD_FRAME_FUNC pHudFrame; + DST_HUD_KEY_EVENT_FUNC pKeyEvent; + DST_HUD_TEMPENTUPDATE_FUNC pTempEntUpdate; + DST_HUD_GETUSERENTITY_FUNC pGetUserEntity; + DST_HUD_VOICESTATUS_FUNC pVoiceStatus; // Possibly null on old client dlls. + DST_HUD_DIRECTORMESSAGE_FUNC pDirectorMessage; // Possibly null on old client dlls. + DST_HUD_STUDIO_INTERFACE_FUNC pStudioInterface; // Not used by all clients + DST_HUD_CHATINPUTPOSITION_FUNC pChatInputPosition; // Not used by all clients + DST_HUD_GETPLAYERTEAM pGetPlayerTeam; // Not used by all clients +} cldll_func_dst_t; + + + + +// ******************************************************** +// Functions exported by the engine +// ******************************************************** + +// Function type declarations for engine exports +typedef HSPRITE_t (*pfnEngSrc_pfnSPR_Load_t ) ( const char *szPicName ); +typedef int (*pfnEngSrc_pfnSPR_Frames_t ) ( HSPRITE_t hPic ); +typedef int (*pfnEngSrc_pfnSPR_Height_t ) ( HSPRITE_t hPic, int frame ); +typedef int (*pfnEngSrc_pfnSPR_Width_t ) ( HSPRITE_t hPic, int frame ); +typedef void (*pfnEngSrc_pfnSPR_Set_t ) ( HSPRITE_t hPic, int r, int g, int b ); +typedef void (*pfnEngSrc_pfnSPR_Draw_t ) ( int frame, int x, int y, const struct rect_s *prc ); +typedef void (*pfnEngSrc_pfnSPR_DrawHoles_t ) ( int frame, int x, int y, const struct rect_s *prc ); +typedef void (*pfnEngSrc_pfnSPR_DrawAdditive_t ) ( int frame, int x, int y, const struct rect_s *prc ); +typedef void (*pfnEngSrc_pfnSPR_EnableScissor_t ) ( int x, int y, int width, int height ); +typedef void (*pfnEngSrc_pfnSPR_DisableScissor_t ) ( void ); +typedef struct client_sprite_s * (*pfnEngSrc_pfnSPR_GetList_t ) ( char *psz, int *piCount ); +typedef void (*pfnEngSrc_pfnFillRGBA_t ) ( int x, int y, int width, int height, int r, int g, int b, int a ); +typedef int (*pfnEngSrc_pfnGetScreenInfo_t ) ( struct SCREENINFO_s *pscrinfo ); +typedef void (*pfnEngSrc_pfnSetCrosshair_t ) ( HSPRITE_t hspr, wrect_t rc, int r, int g, int b ); +typedef struct cvar_s * (*pfnEngSrc_pfnRegisterVariable_t ) ( char *szName, char *szValue, int flags ); +typedef float (*pfnEngSrc_pfnGetCvarFloat_t ) ( char *szName ); +typedef char* (*pfnEngSrc_pfnGetCvarString_t ) ( char *szName ); +typedef int (*pfnEngSrc_pfnAddCommand_t ) ( char *cmd_name, void (*pfnEngSrc_function)(void) ); +typedef int (*pfnEngSrc_pfnHookUserMsg_t ) ( char *szMsgName, pfnUserMsgHook pfn ); +typedef int (*pfnEngSrc_pfnServerCmd_t ) ( char *szCmdString ); +typedef int (*pfnEngSrc_pfnClientCmd_t ) ( char *szCmdString ); +typedef void (*pfnEngSrc_pfnPrimeMusicStream_t ) ( char *szFilename, int looping ); +typedef void (*pfnEngSrc_pfnGetPlayerInfo_t ) ( int ent_num, struct hud_player_info_s *pinfo ); +typedef void (*pfnEngSrc_pfnPlaySoundByName_t ) ( char *szSound, float volume ); +typedef void (*pfnEngSrc_pfnPlaySoundByNameAtPitch_t )( char *szSound, float volume, int pitch ); +typedef void (*pfnEngSrc_pfnPlaySoundVoiceByName_t ) ( char *szSound, float volume, int pitch ); +typedef void (*pfnEngSrc_pfnPlaySoundByIndex_t ) ( int iSound, float volume ); +typedef void (*pfnEngSrc_pfnAngleVectors_t ) ( const float * vecAngles, float * forward, float * right, float * up ); +typedef struct client_textmessage_s*(*pfnEngSrc_pfnTextMessageGet_t ) ( const char *pName ); +typedef int (*pfnEngSrc_pfnDrawCharacter_t ) ( int x, int y, int number, int r, int g, int b ); +typedef int (*pfnEngSrc_pfnDrawConsoleString_t ) ( int x, int y, char *string ); +typedef void (*pfnEngSrc_pfnDrawSetTextColor_t ) ( float r, float g, float b ); +typedef void (*pfnEngSrc_pfnDrawConsoleStringLen_t ) ( const char *string, int *length, int *height ); +typedef void (*pfnEngSrc_pfnConsolePrint_t ) ( const char *string ); +typedef void (*pfnEngSrc_pfnCenterPrint_t ) ( const char *string ); +typedef int (*pfnEngSrc_GetWindowCenterX_t ) ( void ); +typedef int (*pfnEngSrc_GetWindowCenterY_t ) ( void ); +typedef void (*pfnEngSrc_GetViewAngles_t ) ( float * ); +typedef void (*pfnEngSrc_SetViewAngles_t ) ( float * ); +typedef int (*pfnEngSrc_GetMaxClients_t ) ( void ); +typedef void (*pfnEngSrc_Cvar_SetValue_t ) ( char *cvar, float value ); +typedef int (*pfnEngSrc_Cmd_Argc_t) (void); +typedef char * (*pfnEngSrc_Cmd_Argv_t ) ( int arg ); +typedef void (*pfnEngSrc_Con_Printf_t ) ( char *fmt, ... ); +typedef void (*pfnEngSrc_Con_DPrintf_t ) ( char *fmt, ... ); +typedef void (*pfnEngSrc_Con_NPrintf_t ) ( int pos, char *fmt, ... ); +typedef void (*pfnEngSrc_Con_NXPrintf_t ) ( struct con_nprint_s *info, char *fmt, ... ); +typedef const char * (*pfnEngSrc_PhysInfo_ValueForKey_t ) ( const char *key ); +typedef const char * (*pfnEngSrc_ServerInfo_ValueForKey_t ) ( const char *key ); +typedef float (*pfnEngSrc_GetClientMaxspeed_t ) ( void ); +typedef int (*pfnEngSrc_CheckParm_t ) ( char *parm, char **ppnext ); +typedef void (*pfnEngSrc_Key_Event_t ) ( int key, int down ); +typedef void (*pfnEngSrc_GetMousePosition_t ) ( int *mx, int *my ); +typedef int (*pfnEngSrc_IsNoClipping_t ) ( void ); +typedef struct cl_entity_s * (*pfnEngSrc_GetLocalPlayer_t ) ( void ); +typedef struct cl_entity_s * (*pfnEngSrc_GetViewModel_t ) ( void ); +typedef struct cl_entity_s * (*pfnEngSrc_GetEntityByIndex_t ) ( int idx ); +typedef float (*pfnEngSrc_GetClientTime_t ) ( void ); +typedef void (*pfnEngSrc_V_CalcShake_t ) ( void ); +typedef void (*pfnEngSrc_V_ApplyShake_t ) ( float *origin, float *angles, float factor ); +typedef int (*pfnEngSrc_PM_PointContents_t ) ( float *point, int *truecontents ); +typedef int (*pfnEngSrc_PM_WaterEntity_t ) ( float *p ); +typedef struct pmtrace_s * (*pfnEngSrc_PM_TraceLine_t ) ( float *start, float *end, int flags, int usehull, int ignore_pe ); +typedef struct model_s * (*pfnEngSrc_CL_LoadModel_t ) ( const char *modelname, int *index ); +typedef int (*pfnEngSrc_CL_CreateVisibleEntity_t ) ( int type, struct cl_entity_s *ent ); +typedef const struct model_s * (*pfnEngSrc_GetSpritePointer_t ) ( HSPRITE_t hSprite ); +typedef void (*pfnEngSrc_pfnPlaySoundByNameAtLocation_t )( char *szSound, float volume, float *origin ); +typedef unsigned short (*pfnEngSrc_pfnPrecacheEvent_t ) ( int type, const char* psz ); +typedef void (*pfnEngSrc_pfnPlaybackEvent_t ) ( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); +typedef void (*pfnEngSrc_pfnWeaponAnim_t ) ( int iAnim, int body ); +typedef float (*pfnEngSrc_pfnRandomFloat_t ) ( float flLow, float flHigh ); +typedef int32_t (*pfnEngSrc_pfnRandomLong_t ) ( int32_t lLow, int32_t lHigh ); +typedef void (*pfnEngSrc_pfnHookEvent_t ) ( char *name, void ( *pfnEvent )( struct event_args_s *args ) ); +typedef int (*pfnEngSrc_Con_IsVisible_t) (); +typedef const char * (*pfnEngSrc_pfnGetGameDirectory_t ) ( void ); +typedef struct cvar_s * (*pfnEngSrc_pfnGetCvarPointer_t ) ( const char *szName ); +typedef const char * (*pfnEngSrc_Key_LookupBinding_t ) ( const char *pBinding ); +typedef const char * (*pfnEngSrc_pfnGetLevelName_t ) ( void ); +typedef void (*pfnEngSrc_pfnGetScreenFade_t ) ( struct screenfade_s *fade ); +typedef void (*pfnEngSrc_pfnSetScreenFade_t ) ( struct screenfade_s *fade ); +typedef void * (*pfnEngSrc_VGui_GetPanel_t ) ( ); +typedef void (*pfnEngSrc_VGui_ViewportPaintBackground_t )(int extents[4]); +typedef byte* (*pfnEngSrc_COM_LoadFile_t ) ( char *path, int usehunk, int *pLength ); +typedef char* (*pfnEngSrc_COM_ParseFile_t ) ( char *data, char *token ); +typedef void (*pfnEngSrc_COM_FreeFile_t) ( void *buffer ); +typedef struct triangleapi_s * pTriAPI; +typedef struct efx_api_s * pEfxAPI; +typedef struct event_api_s * pEventAPI; +typedef struct demo_api_s * pDemoAPI; +typedef struct net_api_s * pNetAPI; +typedef struct IVoiceTweak_s * pVoiceTweak; +typedef int (*pfnEngSrc_IsSpectateOnly_t ) ( void ); +typedef struct model_s * (*pfnEngSrc_LoadMapSprite_t ) ( const char *filename ); +typedef void (*pfnEngSrc_COM_AddAppDirectoryToSearchPath_t ) ( const char *pszBaseDir, const char *appName ); +typedef int (*pfnEngSrc_COM_ExpandFilename_t) ( const char *fileName, char *nameOutBuffer, int nameOutBufferSize ); +typedef const char * (*pfnEngSrc_PlayerInfo_ValueForKey_t ) ( int playerNum, const char *key ); +typedef void (*pfnEngSrc_PlayerInfo_SetValueForKey_t )( const char *key, const char *value ); +typedef qboolean (*pfnEngSrc_GetPlayerUniqueID_t) (int iPlayer, char playerID[16]); +typedef int (*pfnEngSrc_GetTrackerIDForPlayer_t) (int playerSlot); +typedef int (*pfnEngSrc_GetPlayerForTrackerID_t) (int trackerID); +typedef int (*pfnEngSrc_pfnServerCmdUnreliable_t ) ( char *szCmdString ); +typedef void (*pfnEngSrc_GetMousePos_t ) (struct tagPOINT *ppt); +typedef void (*pfnEngSrc_SetMousePos_t ) (int x, int y); +typedef void (*pfnEngSrc_SetMouseEnable_t) (qboolean fEnable); +typedef struct cvar_s * (*pfnEngSrc_GetFirstCVarPtr_t) (); +typedef unsigned int (*pfnEngSrc_GetFirstCmdFunctionHandle_t)(); +typedef unsigned int (*pfnEngSrc_GetNextCmdFunctionHandle_t) (unsigned int cmdhandle); +typedef const char * (*pfnEngSrc_GetCmdFunctionName_t) (unsigned int cmdhandle); +typedef float (*pfnEngSrc_GetClientOldTime_t) (); +typedef float (*pfnEngSrc_GetServerGravityValue_t) (); +typedef struct model_s * (*pfnEngSrc_GetModelByIndex_t) ( int index ); +typedef void (*pfnEngSrc_pfnSetFilterMode_t ) ( int mode ); +typedef void (*pfnEngSrc_pfnSetFilterColor_t ) ( float r, float g, float b ); +typedef void (*pfnEngSrc_pfnSetFilterBrightness_t ) ( float brightness ); +typedef sequenceEntry_s* (*pfnEngSrc_pfnSequenceGet_t ) ( const char *fileName, const char* entryName ); +typedef void (*pfnEngSrc_pfnSPR_DrawGeneric_t ) ( int frame, int x, int y, const struct rect_s *prc, int src, int dest, int w, int h ); +typedef sentenceEntry_s* (*pfnEngSrc_pfnSequencePickSentence_t ) ( const char *sentenceName, int pickMethod, int* entryPicked ); +// draw a complete string +typedef int (*pfnEngSrc_pfnDrawString_t ) ( int x, int y, const char *str, int r, int g, int b ); +typedef int (*pfnEngSrc_pfnDrawStringReverse_t ) ( int x, int y, const char *str, int r, int g, int b ); +typedef const char * (*pfnEngSrc_LocalPlayerInfo_ValueForKey_t )( const char *key ); +typedef int (*pfnEngSrc_pfnVGUI2DrawCharacter_t ) ( int x, int y, int ch, unsigned int font ); +typedef int (*pfnEngSrc_pfnVGUI2DrawCharacterAdd_t )( int x, int y, int ch, int r, int g, int b, unsigned int font); +typedef unsigned int (*pfnEngSrc_COM_GetApproxWavePlayLength )( const char * filename); +typedef void * (*pfnEngSrc_pfnGetCareerUI_t) (); +typedef void (*pfnEngSrc_Cvar_Set_t ) ( char *cvar, char *value ); +typedef int (*pfnEngSrc_pfnIsPlayingCareerMatch_t) (); +typedef double (*pfnEngSrc_GetAbsoluteTime_t) ( void ); +typedef void (*pfnEngSrc_pfnProcessTutorMessageDecayBuffer_t)(int *buffer, int bufferLength); +typedef void (*pfnEngSrc_pfnConstructTutorMessageDecayBuffer_t)(int *buffer, int bufferLength); +typedef void (*pfnEngSrc_pfnResetTutorMessageDecayData_t)(); +typedef void (*pfnEngSrc_pfnFillRGBABlend_t ) ( int x, int y, int width, int height, int r, int g, int b, int a ); +typedef int (*pfnEngSrc_pfnGetAppID_t) ( void ); +typedef cmdalias_t* (*pfnEngSrc_pfnGetAliases_t) ( void ); +typedef void (*pfnEngSrc_pfnVguiWrap2_GetMouseDelta_t)( int *x, int *y ); + +// Pointers to the exported engine functions themselves +typedef struct cl_enginefuncs_s +{ + pfnEngSrc_pfnSPR_Load_t pfnSPR_Load; + pfnEngSrc_pfnSPR_Frames_t pfnSPR_Frames; + pfnEngSrc_pfnSPR_Height_t pfnSPR_Height; + pfnEngSrc_pfnSPR_Width_t pfnSPR_Width; + pfnEngSrc_pfnSPR_Set_t pfnSPR_Set; + pfnEngSrc_pfnSPR_Draw_t pfnSPR_Draw; + pfnEngSrc_pfnSPR_DrawHoles_t pfnSPR_DrawHoles; + pfnEngSrc_pfnSPR_DrawAdditive_t pfnSPR_DrawAdditive; + pfnEngSrc_pfnSPR_EnableScissor_t pfnSPR_EnableScissor; + pfnEngSrc_pfnSPR_DisableScissor_t pfnSPR_DisableScissor; + pfnEngSrc_pfnSPR_GetList_t pfnSPR_GetList; + pfnEngSrc_pfnFillRGBA_t pfnFillRGBA; + pfnEngSrc_pfnGetScreenInfo_t pfnGetScreenInfo; + pfnEngSrc_pfnSetCrosshair_t pfnSetCrosshair; + pfnEngSrc_pfnRegisterVariable_t pfnRegisterVariable; + pfnEngSrc_pfnGetCvarFloat_t pfnGetCvarFloat; + pfnEngSrc_pfnGetCvarString_t pfnGetCvarString; + pfnEngSrc_pfnAddCommand_t pfnAddCommand; + pfnEngSrc_pfnHookUserMsg_t pfnHookUserMsg; + pfnEngSrc_pfnServerCmd_t pfnServerCmd; + pfnEngSrc_pfnClientCmd_t pfnClientCmd; + pfnEngSrc_pfnGetPlayerInfo_t pfnGetPlayerInfo; + pfnEngSrc_pfnPlaySoundByName_t pfnPlaySoundByName; + pfnEngSrc_pfnPlaySoundByIndex_t pfnPlaySoundByIndex; + pfnEngSrc_pfnAngleVectors_t pfnAngleVectors; + pfnEngSrc_pfnTextMessageGet_t pfnTextMessageGet; + pfnEngSrc_pfnDrawCharacter_t pfnDrawCharacter; + pfnEngSrc_pfnDrawConsoleString_t pfnDrawConsoleString; + pfnEngSrc_pfnDrawSetTextColor_t pfnDrawSetTextColor; + pfnEngSrc_pfnDrawConsoleStringLen_t pfnDrawConsoleStringLen; + pfnEngSrc_pfnConsolePrint_t pfnConsolePrint; + pfnEngSrc_pfnCenterPrint_t pfnCenterPrint; + pfnEngSrc_GetWindowCenterX_t GetWindowCenterX; + pfnEngSrc_GetWindowCenterY_t GetWindowCenterY; + pfnEngSrc_GetViewAngles_t GetViewAngles; + pfnEngSrc_SetViewAngles_t SetViewAngles; + pfnEngSrc_GetMaxClients_t GetMaxClients; + pfnEngSrc_Cvar_SetValue_t Cvar_SetValue; + pfnEngSrc_Cmd_Argc_t Cmd_Argc; + pfnEngSrc_Cmd_Argv_t Cmd_Argv; + pfnEngSrc_Con_Printf_t Con_Printf; + pfnEngSrc_Con_DPrintf_t Con_DPrintf; + pfnEngSrc_Con_NPrintf_t Con_NPrintf; + pfnEngSrc_Con_NXPrintf_t Con_NXPrintf; + pfnEngSrc_PhysInfo_ValueForKey_t PhysInfo_ValueForKey; + pfnEngSrc_ServerInfo_ValueForKey_t ServerInfo_ValueForKey; + pfnEngSrc_GetClientMaxspeed_t GetClientMaxspeed; + pfnEngSrc_CheckParm_t CheckParm; + pfnEngSrc_Key_Event_t Key_Event; + pfnEngSrc_GetMousePosition_t GetMousePosition; + pfnEngSrc_IsNoClipping_t IsNoClipping; + pfnEngSrc_GetLocalPlayer_t GetLocalPlayer; + pfnEngSrc_GetViewModel_t GetViewModel; + pfnEngSrc_GetEntityByIndex_t GetEntityByIndex; + pfnEngSrc_GetClientTime_t GetClientTime; + pfnEngSrc_V_CalcShake_t V_CalcShake; + pfnEngSrc_V_ApplyShake_t V_ApplyShake; + pfnEngSrc_PM_PointContents_t PM_PointContents; + pfnEngSrc_PM_WaterEntity_t PM_WaterEntity; + pfnEngSrc_PM_TraceLine_t PM_TraceLine; + pfnEngSrc_CL_LoadModel_t CL_LoadModel; + pfnEngSrc_CL_CreateVisibleEntity_t CL_CreateVisibleEntity; + pfnEngSrc_GetSpritePointer_t GetSpritePointer; + pfnEngSrc_pfnPlaySoundByNameAtLocation_t pfnPlaySoundByNameAtLocation; + pfnEngSrc_pfnPrecacheEvent_t pfnPrecacheEvent; + pfnEngSrc_pfnPlaybackEvent_t pfnPlaybackEvent; + pfnEngSrc_pfnWeaponAnim_t pfnWeaponAnim; + pfnEngSrc_pfnRandomFloat_t pfnRandomFloat; + pfnEngSrc_pfnRandomLong_t pfnRandomLong; + pfnEngSrc_pfnHookEvent_t pfnHookEvent; + pfnEngSrc_Con_IsVisible_t Con_IsVisible; + pfnEngSrc_pfnGetGameDirectory_t pfnGetGameDirectory; + pfnEngSrc_pfnGetCvarPointer_t pfnGetCvarPointer; + pfnEngSrc_Key_LookupBinding_t Key_LookupBinding; + pfnEngSrc_pfnGetLevelName_t pfnGetLevelName; + pfnEngSrc_pfnGetScreenFade_t pfnGetScreenFade; + pfnEngSrc_pfnSetScreenFade_t pfnSetScreenFade; + pfnEngSrc_VGui_GetPanel_t VGui_GetPanel; + pfnEngSrc_VGui_ViewportPaintBackground_t VGui_ViewportPaintBackground; + pfnEngSrc_COM_LoadFile_t COM_LoadFile; + pfnEngSrc_COM_ParseFile_t COM_ParseFile; + pfnEngSrc_COM_FreeFile_t COM_FreeFile; + struct triangleapi_s *pTriAPI; + struct efx_api_s *pEfxAPI; + struct event_api_s *pEventAPI; + struct demo_api_s *pDemoAPI; + struct net_api_s *pNetAPI; + struct IVoiceTweak_s *pVoiceTweak; + pfnEngSrc_IsSpectateOnly_t IsSpectateOnly; + pfnEngSrc_LoadMapSprite_t LoadMapSprite; + pfnEngSrc_COM_AddAppDirectoryToSearchPath_t COM_AddAppDirectoryToSearchPath; + pfnEngSrc_COM_ExpandFilename_t COM_ExpandFilename; + pfnEngSrc_PlayerInfo_ValueForKey_t PlayerInfo_ValueForKey; + pfnEngSrc_PlayerInfo_SetValueForKey_t PlayerInfo_SetValueForKey; + pfnEngSrc_GetPlayerUniqueID_t GetPlayerUniqueID; + pfnEngSrc_GetTrackerIDForPlayer_t GetTrackerIDForPlayer; + pfnEngSrc_GetPlayerForTrackerID_t GetPlayerForTrackerID; + pfnEngSrc_pfnServerCmdUnreliable_t pfnServerCmdUnreliable; + pfnEngSrc_GetMousePos_t pfnGetMousePos; + pfnEngSrc_SetMousePos_t pfnSetMousePos; + pfnEngSrc_SetMouseEnable_t pfnSetMouseEnable; + pfnEngSrc_GetFirstCVarPtr_t GetFirstCvarPtr; + pfnEngSrc_GetFirstCmdFunctionHandle_t GetFirstCmdFunctionHandle; + pfnEngSrc_GetNextCmdFunctionHandle_t GetNextCmdFunctionHandle; + pfnEngSrc_GetCmdFunctionName_t GetCmdFunctionName; + pfnEngSrc_GetClientOldTime_t hudGetClientOldTime; + pfnEngSrc_GetServerGravityValue_t hudGetServerGravityValue; + pfnEngSrc_GetModelByIndex_t hudGetModelByIndex; + pfnEngSrc_pfnSetFilterMode_t pfnSetFilterMode; + pfnEngSrc_pfnSetFilterColor_t pfnSetFilterColor; + pfnEngSrc_pfnSetFilterBrightness_t pfnSetFilterBrightness; + pfnEngSrc_pfnSequenceGet_t pfnSequenceGet; + pfnEngSrc_pfnSPR_DrawGeneric_t pfnSPR_DrawGeneric; + pfnEngSrc_pfnSequencePickSentence_t pfnSequencePickSentence; + pfnEngSrc_pfnDrawString_t pfnDrawString; + pfnEngSrc_pfnDrawStringReverse_t pfnDrawStringReverse; + pfnEngSrc_LocalPlayerInfo_ValueForKey_t LocalPlayerInfo_ValueForKey; + pfnEngSrc_pfnVGUI2DrawCharacter_t pfnVGUI2DrawCharacter; + pfnEngSrc_pfnVGUI2DrawCharacterAdd_t pfnVGUI2DrawCharacterAdd; + pfnEngSrc_COM_GetApproxWavePlayLength COM_GetApproxWavePlayLength; + pfnEngSrc_pfnGetCareerUI_t pfnGetCareerUI; + pfnEngSrc_Cvar_Set_t Cvar_Set; + pfnEngSrc_pfnIsPlayingCareerMatch_t pfnIsCareerMatch; + pfnEngSrc_pfnPlaySoundVoiceByName_t pfnPlaySoundVoiceByName; + pfnEngSrc_pfnPrimeMusicStream_t pfnPrimeMusicStream; + pfnEngSrc_GetAbsoluteTime_t GetAbsoluteTime; + pfnEngSrc_pfnProcessTutorMessageDecayBuffer_t pfnProcessTutorMessageDecayBuffer; + pfnEngSrc_pfnConstructTutorMessageDecayBuffer_t pfnConstructTutorMessageDecayBuffer; + pfnEngSrc_pfnResetTutorMessageDecayData_t pfnResetTutorMessageDecayData; + pfnEngSrc_pfnPlaySoundByNameAtPitch_t pfnPlaySoundByNameAtPitch; + pfnEngSrc_pfnFillRGBABlend_t pfnFillRGBABlend; + pfnEngSrc_pfnGetAppID_t pfnGetAppID; + pfnEngSrc_pfnGetAliases_t pfnGetAliasList; + pfnEngSrc_pfnVguiWrap2_GetMouseDelta_t pfnVguiWrap2_GetMouseDelta; +} cl_enginefunc_t; + +// Function type declarations for engine destination functions +typedef void(*pfnEngDst_pfnSPR_Load_t) (const char **); +typedef void(*pfnEngDst_pfnSPR_Frames_t) (HSPRITE_t *); +typedef void(*pfnEngDst_pfnSPR_Height_t) (HSPRITE_t *, int *); +typedef void(*pfnEngDst_pfnSPR_Width_t) (HSPRITE_t *, int *); +typedef void(*pfnEngDst_pfnSPR_Set_t) (HSPRITE_t *, int *, int *, int *); +typedef void(*pfnEngDst_pfnSPR_Draw_t) (int *, int *, int *, const struct rect_s **); +typedef void(*pfnEngDst_pfnSPR_DrawHoles_t) (int *, int *, int *, const struct rect_s **); +typedef void(*pfnEngDst_pfnSPR_DrawAdditive_t) (int *, int *, int *, const struct rect_s **); +typedef void(*pfnEngDst_pfnSPR_EnableScissor_t) (int *, int *, int *, int *); +typedef void(*pfnEngDst_pfnSPR_DisableScissor_t) (void); +typedef void(*pfnEngDst_pfnSPR_GetList_t) (char **, int **); +typedef void(*pfnEngDst_pfnFillRGBA_t) (int *, int *, int *, int *, int *, int *, int *, int *); +typedef void(*pfnEngDst_pfnGetScreenInfo_t) (struct SCREENINFO_s **); +typedef void(*pfnEngDst_pfnSetCrosshair_t) (HSPRITE_t *, struct rect_s *, int *, int *, int *); +typedef void(*pfnEngDst_pfnRegisterVariable_t) (char **, char **, int *); +typedef void(*pfnEngDst_pfnGetCvarFloat_t) (char **); +typedef void(*pfnEngDst_pfnGetCvarString_t) (char **); +typedef void(*pfnEngDst_pfnAddCommand_t) (char **, void(**pfnEngDst_function)(void)); +typedef void(*pfnEngDst_pfnHookUserMsg_t) (char **, pfnUserMsgHook *); +typedef void(*pfnEngDst_pfnServerCmd_t) (char **); +typedef void(*pfnEngDst_pfnClientCmd_t) (char **); +typedef void(*pfnEngDst_pfnPrimeMusicStream_t) (char **, int *); +typedef void(*pfnEngDst_pfnGetPlayerInfo_t) (int *, struct hud_player_info_s **); +typedef void(*pfnEngDst_pfnPlaySoundByName_t) (char **, float *); +typedef void(*pfnEngDst_pfnPlaySoundByNameAtPitch_t) (char **, float *, int *); +typedef void(*pfnEngDst_pfnPlaySoundVoiceByName_t) (char **, float *); +typedef void(*pfnEngDst_pfnPlaySoundByIndex_t) (int *, float *); +typedef void(*pfnEngDst_pfnAngleVectors_t) (const float * *, float * *, float * *, float * *); +typedef void(*pfnEngDst_pfnTextMessageGet_t) (const char **); +typedef void(*pfnEngDst_pfnDrawCharacter_t) (int *, int *, int *, int *, int *, int *); +typedef void(*pfnEngDst_pfnDrawConsoleString_t) (int *, int *, char **); +typedef void(*pfnEngDst_pfnDrawSetTextColor_t) (float *, float *, float *); +typedef void(*pfnEngDst_pfnDrawConsoleStringLen_t) (const char **, int **, int **); +typedef void(*pfnEngDst_pfnConsolePrint_t) (const char **); +typedef void(*pfnEngDst_pfnCenterPrint_t) (const char **); +typedef void(*pfnEngDst_GetWindowCenterX_t) (void); +typedef void(*pfnEngDst_GetWindowCenterY_t) (void); +typedef void(*pfnEngDst_GetViewAngles_t) (float **); +typedef void(*pfnEngDst_SetViewAngles_t) (float **); +typedef void(*pfnEngDst_GetMaxClients_t) (void); +typedef void(*pfnEngDst_Cvar_SetValue_t) (char **, float *); +typedef void(*pfnEngDst_Cmd_Argc_t) (void); +typedef void(*pfnEngDst_Cmd_Argv_t) (int *); +typedef void(*pfnEngDst_Con_Printf_t) (char **); +typedef void(*pfnEngDst_Con_DPrintf_t) (char **); +typedef void(*pfnEngDst_Con_NPrintf_t) (int *, char **); +typedef void(*pfnEngDst_Con_NXPrintf_t) (struct con_nprint_s **, char **); +typedef void(*pfnEngDst_PhysInfo_ValueForKey_t) (const char **); +typedef void(*pfnEngDst_ServerInfo_ValueForKey_t) (const char **); +typedef void(*pfnEngDst_GetClientMaxspeed_t) (void); +typedef void(*pfnEngDst_CheckParm_t) (char **, char ***); +typedef void(*pfnEngDst_Key_Event_t) (int *, int *); +typedef void(*pfnEngDst_GetMousePosition_t) (int **, int **); +typedef void(*pfnEngDst_IsNoClipping_t) (void); +typedef void(*pfnEngDst_GetLocalPlayer_t) (void); +typedef void(*pfnEngDst_GetViewModel_t) (void); +typedef void(*pfnEngDst_GetEntityByIndex_t) (int *); +typedef void(*pfnEngDst_GetClientTime_t) (void); +typedef void(*pfnEngDst_V_CalcShake_t) (void); +typedef void(*pfnEngDst_V_ApplyShake_t) (float **, float **, float *); +typedef void(*pfnEngDst_PM_PointContents_t) (float **, int **); +typedef void(*pfnEngDst_PM_WaterEntity_t) (float **); +typedef void(*pfnEngDst_PM_TraceLine_t) (float **, float **, int *, int *, int *); +typedef void(*pfnEngDst_CL_LoadModel_t) (const char **, int **); +typedef void(*pfnEngDst_CL_CreateVisibleEntity_t) (int *, struct cl_entity_s **); +typedef void(*pfnEngDst_GetSpritePointer_t) (HSPRITE_t *); +typedef void(*pfnEngDst_pfnPlaySoundByNameAtLocation_t) (char **, float *, float **); +typedef void(*pfnEngDst_pfnPrecacheEvent_t) (int *, const char* *); +typedef void(*pfnEngDst_pfnPlaybackEvent_t) (int *, const struct edict_s **, unsigned short *, float *, float **, float **, float *, float *, int *, int *, int *, int *); +typedef void(*pfnEngDst_pfnWeaponAnim_t) (int *, int *); +typedef void(*pfnEngDst_pfnRandomFloat_t) (float *, float *); +typedef void(*pfnEngDst_pfnRandomLong_t) (int32_t *, int32_t *); +typedef void(*pfnEngDst_pfnHookEvent_t) (char **, void(**pfnEvent)(struct event_args_s *args)); +typedef void(*pfnEngDst_Con_IsVisible_t) (); +typedef void(*pfnEngDst_pfnGetGameDirectory_t) (void); +typedef void(*pfnEngDst_pfnGetCvarPointer_t) (const char **); +typedef void(*pfnEngDst_Key_LookupBinding_t) (const char **); +typedef void(*pfnEngDst_pfnGetLevelName_t) (void); +typedef void(*pfnEngDst_pfnGetScreenFade_t) (struct screenfade_s **); +typedef void(*pfnEngDst_pfnSetScreenFade_t) (struct screenfade_s **); +typedef void(*pfnEngDst_VGui_GetPanel_t) (); +typedef void(*pfnEngDst_VGui_ViewportPaintBackground_t) (int **); +typedef void(*pfnEngDst_COM_LoadFile_t) (char **, int *, int **); +typedef void(*pfnEngDst_COM_ParseFile_t) (char **, char **); +typedef void(*pfnEngDst_COM_FreeFile_t) (void **); +typedef void(*pfnEngDst_IsSpectateOnly_t) (void); +typedef void(*pfnEngDst_LoadMapSprite_t) (const char **); +typedef void(*pfnEngDst_COM_AddAppDirectoryToSearchPath_t) (const char **, const char **); +typedef void(*pfnEngDst_COM_ExpandFilename_t) (const char **, char **, int *); +typedef void(*pfnEngDst_PlayerInfo_ValueForKey_t) (int *, const char **); +typedef void(*pfnEngDst_PlayerInfo_SetValueForKey_t) (const char **, const char **); +typedef void(*pfnEngDst_GetPlayerUniqueID_t) (int *, char **); +typedef void(*pfnEngDst_GetTrackerIDForPlayer_t) (int *); +typedef void(*pfnEngDst_GetPlayerForTrackerID_t) (int *); +typedef void(*pfnEngDst_pfnServerCmdUnreliable_t) (char **); +typedef void(*pfnEngDst_GetMousePos_t) (struct tagPOINT **); +typedef void(*pfnEngDst_SetMousePos_t) (int *, int *); +typedef void(*pfnEngDst_SetMouseEnable_t) (qboolean *); +typedef void(*pfnEngDst_pfnSetFilterMode_t) (int *); +typedef void(*pfnEngDst_pfnSetFilterColor_t) (float *, float *, float *); +typedef void(*pfnEngDst_pfnSetFilterBrightness_t) (float *); +typedef void(*pfnEngDst_pfnSequenceGet_t) (const char**, const char**); +typedef void(*pfnEngDst_pfnSPR_DrawGeneric_t) (int *, int *, int *, const struct rect_s **, int *, int *, int *, int *); +typedef void(*pfnEngDst_pfnSequencePickSentence_t) (const char**, int *, int **); +typedef void(*pfnEngDst_pfnDrawString_t) (int *, int *, const char *, int *, int *, int *); +typedef void(*pfnEngDst_pfnDrawStringReverse_t) (int *, int *, const char *, int *, int *, int *); +typedef void(*pfnEngDst_LocalPlayerInfo_ValueForKey_t) (const char **); +typedef void(*pfnEngDst_pfnVGUI2DrawCharacter_t) (int *, int *, int *, unsigned int *); +typedef void(*pfnEngDst_pfnVGUI2DrawCharacterAdd_t) (int *, int *, int *, int *, int *, int *, unsigned int *); +typedef void(*pfnEngDst_pfnProcessTutorMessageDecayBuffer_t) (int **, int *); +typedef void(*pfnEngDst_pfnConstructTutorMessageDecayBuffer_t) (int **, int *); +typedef void(*pfnEngDst_pfnResetTutorMessageDecayData_t) (); +typedef void(*pfnEngDst_pfnFillRGBABlend_t) (int *, int *, int *, int *, int *, int *, int *, int *); +typedef void(*pfnEngDst_pfnGetAppID_t) (void); +typedef void(*pfnEngDst_pfnGetAliases_t) (void); +typedef void(*pfnEngDst_pfnVguiWrap2_GetMouseDelta_t) (int *x, int *y); + + +// Pointers to the engine destination functions +typedef struct +{ + pfnEngDst_pfnSPR_Load_t pfnSPR_Load; + pfnEngDst_pfnSPR_Frames_t pfnSPR_Frames; + pfnEngDst_pfnSPR_Height_t pfnSPR_Height; + pfnEngDst_pfnSPR_Width_t pfnSPR_Width; + pfnEngDst_pfnSPR_Set_t pfnSPR_Set; + pfnEngDst_pfnSPR_Draw_t pfnSPR_Draw; + pfnEngDst_pfnSPR_DrawHoles_t pfnSPR_DrawHoles; + pfnEngDst_pfnSPR_DrawAdditive_t pfnSPR_DrawAdditive; + pfnEngDst_pfnSPR_EnableScissor_t pfnSPR_EnableScissor; + pfnEngDst_pfnSPR_DisableScissor_t pfnSPR_DisableScissor; + pfnEngDst_pfnSPR_GetList_t pfnSPR_GetList; + pfnEngDst_pfnFillRGBA_t pfnFillRGBA; + pfnEngDst_pfnGetScreenInfo_t pfnGetScreenInfo; + pfnEngDst_pfnSetCrosshair_t pfnSetCrosshair; + pfnEngDst_pfnRegisterVariable_t pfnRegisterVariable; + pfnEngDst_pfnGetCvarFloat_t pfnGetCvarFloat; + pfnEngDst_pfnGetCvarString_t pfnGetCvarString; + pfnEngDst_pfnAddCommand_t pfnAddCommand; + pfnEngDst_pfnHookUserMsg_t pfnHookUserMsg; + pfnEngDst_pfnServerCmd_t pfnServerCmd; + pfnEngDst_pfnClientCmd_t pfnClientCmd; + pfnEngDst_pfnGetPlayerInfo_t pfnGetPlayerInfo; + pfnEngDst_pfnPlaySoundByName_t pfnPlaySoundByName; + pfnEngDst_pfnPlaySoundByIndex_t pfnPlaySoundByIndex; + pfnEngDst_pfnAngleVectors_t pfnAngleVectors; + pfnEngDst_pfnTextMessageGet_t pfnTextMessageGet; + pfnEngDst_pfnDrawCharacter_t pfnDrawCharacter; + pfnEngDst_pfnDrawConsoleString_t pfnDrawConsoleString; + pfnEngDst_pfnDrawSetTextColor_t pfnDrawSetTextColor; + pfnEngDst_pfnDrawConsoleStringLen_t pfnDrawConsoleStringLen; + pfnEngDst_pfnConsolePrint_t pfnConsolePrint; + pfnEngDst_pfnCenterPrint_t pfnCenterPrint; + pfnEngDst_GetWindowCenterX_t GetWindowCenterX; + pfnEngDst_GetWindowCenterY_t GetWindowCenterY; + pfnEngDst_GetViewAngles_t GetViewAngles; + pfnEngDst_SetViewAngles_t SetViewAngles; + pfnEngDst_GetMaxClients_t GetMaxClients; + pfnEngDst_Cvar_SetValue_t Cvar_SetValue; + pfnEngDst_Cmd_Argc_t Cmd_Argc; + pfnEngDst_Cmd_Argv_t Cmd_Argv; + pfnEngDst_Con_Printf_t Con_Printf; + pfnEngDst_Con_DPrintf_t Con_DPrintf; + pfnEngDst_Con_NPrintf_t Con_NPrintf; + pfnEngDst_Con_NXPrintf_t Con_NXPrintf; + pfnEngDst_PhysInfo_ValueForKey_t PhysInfo_ValueForKey; + pfnEngDst_ServerInfo_ValueForKey_t ServerInfo_ValueForKey; + pfnEngDst_GetClientMaxspeed_t GetClientMaxspeed; + pfnEngDst_CheckParm_t CheckParm; + pfnEngDst_Key_Event_t Key_Event; + pfnEngDst_GetMousePosition_t GetMousePosition; + pfnEngDst_IsNoClipping_t IsNoClipping; + pfnEngDst_GetLocalPlayer_t GetLocalPlayer; + pfnEngDst_GetViewModel_t GetViewModel; + pfnEngDst_GetEntityByIndex_t GetEntityByIndex; + pfnEngDst_GetClientTime_t GetClientTime; + pfnEngDst_V_CalcShake_t V_CalcShake; + pfnEngDst_V_ApplyShake_t V_ApplyShake; + pfnEngDst_PM_PointContents_t PM_PointContents; + pfnEngDst_PM_WaterEntity_t PM_WaterEntity; + pfnEngDst_PM_TraceLine_t PM_TraceLine; + pfnEngDst_CL_LoadModel_t CL_LoadModel; + pfnEngDst_CL_CreateVisibleEntity_t CL_CreateVisibleEntity; + pfnEngDst_GetSpritePointer_t GetSpritePointer; + pfnEngDst_pfnPlaySoundByNameAtLocation_t pfnPlaySoundByNameAtLocation; + pfnEngDst_pfnPrecacheEvent_t pfnPrecacheEvent; + pfnEngDst_pfnPlaybackEvent_t pfnPlaybackEvent; + pfnEngDst_pfnWeaponAnim_t pfnWeaponAnim; + pfnEngDst_pfnRandomFloat_t pfnRandomFloat; + pfnEngDst_pfnRandomLong_t pfnRandomLong; + pfnEngDst_pfnHookEvent_t pfnHookEvent; + pfnEngDst_Con_IsVisible_t Con_IsVisible; + pfnEngDst_pfnGetGameDirectory_t pfnGetGameDirectory; + pfnEngDst_pfnGetCvarPointer_t pfnGetCvarPointer; + pfnEngDst_Key_LookupBinding_t Key_LookupBinding; + pfnEngDst_pfnGetLevelName_t pfnGetLevelName; + pfnEngDst_pfnGetScreenFade_t pfnGetScreenFade; + pfnEngDst_pfnSetScreenFade_t pfnSetScreenFade; + pfnEngDst_VGui_GetPanel_t VGui_GetPanel; + pfnEngDst_VGui_ViewportPaintBackground_t VGui_ViewportPaintBackground; + pfnEngDst_COM_LoadFile_t COM_LoadFile; + pfnEngDst_COM_ParseFile_t COM_ParseFile; + pfnEngDst_COM_FreeFile_t COM_FreeFile; + struct triangleapi_s *pTriAPI; + struct efx_api_s *pEfxAPI; + struct event_api_s *pEventAPI; + struct demo_api_s *pDemoAPI; + struct net_api_s *pNetAPI; + struct IVoiceTweak_s *pVoiceTweak; + pfnEngDst_IsSpectateOnly_t IsSpectateOnly; + pfnEngDst_LoadMapSprite_t LoadMapSprite; + pfnEngDst_COM_AddAppDirectoryToSearchPath_t COM_AddAppDirectoryToSearchPath; + pfnEngDst_COM_ExpandFilename_t COM_ExpandFilename; + pfnEngDst_PlayerInfo_ValueForKey_t PlayerInfo_ValueForKey; + pfnEngDst_PlayerInfo_SetValueForKey_t PlayerInfo_SetValueForKey; + pfnEngDst_GetPlayerUniqueID_t GetPlayerUniqueID; + pfnEngDst_GetTrackerIDForPlayer_t GetTrackerIDForPlayer; + pfnEngDst_GetPlayerForTrackerID_t GetPlayerForTrackerID; + pfnEngDst_pfnServerCmdUnreliable_t pfnServerCmdUnreliable; + pfnEngDst_GetMousePos_t pfnGetMousePos; + pfnEngDst_SetMousePos_t pfnSetMousePos; + pfnEngDst_SetMouseEnable_t pfnSetMouseEnable; + pfnEngDst_pfnSetFilterMode_t pfnSetFilterMode ; + pfnEngDst_pfnSetFilterColor_t pfnSetFilterColor ; + pfnEngDst_pfnSetFilterBrightness_t pfnSetFilterBrightness ; + pfnEngDst_pfnSequenceGet_t pfnSequenceGet; + pfnEngDst_pfnSPR_DrawGeneric_t pfnSPR_DrawGeneric; + pfnEngDst_pfnSequencePickSentence_t pfnSequencePickSentence; + pfnEngDst_pfnDrawString_t pfnDrawString; + pfnEngDst_pfnDrawString_t pfnDrawStringReverse; + pfnEngDst_LocalPlayerInfo_ValueForKey_t LocalPlayerInfo_ValueForKey; + pfnEngDst_pfnVGUI2DrawCharacter_t pfnVGUI2DrawCharacter; + pfnEngDst_pfnVGUI2DrawCharacterAdd_t pfnVGUI2DrawCharacterAdd; + pfnEngDst_pfnPlaySoundVoiceByName_t pfnPlaySoundVoiceByName; + pfnEngDst_pfnPrimeMusicStream_t pfnPrimeMusicStream; + pfnEngDst_pfnProcessTutorMessageDecayBuffer_t pfnProcessTutorMessageDecayBuffer; + pfnEngDst_pfnConstructTutorMessageDecayBuffer_t pfnConstructTutorMessageDecayBuffer; + pfnEngDst_pfnResetTutorMessageDecayData_t pfnResetTutorMessageDecayData; + pfnEngDst_pfnPlaySoundByNameAtPitch_t pfnPlaySoundByNameAtPitch; + pfnEngDst_pfnFillRGBABlend_t pfnFillRGBABlend; + pfnEngDst_pfnGetAppID_t pfnGetAppID; + pfnEngDst_pfnGetAliases_t pfnGetAliasList; + pfnEngDst_pfnVguiWrap2_GetMouseDelta_t pfnVguiWrap2_GetMouseDelta; +} cl_enginefunc_dst_t; + + +// ******************************************************** +// Functions exposed by the engine to the module +// ******************************************************** + +// Functions for ModuleS +typedef void (*PFN_KICKPLAYER)(int nPlayerSlot, int nReason); + +typedef struct modshelpers_s +{ + PFN_KICKPLAYER m_pfnKickPlayer; + + // reserved for future expansion + int m_nVoid1; + int m_nVoid2; + int m_nVoid3; + int m_nVoid4; + int m_nVoid5; + int m_nVoid6; + int m_nVoid7; + int m_nVoid8; + int m_nVoid9; +} modshelpers_t; + +// Functions for moduleC +typedef struct modchelpers_s +{ + // reserved for future expansion + int m_nVoid0; + int m_nVoid1; + int m_nVoid2; + int m_nVoid3; + int m_nVoid4; + int m_nVoid5; + int m_nVoid6; + int m_nVoid7; + int m_nVoid8; + int m_nVoid9; +} modchelpers_t; + + +// ******************************************************** +// Information about the engine +// ******************************************************** +typedef struct engdata_s +{ + cl_enginefunc_t *pcl_enginefuncs; // functions exported by the engine + cl_enginefunc_dst_t *pg_engdstAddrs; // destination handlers for engine exports + cldll_func_t *pcl_funcs; // client exports + cldll_func_dst_t *pg_cldstAddrs; // client export destination handlers + struct modfuncs_s *pg_modfuncs; // engine's pointer to module functions + struct cmd_function_s **pcmd_functions; // list of all registered commands + void *pkeybindings; // all key bindings (not really a void *, but easier this way) + void (*pfnConPrintf)(char *, ...); // dump to console + struct cvar_s **pcvar_vars; // pointer to head of cvar list + struct glwstate_t *pglwstate; // OpenGl information + void *(*pfnSZ_GetSpace)(struct sizebuf_s *, int); // pointer to SZ_GetSpace + struct modfuncs_s *pmodfuncs; // &g_modfuncs + void *pfnGetProcAddress; // &GetProcAddress + void *pfnGetModuleHandle; // &GetModuleHandle + struct server_static_s *psvs; // &svs + struct client_static_s *pcls; // &cls + void (*pfnSV_DropClient)(struct client_s *, qboolean, char *, ...); // pointer to SV_DropClient + void (*pfnNetchan_Transmit)(struct netchan_s *, int, byte *); // pointer to Netchan_Transmit + void (*pfnNET_SendPacket)(enum netsrc_s sock, int length, void *data, netadr_t to); // &NET_SendPacket + struct cvar_s *(*pfnCvarFindVar)(const char *pchName); // pointer to Cvar_FindVar + int *phinstOpenGlEarly; // &g_hinstOpenGlEarly + + // Reserved for future expansion + void *pVoid0; // reserved for future expan + void *pVoid1; // reserved for future expan + void *pVoid2; // reserved for future expan + void *pVoid3; // reserved for future expan + void *pVoid4; // reserved for future expan + void *pVoid5; // reserved for future expan + void *pVoid6; // reserved for future expan + void *pVoid7; // reserved for future expan + void *pVoid8; // reserved for future expan + void *pVoid9; // reserved for future expan +} engdata_t; + + +// ******************************************************** +// Functions exposed by the security module +// ******************************************************** +typedef void (*PFN_LOADMOD)(char *pchModule); +typedef void (*PFN_CLOSEMOD)(void); +typedef int (*PFN_NCALL)(int ijump, int cnArg, ...); + +typedef void (*PFN_GETCLDSTADDRS)(cldll_func_dst_t *pcldstAddrs); +typedef void (*PFN_GETENGDSTADDRS)(cl_enginefunc_dst_t *pengdstAddrs); +typedef void (*PFN_MODULELOADED)(void); + +typedef void (*PFN_PROCESSOUTGOINGNET)(struct netchan_s *pchan, struct sizebuf_s *psizebuf); +typedef qboolean (*PFN_PROCESSINCOMINGNET)(struct netchan_s *pchan, struct sizebuf_s *psizebuf); + +typedef void (*PFN_TEXTURELOAD)(char *pszName, int dxWidth, int dyHeight, char *pbData); +typedef void (*PFN_MODELLOAD)(struct model_s *pmodel, void *pvBuf); + +typedef void (*PFN_FRAMEBEGIN)(void); +typedef void (*PFN_FRAMERENDER1)(void); +typedef void (*PFN_FRAMERENDER2)(void); + +typedef void (*PFN_SETMODSHELPERS)(modshelpers_t *pmodshelpers); +typedef void (*PFN_SETMODCHELPERS)(modchelpers_t *pmodchelpers); +typedef void (*PFN_SETENGDATA)(engdata_t *pengdata); + +typedef void (*PFN_CONNECTCLIENT)(int iPlayer); +typedef void (*PFN_RECORDIP)(unsigned int pnIP); +typedef void (*PFN_PLAYERSTATUS)(unsigned char *pbData, int cbData); + +typedef void (*PFN_SETENGINEVERSION)(int nVersion); + +// typedef class CMachine *(*PFN_PCMACHINE)(void); +typedef int (*PFN_PCMACHINE)(void); +typedef void (*PFN_SETIP)(int ijump); +typedef void (*PFN_EXECUTE)(void); + +typedef struct modfuncs_s +{ + // Functions for the pcode interpreter + PFN_LOADMOD m_pfnLoadMod; + PFN_CLOSEMOD m_pfnCloseMod; + PFN_NCALL m_pfnNCall; + + // API destination functions + PFN_GETCLDSTADDRS m_pfnGetClDstAddrs; + PFN_GETENGDSTADDRS m_pfnGetEngDstAddrs; + + // Miscellaneous functions + PFN_MODULELOADED m_pfnModuleLoaded; // Called right after the module is loaded + + // Functions for processing network traffic + PFN_PROCESSOUTGOINGNET m_pfnProcessOutgoingNet; // Every outgoing packet gets run through this + PFN_PROCESSINCOMINGNET m_pfnProcessIncomingNet; // Every incoming packet gets run through this + + // Resource functions + PFN_TEXTURELOAD m_pfnTextureLoad; // Called as each texture is loaded + PFN_MODELLOAD m_pfnModelLoad; // Called as each model is loaded + + // Functions called every frame + PFN_FRAMEBEGIN m_pfnFrameBegin; // Called at the beginning of each frame cycle + PFN_FRAMERENDER1 m_pfnFrameRender1; // Called at the beginning of the render loop + PFN_FRAMERENDER2 m_pfnFrameRender2; // Called at the end of the render loop + + // Module helper transfer + PFN_SETMODSHELPERS m_pfnSetModSHelpers; + PFN_SETMODCHELPERS m_pfnSetModCHelpers; + PFN_SETENGDATA m_pfnSetEngData; + + // Which version of the module is this? + int m_nVersion; + + // Miscellaneous game stuff + PFN_CONNECTCLIENT m_pfnConnectClient; // Called whenever a new client connects + PFN_RECORDIP m_pfnRecordIP; // Secure master has reported a new IP for us + PFN_PLAYERSTATUS m_pfnPlayerStatus; // Called whenever we receive a PlayerStatus packet + + // Recent additions + PFN_SETENGINEVERSION m_pfnSetEngineVersion; // 1 = patched engine + + // reserved for future expansion + int m_nVoid2; + int m_nVoid3; + int m_nVoid4; + int m_nVoid5; + int m_nVoid6; + int m_nVoid7; + int m_nVoid8; + int m_nVoid9; +} modfuncs_t; + + +#define k_nEngineVersion15Base 0 +#define k_nEngineVersion15Patch 1 +#define k_nEngineVersion16Base 2 +#define k_nEngineVersion16Validated 3 // 1.6 engine with built-in validation + + +typedef struct validator_s +{ + int m_nRandomizer; // Random number to be XOR'd into all subsequent fields + int m_nSignature1; // First signature that identifies this structure + int m_nSignature2; // Second signature + int m_pbCode; // Beginning of the code block + int m_cbCode; // Size of the code block + int m_nChecksum; // Checksum of the code block + int m_nSpecial; // For engine, 1 if hw.dll, 0 if sw.dll. For client, pclfuncs checksum + int m_nCompensator; // Keeps the checksum correct +} validator_t; + + +#define k_nChecksumCompensator 0x36a8f09c // Don't change this value: it's hardcorded in cdll_int.cpp, + +#define k_nModuleVersionCur 0x43210004 + + +#endif // __APIPROXY__ diff --git a/rehlds/engine/anorms.h b/rehlds/engine/anorms.h new file mode 100644 index 0000000..c90f8d6 --- /dev/null +++ b/rehlds/engine/anorms.h @@ -0,0 +1,177 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/rehlds/engine/buildnum.cpp b/rehlds/engine/buildnum.cpp new file mode 100644 index 0000000..a71c3ea --- /dev/null +++ b/rehlds/engine/buildnum.cpp @@ -0,0 +1,77 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +//TODO: use last commit date there +#ifdef REHLDS_FIXES +static char *date = __DATE__; +#else // REHLDS_FIXES +static char *date = "Aug 8 2013"; +#endif // REHLDS_FIXES + +static char *mon[12] = +{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +static char mond[12] = +{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + +int build_number(void) +{ + int m = 0; + int d = 0; + int y = 0; + static int b = 0; + + if (b != 0) + return b; + + for (m = 0; m < 11; m++) + { + if (Q_strnicmp(&date[0], mon[m], 3) == 0) + break; + d += mond[m]; + } + + d += Q_atoi(&date[4]) - 1; + y = Q_atoi(&date[7]) - 1900; + b = d + (int)((y - 1) * 365.25); + + if (((y % 4) == 0) && m > 1) + { + b += 1; + } + +#ifdef REHLDS_FIXES + b -= 41374; // return days since initial commit on Apr 12 2014 (Happy Cosmonautics Day!) +#else // REHLDS_FIXES + b -= 34995; // return days since Oct 24 1996 +#endif // REHLDS_FIXES + + return b; +} diff --git a/rehlds/engine/cdll_int.h b/rehlds/engine/cdll_int.h new file mode 100644 index 0000000..914779c --- /dev/null +++ b/rehlds/engine/cdll_int.h @@ -0,0 +1,465 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cdll_int.h +// +// 4-23-98 +// JOHN: client dll interface declarations +// +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "const.h" + + +// this file is included by both the engine and the client-dll, +// so make sure engine declarations aren't done twice + +typedef int HSPRITE_t; // handle to a graphic + +#define SCRINFO_SCREENFLASH 1 +#define SCRINFO_STRETCHED 2 + +typedef struct SCREENINFO_s +{ + int iSize; + int iWidth; + int iHeight; + int iFlags; + int iCharHeight; + short charWidths[256]; +} SCREENINFO; + + +typedef struct client_data_s +{ + // fields that cannot be modified (ie. have no effect if changed) + vec3_t origin; + + // fields that can be changed by the cldll + vec3_t viewangles; + int iWeaponBits; +// int iAccessoryBits; + float fov; // field of view +} client_data_t; + +typedef struct client_sprite_s +{ + char szName[64]; + char szSprite[64]; + int hspr; + int iRes; + wrect_t rc; +} client_sprite_t; + + + +typedef struct hud_player_info_s +{ + char *name; + short ping; + byte thisplayer; // TRUE if this is the calling player + + byte spectator; + byte packetloss; + + char *model; + short topcolor; + short bottomcolor; + + uint64_t m_nSteamID; +} hud_player_info_t; + + + +typedef struct module_s +{ + unsigned char ucMD5Hash[16]; // hash over code + qboolean fLoaded; // true if successfully loaded +} module_t; + + + +#ifndef IN_BUTTONS_H +#include "in_buttons.h" +#endif + +#define CLDLL_INTERFACE_VERSION 7 + +extern void LoadSecurityModuleFromDisk(char * pszDllName); +extern void LoadSecurityModuleFromMemory( unsigned char * pCode, int nSize ); +extern void CloseSecurityModule(); + + +extern void ClientDLL_Init( void ); // from cdll_int.c +extern void ClientDLL_Shutdown( void ); +extern void ClientDLL_HudInit( void ); +extern void ClientDLL_HudVidInit( void ); +extern void ClientDLL_UpdateClientData( void ); +extern void ClientDLL_Frame( double time ); +extern void ClientDLL_HudRedraw( int intermission ); +extern void ClientDLL_MoveClient( struct playermove_s *ppmove ); +extern void ClientDLL_ClientMoveInit( struct playermove_s *ppmove ); +extern char ClientDLL_ClientTextureType( char *name ); + +extern void ClientDLL_CreateMove( float frametime, struct usercmd_s *cmd, int active ); +extern void ClientDLL_ActivateMouse( void ); +extern void ClientDLL_DeactivateMouse( void ); +extern void ClientDLL_MouseEvent( int mstate ); +extern void ClientDLL_ClearStates( void ); +extern int ClientDLL_IsThirdPerson( void ); +extern void ClientDLL_GetCameraOffsets( float *ofs ); +extern int ClientDLL_GraphKeyDown( void ); +extern struct kbutton_s *ClientDLL_FindKey( const char *name ); +extern void ClientDLL_CAM_Think( void ); +extern void ClientDLL_IN_Accumulate( void ); +extern void ClientDLL_CalcRefdef( struct ref_params_s *pparams ); +extern int ClientDLL_AddEntity( int type, struct cl_entity_s *ent ); +extern void ClientDLL_CreateEntities( void ); + +extern void ClientDLL_DrawNormalTriangles( void ); +extern void ClientDLL_DrawTransparentTriangles( void ); +extern void ClientDLL_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); +extern void ClientDLL_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); +extern void ClientDLL_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); +extern void ClientDLL_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); +extern void ClientDLL_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ); +extern void ClientDLL_ReadDemoBuffer( int size, unsigned char *buffer ); +extern int ClientDLL_ConnectionlessPacket( const struct netadr_s *net_from_, const char *args, char *response_buffer, int *response_buffer_size ); +extern int ClientDLL_GetHullBounds( int hullnumber, float *mins, float *maxs ); + +extern void ClientDLL_VGui_ConsolePrint(const char* text); + +extern int ClientDLL_Key_Event( int down, int keynum, const char *pszCurrentBinding ); +extern void ClientDLL_TempEntUpdate( double ft, double ct, double grav, struct tempent_s **ppFreeTE, struct tempent_s **ppActiveTE, int ( *addTEntity )( struct cl_entity_s *pEntity ), void ( *playTESound )( struct tempent_s *pTemp, float damp ) ); +extern struct cl_entity_s *ClientDLL_GetUserEntity( int index ); +extern void ClientDLL_VoiceStatus(int entindex, qboolean bTalking); +extern void ClientDLL_DirectorMessage( int iSize, void *pbuf ); +extern void ClientDLL_ChatInputPosition( int *x, int *y ); + +//#include "server.h" // server_static_t define for apiproxy +#include "APIProxy.h" + +extern cldll_func_t cl_funcs; +extern cl_enginefunc_t cl_engsrcProxies; + +#ifdef HOOK_ENGINE +#define g_engdstAddrs (*pg_engdstAddrs) +#define g_module (*pg_module) +#endif + +extern cl_enginefunc_dst_t g_engdstAddrs; +extern module_t g_module; + + +// Module exports +extern modfuncs_t g_modfuncs; + + +// Macros for exported engine funcs +#define RecEngSPR_Load(a) (g_engdstAddrs.pfnSPR_Load(&a)) +#define RecEngSPR_Frames(a) (g_engdstAddrs.pfnSPR_Frames(&a)) +#define RecEngSPR_Height(a, b) (g_engdstAddrs.pfnSPR_Height(&a, &b)) +#define RecEngSPR_Width(a, b) (g_engdstAddrs.pfnSPR_Width(&a, &b)) +#define RecEngSPR_Set(a, b, c, d) (g_engdstAddrs.pfnSPR_Set(&a, &b, &c, &d)) +#define RecEngSPR_Draw(a, b, c, d) (g_engdstAddrs.pfnSPR_Draw(&a, &b, &c, &d)) +#define RecEngSPR_DrawHoles(a, b, c, d) (g_engdstAddrs.pfnSPR_DrawHoles(&a, &b, &c, &d)) +#define RecEngSPR_DrawAdditive(a, b, c, d) (g_engdstAddrs.pfnSPR_DrawAdditive(&a, &b, &c, &d)) +#define RecEngSPR_EnableScissor(a, b, c, d) (g_engdstAddrs.pfnSPR_EnableScissor(&a, &b, &c, &d)) +#define RecEngSPR_DisableScissor() (g_engdstAddrs.pfnSPR_DisableScissor()) +#define RecEngSPR_GetList(a, b) (g_engdstAddrs.pfnSPR_GetList(&a, &b)) +#define RecEngDraw_FillRGBA(a, b, c, d, e, f, g, h) (g_engdstAddrs.pfnFillRGBA(&a, &b, &c, &d, &e, &f, &g, &h)) +#define RecEnghudGetScreenInfo(a) (g_engdstAddrs.pfnGetScreenInfo(&a)) +#define RecEngSetCrosshair(a, b, c, d, e) (g_engdstAddrs.pfnSetCrosshair(&a, &b, &c, &d, &e)) +#define RecEnghudRegisterVariable(a, b, c) (g_engdstAddrs.pfnRegisterVariable(&a, &b, &c)) +#define RecEnghudGetCvarFloat(a) (g_engdstAddrs.pfnGetCvarFloat(&a)) +#define RecEnghudGetCvarString(a) (g_engdstAddrs.pfnGetCvarString(&a)) +#define RecEnghudAddCommand(a, b) (g_engdstAddrs.pfnAddCommand(&a, &b)) +#define RecEnghudHookUserMsg(a, b) (g_engdstAddrs.pfnHookUserMsg(&a, &b)) +#define RecEnghudServerCmd(a) (g_engdstAddrs.pfnServerCmd(&a)) +#define RecEnghudClientCmd(a) (g_engdstAddrs.pfnClientCmd(&a)) +#define RecEngPrimeMusicStream(a, b) (g_engdstAddrs.pfnPrimeMusicStream(&a, &b)) +#define RecEnghudGetPlayerInfo(a, b) (g_engdstAddrs.pfnGetPlayerInfo(&a, &b)) +#define RecEnghudPlaySoundByName(a, b) (g_engdstAddrs.pfnPlaySoundByName(&a, &b)) +#define RecEnghudPlaySoundByNameAtPitch(a, b, c) (g_engdstAddrs.pfnPlaySoundByNameAtPitch(&a, &b, &c)) +#define RecEnghudPlaySoundVoiceByName(a, b) (g_engdstAddrs.pfnPlaySoundVoiceByName(&a, &b)) +#define RecEnghudPlaySoundByIndex(a, b) (g_engdstAddrs.pfnPlaySoundByIndex(&a, &b)) +#define RecEngAngleVectors(a, b, c, d) (g_engdstAddrs.pfnAngleVectors(&a, &b, &c, &d)) +#define RecEngTextMessageGet(a) (g_engdstAddrs.pfnTextMessageGet(&a)) +#define RecEngTextMessageDrawCharacter(a, b, c, d, e, f) (g_engdstAddrs.pfnDrawCharacter(&a, &b, &c, &d, &e, &f)) +#define RecEngDrawConsoleString(a, b, c) (g_engdstAddrs.pfnDrawConsoleString(&a, &b, &c)) +#define RecEngDrawSetTextColor(a, b, c) (g_engdstAddrs.pfnDrawSetTextColor(&a, &b, &c)) +#define RecEnghudDrawConsoleStringLen(a, b, c) (g_engdstAddrs.pfnDrawConsoleStringLen(&a, &b, &c)) +#define RecEnghudConsolePrint(a) (g_engdstAddrs.pfnConsolePrint(&a)) +#define RecEnghudCenterPrint(a) (g_engdstAddrs.pfnCenterPrint(&a)) +#define RecEnghudCenterX() (g_engdstAddrs.GetWindowCenterX()) +#define RecEnghudCenterY() (g_engdstAddrs.GetWindowCenterY()) +#define RecEnghudGetViewAngles(a) (g_engdstAddrs.GetViewAngles(&a)) +#define RecEnghudSetViewAngles(a) (g_engdstAddrs.SetViewAngles(&a)) +#define RecEnghudGetMaxClients() (g_engdstAddrs.GetMaxClients()) +#define RecEngCvar_SetValue(a, b) (g_engdstAddrs.Cvar_SetValue(&a, &b)) +#define RecEngCmd_Argc() (g_engdstAddrs.Cmd_Argc()) +#define RecEngCmd_Argv(a) (g_engdstAddrs.Cmd_Argv(&a)) +#define RecEngCon_Printf(a) (g_engdstAddrs.Con_Printf(&a)) +#define RecEngCon_DPrintf(a) (g_engdstAddrs.Con_DPrintf(&a)) +#define RecEngCon_NPrintf(a, b) (g_engdstAddrs.Con_NPrintf(&a, &b)) +#define RecEngCon_NXPrintf(a, b) (g_engdstAddrs.Con_NXPrintf(&a, &b)) +#define RecEnghudPhysInfo_ValueForKey(a) (g_engdstAddrs.PhysInfo_ValueForKey(&a)) +#define RecEnghudServerInfo_ValueForKey(a) (g_engdstAddrs.ServerInfo_ValueForKey(&a)) +#define RecEnghudGetClientMaxspeed() (g_engdstAddrs.GetClientMaxspeed()) +#define RecEnghudCheckParm(a, b) (g_engdstAddrs.CheckParm(&a, &b)) +#define RecEngKey_Event(a, b) (g_engdstAddrs.Key_Event(&a, &b)) +#define RecEnghudGetMousePosition(a, b) (g_engdstAddrs.GetMousePosition(&a, &b)) +#define RecEnghudIsNoClipping() (g_engdstAddrs.IsNoClipping()) +#define RecEnghudGetLocalPlayer() (g_engdstAddrs.GetLocalPlayer()) +#define RecEnghudGetViewModel() (g_engdstAddrs.GetViewModel()) +#define RecEnghudGetEntityByIndex(a) (g_engdstAddrs.GetEntityByIndex(&a)) +#define RecEnghudGetClientTime() (g_engdstAddrs.GetClientTime()) +#define RecEngV_CalcShake() (g_engdstAddrs.V_CalcShake()) +#define RecEngV_ApplyShake(a, b, c) (g_engdstAddrs.V_ApplyShake(&a, &b, &c)) +#define RecEngPM_PointContents(a, b) (g_engdstAddrs.PM_PointContents(&a, &b)) +#define RecEngPM_WaterEntity(a) (g_engdstAddrs.PM_WaterEntity(&a)) +#define RecEngPM_TraceLine(a, b, c, d, e) (g_engdstAddrs.PM_TraceLine(&a, &b, &c, &d, &e)) +#define RecEngCL_LoadModel(a, b) (g_engdstAddrs.CL_LoadModel(&a, &b)) +#define RecEngCL_CreateVisibleEntity(a, b) (g_engdstAddrs.CL_CreateVisibleEntity(&a, &b)) +#define RecEnghudGetSpritePointer(a) (g_engdstAddrs.GetSpritePointer(&a)) +#define RecEnghudPlaySoundByNameAtLocation(a, b, c) (g_engdstAddrs.pfnPlaySoundByNameAtLocation(&a, &b, &c)) +#define RecEnghudPrecacheEvent(a, b) (g_engdstAddrs.pfnPrecacheEvent(&a, &b)) +#define RecEnghudPlaybackEvent(a, b, c, d, e, f, g, h, i, j, k, l) (g_engdstAddrs.pfnPlaybackEvent(&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l)) +#define RecEnghudWeaponAnim(a, b) (g_engdstAddrs.pfnWeaponAnim(&a, &b)) +#define RecEngRandomFloat(a, b) (g_engdstAddrs.pfnRandomFloat(&a, &b)) +#define RecEngRandomLong(a, b) (g_engdstAddrs.pfnRandomLong(&a, &b)) +#define RecEngCL_HookEvent(a, b) (g_engdstAddrs.pfnHookEvent(&a, &b)) +#define RecEngCon_IsVisible() (g_engdstAddrs.Con_IsVisible()) +#define RecEnghudGetGameDir() (g_engdstAddrs.pfnGetGameDirectory()) +#define RecEngCvar_FindVar(a) (g_engdstAddrs.pfnGetCvarPointer(&a)) +#define RecEngKey_NameForBinding(a) (g_engdstAddrs.Key_LookupBinding(&a)) +#define RecEnghudGetLevelName() (g_engdstAddrs.pfnGetLevelName()) +#define RecEnghudGetScreenFade(a) (g_engdstAddrs.pfnGetScreenFade(&a)) +#define RecEnghudSetScreenFade(a) (g_engdstAddrs.pfnSetScreenFade(&a)) +#define RecEngVGuiWrap_GetPanel() (g_engdstAddrs.VGui_GetPanel()) +#define RecEngVGui_ViewportPaintBackground(a) (g_engdstAddrs.VGui_ViewportPaintBackground(&a)) +#define RecEngCOM_LoadFile(a, b, c) (g_engdstAddrs.COM_LoadFile(&a, &b, &c)) +#define RecEngCOM_ParseFile(a, b) (g_engdstAddrs.COM_ParseFile(&a, &b)) +#define RecEngCOM_FreeFile(a) (g_engdstAddrs.COM_FreeFile(&a)) +#define RecEngCL_IsSpectateOnly() (g_engdstAddrs.IsSpectateOnly()) +#define RecEngR_LoadMapSprite(a) (g_engdstAddrs.LoadMapSprite(&a)) +#define RecEngCOM_AddAppDirectoryToSearchPath(a, b) (g_engdstAddrs.COM_AddAppDirectoryToSearchPath(&a, &b)) +#define RecEngClientDLL_ExpandFileName(a, b, c) (g_engdstAddrs.COM_ExpandFilename(&a, &b, &c)) +#define RecEngPlayerInfo_ValueForKey(a, b) (g_engdstAddrs.PlayerInfo_ValueForKey(&a, &b)) +#define RecEngPlayerInfo_SetValueForKey(a, b) (g_engdstAddrs.PlayerInfo_SetValueForKey(&a, &b)) +#define RecEngGetPlayerUniqueID(a, b) (g_engdstAddrs.GetPlayerUniqueID(&a, &b)) +#define RecEngGetTrackerIDForPlayer(a) (g_engdstAddrs.GetTrackerIDForPlayer(&a)) +#define RecEngGetPlayerForTrackerID(a) (g_engdstAddrs.GetPlayerForTrackerID(&a)) +#define RecEnghudServerCmdUnreliable(a) (g_engdstAddrs.pfnServerCmdUnreliable(&a)) +#define RecEngGetMousePos(a) (g_engdstAddrs.pfnGetMousePos(&a)) +#define RecEngSetMousePos(a, b) (g_engdstAddrs.pfnSetMousePos(&a, &b)) +#define RecEngSetMouseEnable(a) (g_engdstAddrs.pfnSetMouseEnable(&a)) +#define RecEngSetFilterMode(a) (g_engdstAddrs.pfnSetFilterMode(&a)) +#define RecEngSetFilterColor(a,b,c) (g_engdstAddrs.pfnSetFilterColor(&a,&b,&c)) +#define RecEngSetFilterBrightness(a) (g_engdstAddrs.pfnSetFilterBrightness(&a)) +#define RecEngSequenceGet(a,b) (g_engdstAddrs.pfnSequenceGet(&a,&b)) +#define RecEngSPR_DrawGeneric(a,b,c,d,e,f,g,h) (g_engdstAddrs.pfnSPR_DrawGeneric(&a, &b, &c, &d, &e, &f, &g, &h)) +#define RecEngSequencePickSentence(a,b,c) (g_engdstAddrs.pfnSequencePickSentence(&a, &b, &c)) +#define RecEngLocalPlayerInfo_ValueForKey(a) (g_engdstAddrs.LocalPlayerInfo_ValueForKey(&a)) +#define RecEngProcessTutorMessageDecayBuffer(a, b) (g_engdstAddrs.pfnProcessTutorMessageDecayBuffer(&a, &b)) +#define RecEngConstructTutorMessageDecayBuffer(a, b) (g_engdstAddrs.pfnConstructTutorMessageDecayBuffer(&a, &b)) +#define RecEngResetTutorMessageDecayBuffer() (g_engdstAddrs.pfnResetTutorMessageDecayBuffer()) +#define RecEngDraw_FillRGBABlend(a, b, c, d, e, f, g, h) (g_engdstAddrs.pfnFillRGBABlend(&a, &b, &c, &d, &e, &f, &g, &h)) + +// Dummy destination function for use when there's no security module +extern void NullDst(void); + +// Use this to init an engdst structure to point to NullDst +#define k_engdstNull \ +{ \ + (pfnEngDst_pfnSPR_Load_t) NullDst, \ + (pfnEngDst_pfnSPR_Frames_t) NullDst, \ + (pfnEngDst_pfnSPR_Height_t) NullDst, \ + (pfnEngDst_pfnSPR_Width_t) NullDst, \ + (pfnEngDst_pfnSPR_Set_t) NullDst, \ + (pfnEngDst_pfnSPR_Draw_t) NullDst, \ + (pfnEngDst_pfnSPR_DrawHoles_t) NullDst, \ + (pfnEngDst_pfnSPR_DrawAdditive_t) NullDst, \ + (pfnEngDst_pfnSPR_EnableScissor_t) NullDst, \ + (pfnEngDst_pfnSPR_DisableScissor_t) NullDst, \ + (pfnEngDst_pfnSPR_GetList_t) NullDst, \ + (pfnEngDst_pfnFillRGBA_t) NullDst, \ + (pfnEngDst_pfnGetScreenInfo_t) NullDst, \ + (pfnEngDst_pfnSetCrosshair_t) NullDst, \ + (pfnEngDst_pfnRegisterVariable_t) NullDst, \ + (pfnEngDst_pfnGetCvarFloat_t) NullDst, \ + (pfnEngDst_pfnGetCvarString_t) NullDst, \ + (pfnEngDst_pfnAddCommand_t) NullDst, \ + (pfnEngDst_pfnHookUserMsg_t) NullDst, \ + (pfnEngDst_pfnServerCmd_t) NullDst, \ + (pfnEngDst_pfnClientCmd_t) NullDst, \ + (pfnEngDst_pfnGetPlayerInfo_t) NullDst, \ + (pfnEngDst_pfnPlaySoundByName_t) NullDst, \ + (pfnEngDst_pfnPlaySoundByIndex_t) NullDst, \ + (pfnEngDst_pfnAngleVectors_t) NullDst, \ + (pfnEngDst_pfnTextMessageGet_t) NullDst, \ + (pfnEngDst_pfnDrawCharacter_t) NullDst, \ + (pfnEngDst_pfnDrawConsoleString_t) NullDst, \ + (pfnEngDst_pfnDrawSetTextColor_t) NullDst, \ + (pfnEngDst_pfnDrawConsoleStringLen_t) NullDst, \ + (pfnEngDst_pfnConsolePrint_t) NullDst, \ + (pfnEngDst_pfnCenterPrint_t) NullDst, \ + (pfnEngDst_GetWindowCenterX_t) NullDst, \ + (pfnEngDst_GetWindowCenterY_t) NullDst, \ + (pfnEngDst_GetViewAngles_t) NullDst, \ + (pfnEngDst_SetViewAngles_t) NullDst, \ + (pfnEngDst_GetMaxClients_t) NullDst, \ + (pfnEngDst_Cvar_SetValue_t) NullDst, \ + (pfnEngDst_Cmd_Argc_t) NullDst, \ + (pfnEngDst_Cmd_Argv_t) NullDst, \ + (pfnEngDst_Con_Printf_t) NullDst, \ + (pfnEngDst_Con_DPrintf_t) NullDst, \ + (pfnEngDst_Con_NPrintf_t) NullDst, \ + (pfnEngDst_Con_NXPrintf_t) NullDst, \ + (pfnEngDst_PhysInfo_ValueForKey_t) NullDst, \ + (pfnEngDst_ServerInfo_ValueForKey_t) NullDst, \ + (pfnEngDst_GetClientMaxspeed_t) NullDst, \ + (pfnEngDst_CheckParm_t) NullDst, \ + (pfnEngDst_Key_Event_t) NullDst, \ + (pfnEngDst_GetMousePosition_t) NullDst, \ + (pfnEngDst_IsNoClipping_t) NullDst, \ + (pfnEngDst_GetLocalPlayer_t) NullDst, \ + (pfnEngDst_GetViewModel_t) NullDst, \ + (pfnEngDst_GetEntityByIndex_t) NullDst, \ + (pfnEngDst_GetClientTime_t) NullDst, \ + (pfnEngDst_V_CalcShake_t) NullDst, \ + (pfnEngDst_V_ApplyShake_t) NullDst, \ + (pfnEngDst_PM_PointContents_t) NullDst, \ + (pfnEngDst_PM_WaterEntity_t) NullDst, \ + (pfnEngDst_PM_TraceLine_t) NullDst, \ + (pfnEngDst_CL_LoadModel_t) NullDst, \ + (pfnEngDst_CL_CreateVisibleEntity_t) NullDst, \ + (pfnEngDst_GetSpritePointer_t) NullDst, \ + (pfnEngDst_pfnPlaySoundByNameAtLocation_t) NullDst, \ + (pfnEngDst_pfnPrecacheEvent_t) NullDst, \ + (pfnEngDst_pfnPlaybackEvent_t) NullDst, \ + (pfnEngDst_pfnWeaponAnim_t) NullDst, \ + (pfnEngDst_pfnRandomFloat_t) NullDst, \ + (pfnEngDst_pfnRandomLong_t) NullDst, \ + (pfnEngDst_pfnHookEvent_t) NullDst, \ + (pfnEngDst_Con_IsVisible_t) NullDst, \ + (pfnEngDst_pfnGetGameDirectory_t) NullDst, \ + (pfnEngDst_pfnGetCvarPointer_t) NullDst, \ + (pfnEngDst_Key_LookupBinding_t) NullDst, \ + (pfnEngDst_pfnGetLevelName_t) NullDst, \ + (pfnEngDst_pfnGetScreenFade_t) NullDst, \ + (pfnEngDst_pfnSetScreenFade_t) NullDst, \ + (pfnEngDst_VGui_GetPanel_t) NullDst, \ + (pfnEngDst_VGui_ViewportPaintBackground_t) NullDst, \ + (pfnEngDst_COM_LoadFile_t) NullDst, \ + (pfnEngDst_COM_ParseFile_t) NullDst, \ + (pfnEngDst_COM_FreeFile_t) NullDst, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + (pfnEngDst_IsSpectateOnly_t) NullDst, \ + (pfnEngDst_LoadMapSprite_t) NullDst, \ + (pfnEngDst_COM_AddAppDirectoryToSearchPath_t) NullDst, \ + (pfnEngDst_COM_ExpandFilename_t) NullDst, \ + (pfnEngDst_PlayerInfo_ValueForKey_t) NullDst, \ + (pfnEngDst_PlayerInfo_SetValueForKey_t) NullDst, \ + (pfnEngDst_GetPlayerUniqueID_t) NullDst, \ + (pfnEngDst_GetTrackerIDForPlayer_t) NullDst, \ + (pfnEngDst_GetPlayerForTrackerID_t) NullDst, \ + (pfnEngDst_pfnServerCmdUnreliable_t) NullDst, \ + (pfnEngDst_GetMousePos_t) NullDst, \ + (pfnEngDst_SetMousePos_t) NullDst, \ + (pfnEngDst_SetMouseEnable_t) NullDst, \ + (pfnEngDst_pfnSetFilterMode_t) NullDst, \ + (pfnEngDst_pfnSetFilterColor_t) NullDst, \ + (pfnEngDst_pfnSetFilterBrightness_t) NullDst, \ + (pfnEngDst_pfnSequenceGet_t) NullDst, \ + (pfnEngDst_pfnSPR_DrawGeneric_t) NullDst, \ + (pfnEngDst_pfnSequencePickSentence_t) NullDst, \ + (pfnEngDst_pfnDrawString_t) NullDst, \ + (pfnEngDst_pfnDrawStringReverse_t) NullDst, \ + (pfnEngDst_LocalPlayerInfo_ValueForKey_t) NullDst, \ + (pfnEngDst_pfnVGUI2DrawCharacter_t) NullDst, \ + (pfnEngDst_pfnVGUI2DrawCharacterAdd_t) NullDst, \ + (pfnEngDst_pfnPlaySoundVoiceByName_t) NullDst, \ + (pfnEngDst_pfnPrimeMusicStream_t) NullDst, \ + (pfnEngDst_pfnProcessTutorMessageDecayBuffer_t) NullDst, \ + (pfnEngDst_pfnConstructTutorMessageDecayBuffer_t) NullDst, \ + (pfnEngDst_pfnResetTutorMessageDecayData_t) NullDst, \ + (pfnEngDst_pfnPlaySoundByNameAtPitch_t) NullDst, \ + (pfnEngDst_pfnFillRGBABlend_t) NullDst, \ + (pfnEngDst_pfnGetAppID_t) NullDst, \ + (pfnEngDst_pfnGetAliases_t) NullDst, \ + (pfnEngDst_pfnVguiWrap2_GetMouseDelta_t) NullDst, \ +}; + +// Use this to init a cldll_func_dst structure to point to NullDst +#define k_cldstNull \ +{ \ + (DST_INITIALIZE_FUNC) NullDst, \ + (DST_HUD_INIT_FUNC) NullDst, \ + (DST_HUD_VIDINIT_FUNC) NullDst, \ + (DST_HUD_REDRAW_FUNC) NullDst, \ + (DST_HUD_UPDATECLIENTDATA_FUNC) NullDst, \ + (DST_HUD_RESET_FUNC) NullDst, \ + (DST_HUD_CLIENTMOVE_FUNC) NullDst, \ + (DST_HUD_CLIENTMOVEINIT_FUNC) NullDst, \ + (DST_HUD_TEXTURETYPE_FUNC) NullDst, \ + (DST_HUD_IN_ACTIVATEMOUSE_FUNC) NullDst, \ + (DST_HUD_IN_DEACTIVATEMOUSE_FUNC) NullDst, \ + (DST_HUD_IN_MOUSEEVENT_FUNC) NullDst, \ + (DST_HUD_IN_CLEARSTATES_FUNC) NullDst, \ + (DST_HUD_IN_ACCUMULATE_FUNC) NullDst, \ + (DST_HUD_CL_CREATEMOVE_FUNC) NullDst, \ + (DST_HUD_CL_ISTHIRDPERSON_FUNC) NullDst, \ + (DST_HUD_CL_GETCAMERAOFFSETS_FUNC) NullDst, \ + (DST_HUD_KB_FIND_FUNC) NullDst, \ + (DST_HUD_CAMTHINK_FUNC) NullDst, \ + (DST_HUD_CALCREF_FUNC) NullDst, \ + (DST_HUD_ADDENTITY_FUNC) NullDst, \ + (DST_HUD_CREATEENTITIES_FUNC) NullDst, \ + (DST_HUD_DRAWNORMALTRIS_FUNC) NullDst, \ + (DST_HUD_DRAWTRANSTRIS_FUNC) NullDst, \ + (DST_HUD_STUDIOEVENT_FUNC) NullDst, \ + (DST_HUD_POSTRUNCMD_FUNC) NullDst, \ + (DST_HUD_SHUTDOWN_FUNC) NullDst, \ + (DST_HUD_TXFERLOCALOVERRIDES_FUNC) NullDst, \ + (DST_HUD_PROCESSPLAYERSTATE_FUNC) NullDst, \ + (DST_HUD_TXFERPREDICTIONDATA_FUNC) NullDst, \ + (DST_HUD_DEMOREAD_FUNC) NullDst, \ + (DST_HUD_CONNECTIONLESS_FUNC) NullDst, \ + (DST_HUD_GETHULLBOUNDS_FUNC) NullDst, \ + (DST_HUD_FRAME_FUNC) NullDst, \ + (DST_HUD_KEY_EVENT_FUNC) NullDst, \ + (DST_HUD_TEMPENTUPDATE_FUNC) NullDst, \ + (DST_HUD_GETUSERENTITY_FUNC) NullDst, \ + (DST_HUD_VOICESTATUS_FUNC) NullDst, \ + (DST_HUD_DIRECTORMESSAGE_FUNC) NullDst, \ + (DST_HUD_STUDIO_INTERFACE_FUNC) NullDst, \ + (DST_HUD_CHATINPUTPOSITION_FUNC) NullDst, \ + (DST_HUD_GETPLAYERTEAM) NullDst, \ +} + +#ifdef __cplusplus +} +#endif + diff --git a/rehlds/engine/cl_null.cpp b/rehlds/engine/cl_null.cpp new file mode 100644 index 0000000..0ca80ee --- /dev/null +++ b/rehlds/engine/cl_null.cpp @@ -0,0 +1,233 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +client_static_t g_pcls; +client_state_t g_pcl; +keydest_t key_dest; + +playermove_t g_clmove; +qboolean cl_inmovie; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t cl_name = { "name", "0", FCVAR_ARCHIVE | FCVAR_USERINFO, 0.0f, NULL }; +cvar_t rate_ = { "rate", "30000", FCVAR_USERINFO, 0.0f, NULL }; +cvar_t console = { "console", "1.0", FCVAR_ARCHIVE, 0.0f, NULL }; + +#else //HOOK_ENGINE + +cvar_t cl_name; +cvar_t rate_; +cvar_t console; + +#endif //HOOK_ENGINE + +/* <1c38b> ../engine/cl_null.c:18 */ +void CL_RecordHUDCommand(char *cmdname) { } + +/* <1c3b2> ../engine/cl_null.c:19 */ +void R_DecalRemoveAll(int textureIndex) { } + +/* <1c3d9> ../engine/cl_null.c:20 */ +void CL_CheckForResend(void) { } + +/* <1c3ed> ../engine/cl_null.c:21 */ +qboolean CL_CheckFile(sizebuf_t *msg, char *filename) { return 1; } + +/* <1c42c> ../engine/cl_null.c:22 */ +void CL_ClearClientState(void) { } + +/* <1c440> ../engine/cl_null.c:23 */ +void CL_Connect_f(void) { } + +/* <1c454> ../engine/cl_null.c:24 */ +void CL_DecayLights(void) { } + +/* <1c468> ../engine/cl_null.c:25 */ +void CL_Disconnect(void) { } + +/* <1c47c> ../engine/cl_null.c:26 */ +void CL_Disconnect_f(void) { } + +/* <1c490> ../engine/cl_null.c:27 */ +void CL_EmitEntities(void) { } + +/* <1c4a4> ../engine/cl_null.c:28 */ +void CL_InitClosest(void) { } + +/* <1c4b7> ../engine/cl_null.c:29 */ +void CL_Init(void) { } + +/* <1c4cb> ../engine/cl_null.c:30 */ +void CL_Particle(vec_t *origin, int color, float life, int zpos, int zvel) { } + +/* <1c530> ../engine/cl_null.c:31 */ +void CL_PredictMove(qboolean repredicting) { } + +/* <1c557> ../engine/cl_null.c:32 */ +void CL_PrintLogos(void) { } + +/* <1c56b> ../engine/cl_null.c:33 */ +void CL_ReadPackets(void) { } + +/* <1c57f> ../engine/cl_null.c:34 */ +qboolean CL_RequestMissingResources(void) { return 0; } + +/* <1c597> ../engine/cl_null.c:35 */ +void CL_Move(void) { } + +/* <1c5ab> ../engine/cl_null.c:36 */ +void CL_SendConnectPacket(void) { } + +/* <1c5bf> ../engine/cl_null.c:38 */ +void CL_StopPlayback(void) { } + +/* <1c5d3> ../engine/cl_null.c:39 */ +void CL_UpdateSoundFade(void) { } + +/* <1c5e7> ../engine/cl_null.c:40 */ +void CL_AdjustClock(void) { } + +void CL_HudMessage(const char *pMessage) { } +int Key_CountBindings(void) { return 0; } + +/* <1c5fb> ../engine/cl_null.c:43 */ +void Key_WriteBindings(FileHandle_t f) { } + +/* <1c620> ../engine/cl_null.c:44 */ +extern "C" void ClientDLL_UpdateClientData(void) { } + +/* <1c634> ../engine/cl_null.c:45 */ +extern "C" void ClientDLL_HudVidInit(void) { } + +/* <1c648> ../engine/cl_null.c:46 */ +void Chase_Init(void) { } + +/* <1c65c> ../engine/cl_null.c:47 */ +void Key_Init(void) { } + +/* <1c670> ../engine/cl_null.c:48 */ +extern "C" void ClientDLL_Init(void) { } +extern "C" void ClientDLL_Shutdown(void) { } + +/* <1c684> ../engine/cl_null.c:49 */ +void Con_Shutdown(void) { } + +/* <1c698> ../engine/cl_null.c:50 */ +int DispatchDirectUserMsg(const char *pszName, int iSize, void *pBuf) { return 0; } + +/* <1c6df> ../engine/cl_null.c:51 */ +void CL_ShutDownUsrMessages(void) { } + +/* <1c6f3> ../engine/cl_null.c:52 */ +void CL_ShutDownClientStatic(void) { } + +/* <1c707> ../engine/cl_null.c:54 */ +void ClientDLL_MoveClient(struct playermove_s *pmove) { } + +void ClientDLL_DeactivateMouse(void) { } +void ClientDLL_MouseEvent(int mstate) { } + +/* <1c73a> ../engine/cl_null.c:56 */ +void CL_Shutdown(void) { } + +/* <1c74e> ../engine/cl_null.c:58 */ +extern "C" void ClientDLL_Frame(double time) { } + +/* <1c775> ../engine/cl_null.c:59 */ +extern "C" void ClientDLL_CAM_Think(void) { } + +/* <1c788> ../engine/cl_null.c:60 */ +void CL_InitEventSystem(void) { } + +/* <1c79b> ../engine/cl_null.c:61 */ +void CL_CheckClientState(void) { } + +/* <1c7af> ../engine/cl_null.c:62 */ +void CL_RedoPrediction(void) { } + +/* <1c7c3> ../engine/cl_null.c:63 */ +void CL_SetLastUpdate(void) { } + +/* <1c7d7> ../engine/cl_null.c:65 */ +void Con_NPrintf(int idx, const char *fmt, ...) { } +void Sequence_OnLevelLoad( const char* mapName ) { } + +/* <1c80d> ../engine/cl_null.c:69 */ +void CL_WriteMessageHistory(int starting_count, int cmd) { } + +/* <1c842> ../engine/cl_null.c:71 */ +void CL_MoveSpectatorCamera(void) { } + +/* <1c856> ../engine/cl_null.c:72 */ +void CL_AddVoiceToDatagram(qboolean bFinal) { } + +/* <1c87d> ../engine/cl_null.c:73 */ +void CL_VoiceIdle(void) { } + +/* <1c891> ../engine/cl_null.c:75 */ +void PollDInputDevices(void) { } + +/* <1c8a4> ../engine/cl_null.c:77 */ +void CL_KeepConnectionActive(void) { } + +/* <1c8b8> ../engine/cl_null.c:79 */ +void CL_UpdateModuleC(void) { } + +/* <1c8cc> ../engine/cl_null.c:81 */ +int VGuiWrap2_IsInCareerMatch(void) { return 0; } + +/* <1c8e3> ../engine/cl_null.c:83 */ +void VguiWrap2_GetCareerUI(void) { } + +/* <1c8f6> ../engine/cl_null.c:85 */ +int VGuiWrap2_GetLocalizedStringLength(const char *label) { return 0; } +void VGuiWrap2_LoadingStarted(const char *resourceType, const char *resourceName) {} + +/* <1c921> ../engine/cl_null.c:87 */ +void ConstructTutorMessageDecayBuffer(int *buffer, int bufferLength) { } + +/* <1c95c> ../engine/cl_null.c:88 */ +void ProcessTutorMessageDecayBuffer(int *buffer, int bufferLength) { } + +/* <1c991> ../engine/cl_null.c:89 */ +int GetTimesTutorMessageShown(int id) { return -1; } + +/* <1c9bb> ../engine/cl_null.c:90 */ +void RegisterTutorMessageShown(int mid) { } + +/* <1c9e2> ../engine/cl_null.c:91 */ +void ResetTutorMessageDecayData(void) { } + +/* <1c9f5> ../engine/cl_null.c:92 */ +void SetCareerAudioState(int state) { } diff --git a/rehlds/engine/client.h b/rehlds/engine/client.h new file mode 100644 index 0000000..dfba5f4 --- /dev/null +++ b/rehlds/engine/client.h @@ -0,0 +1,377 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef CLIENT_H +#define CLIENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "common.h" +#include "custom.h" +#include "cl_entity.h" +#include "consistency.h" +#include "delta_packet.h" +#include "dlight.h" +#include "entity_state.h" +#include "event.h" +#include "info.h" +#include "net.h" +#include "keys.h" +#include "sound.h" +#include "screenfade.h" +#include "usercmd.h" +#include "model.h" +#include "kbutton.h" + +#define MAX_SCOREBOARDNAME 32 +#define MAX_DEMOS 32 + +typedef enum cactive_e +{ + ca_dedicated, + ca_disconnected, + ca_connecting, + ca_connected, + ca_uninitialized, + ca_active, +} cactive_t; + +/* <1523b> ../engine/client.h:70 */ +typedef struct cmd_s +{ + usercmd_t cmd; + float senttime; + float receivedtime; + float frame_lerp; + qboolean processedfuncs; + qboolean heldback; + int sendsize; +} cmd_t; + +/* <152b1> ../engine/client.h:85 */ +typedef struct frame_s +{ + double receivedtime; + double latency; + qboolean invalid; + qboolean choked; + entity_state_t playerstate[32]; + double time; + clientdata_t clientdata; + weapon_data_t weapondata[64]; + packet_entities_t packet_entities; + uint16_t clientbytes; + uint16_t playerinfobytes; + uint16_t packetentitybytes; + uint16_t tentitybytes; + uint16_t soundbytes; + uint16_t eventbytes; + uint16_t usrbytes; + uint16_t voicebytes; + uint16_t msgbytes; +} frame_t; + +/* <153e9> ../engine/client.h:127 */ +typedef struct player_info_s +{ + int userid; + char userinfo[MAX_INFO_STRING]; + char name[MAX_SCOREBOARDNAME]; + int spectator; + int ping; + int packet_loss; + char model[MAX_QPATH]; + int topcolor; + int bottomcolor; + int renderframe; + int gaitsequence; + float gaitframe; + float gaityaw; + vec3_t prevgaitorigin; + customization_t customdata; + char hashedcdkey[16]; + uint64_t m_nSteamID; +} player_info_t; + +/* <277f5> ../engine/client.h:208 */ +typedef struct soundfade_s +{ + int nStartPercent; + int nClientSoundFadePercent; + double soundFadeStartTime; + int soundFadeOutTime; + int soundFadeHoldTime; + int soundFadeInTime; +} soundfade_t; + +/* <1f23> ../engine/client.h:223 */ +typedef struct client_static_s +{ + cactive_t state; + netchan_t netchan; + sizebuf_t datagram; + byte datagram_buf[4000]; + double connect_time; + int connect_retry; + int challenge; + byte authprotocol; + int userid; + char trueaddress[32]; + float slist_time; + int signon; + char servername[260]; + char mapstring[64]; + char spawnparms[2048]; + char userinfo[256]; + float nextcmdtime; + int lastoutgoingcommand; + int demonum; + char demos[MAX_DEMOS][16]; + qboolean demorecording; + qboolean demoplayback; + qboolean timedemo; + float demostarttime; + int demostartframe; + int forcetrack; + FileHandle_t demofile; + FileHandle_t demoheader; + qboolean demowaiting; + qboolean demoappending; + char demofilename[260]; + int demoframecount; + int td_lastframe; + int td_startframe; + float td_starttime; + incomingtransfer_t dl; + float packet_loss; + double packet_loss_recalc_time; + int playerbits; + soundfade_t soundfade; + char physinfo[256]; + unsigned char md5_clientdll[16]; + netadr_t game_stream; + netadr_t connect_stream; + qboolean passive; + qboolean spectator; + qboolean director; + qboolean fSecureClient; + qboolean isVAC2Secure; + uint64_t GameServerSteamID; + int build_num; +} client_static_t; + +/* <1bda4> ../engine/client.h:320 */ +typedef struct client_state_s +{ + int max_edicts; + resource_t resourcesonhand; + resource_t resourcesneeded; + resource_t resourcelist[1280]; + int num_resources; + qboolean need_force_consistency_response; + char serverinfo[512]; + int servercount; + int validsequence; + int parsecount; + int parsecountmod; + int stats[32]; + int weapons; + usercmd_t cmd; + vec3_t viewangles; + vec3_t punchangle; + vec3_t crosshairangle; + vec3_t simorg; + vec3_t simvel; + vec3_t simangles; + vec_t predicted_origins[64][3]; + vec3_t prediction_error; + float idealpitch; + vec3_t viewheight; + screenfade_t sf; + qboolean paused; + int onground; + int moving; + int waterlevel; + int usehull; + float maxspeed; + int pushmsec; + int light_level; + int intermission; + double mtime[2]; + double time; + double oldtime; + frame_t frames[64]; + cmd_t commands[64]; + local_state_t predicted_frames[64]; + int delta_sequence; + int playernum; + event_t event_precache[256]; + model_t *model_precache[512]; + int model_precache_count; + sfx_s *sound_precache[512]; + consistency_t consistency_list[512]; + int num_consistency; + int highentity; + char levelname[40]; + int maxclients; + int gametype; + int viewentity; + model_t *worldmodel; + efrag_t *free_efrags; + int num_entities; + int num_statics; + cl_entity_t viewent; + int cdtrack; + int looptrack; + CRC32_t serverCRC; + unsigned char clientdllmd5[16]; + float weaponstarttime; + int weaponsequence; + int fPrecaching; + dlight_t *pLight; + player_info_t players[32]; + entity_state_t instanced_baseline[64]; + int instanced_baseline_number; + CRC32_t mapCRC; + event_state_t events; + char downloadUrl[128]; +} client_state_t; + +/* <3a9c7> ../engine/client.h:645 */ +typedef enum CareerStateType_e +{ + CAREER_NONE = 0, + CAREER_LOADING = 1, + CAREER_PLAYING = 2, +} CareerStateType; + + +#ifdef HOOK_ENGINE +#define g_pcls (*pcls) +#define g_pcl (*pcl) +#define key_dest (*pkey_dest) + +#define g_clmove (*pg_clmove) +#define cl_inmovie (*pcl_inmovie) + +#define cl_name (*pcl_name) +#define rate_ (*prate) +#define console (*pconsole) +#endif // HOOK_ENGINE + +extern keydest_t key_dest; +extern client_static_t g_pcls; +extern client_state_t g_pcl; + +extern playermove_t g_clmove; +extern qboolean cl_inmovie; + +extern cvar_t cl_name; +extern cvar_t rate_; +extern cvar_t console; + +void CL_RecordHUDCommand(char *cmdname); +void R_DecalRemoveAll(int textureIndex); +void CL_CheckForResend(void); +qboolean CL_CheckFile(sizebuf_t *msg, char *filename); +void CL_ClearClientState(void); +void CL_Connect_f(void); +void CL_DecayLights(void); +void CL_Disconnect(void); +void CL_Disconnect_f(void); +void CL_EmitEntities(void); +void CL_InitClosest(void); +void CL_Init(void); +void CL_Particle(vec_t *origin, int color, float life, int zpos, int zvel); +void CL_PredictMove(qboolean repredicting); +void CL_PrintLogos(void); +void CL_ReadPackets(void); +qboolean CL_RequestMissingResources(void); +void CL_Move(void); +void CL_SendConnectPacket(void); +void CL_StopPlayback(void); +void CL_UpdateSoundFade(void); +void CL_AdjustClock(void); +void CL_Save(const char *name); +void CL_HudMessage(const char *pMessage); + +int Key_CountBindings(void); +void Key_WriteBindings(FileHandle_t f); +extern "C" void ClientDLL_UpdateClientData(void); +extern "C" void ClientDLL_HudVidInit(void); +void Chase_Init(void); +void Key_Init(void); +extern "C" void ClientDLL_Init(void); +void Con_Shutdown(void); +int DispatchDirectUserMsg(const char *pszName, int iSize, void *pBuf); +void CL_ShutDownUsrMessages(void); +void CL_ShutDownClientStatic(void); + +extern "C" void ClientDLL_MoveClient(struct playermove_s *ppmove); + +void CL_Shutdown(void); + +extern "C" void ClientDLL_Frame(double time); +extern "C" void ClientDLL_CAM_Think(void); +void CL_InitEventSystem(void); +void CL_CheckClientState(void); +void CL_RedoPrediction(void); +void CL_SetLastUpdate(void); + +void Con_NPrintf(int idx, const char *fmt, ...); + + +void CL_WriteMessageHistory(int starting_count, int cmd); + +void CL_MoveSpectatorCamera(void); +void CL_AddVoiceToDatagram(qboolean bFinal); +void CL_VoiceIdle(void); + +void PollDInputDevices(void); + +void CL_KeepConnectionActive(void); + +void CL_UpdateModuleC(void); + +int VGuiWrap2_IsInCareerMatch(void); + +void VguiWrap2_GetCareerUI(void); + +int VGuiWrap2_GetLocalizedStringLength(const char *label); +void VGuiWrap2_LoadingStarted(const char *resourceType, const char *resourceName); + +void ConstructTutorMessageDecayBuffer(int *buffer, int bufferLength); +void ProcessTutorMessageDecayBuffer(int *buffer, int bufferLength); +int GetTimesTutorMessageShown(int id); +void RegisterTutorMessageShown(int mid); +void ResetTutorMessageDecayData(void); +void SetCareerAudioState(int state); + +#endif // CLIENT_H diff --git a/rehlds/engine/cmd.cpp b/rehlds/engine/cmd.cpp new file mode 100644 index 0000000..09c39fb --- /dev/null +++ b/rehlds/engine/cmd.cpp @@ -0,0 +1,1165 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +int cmd_argc; +char *cmd_argv[80]; + +// Complete arguments string +char *cmd_args; + +sizebuf_t cmd_text; +cmd_source_t cmd_source; +qboolean cmd_wait; +cmdalias_t *cmd_alias; + +//int trashtest; +//int *trashspot; + +cmd_function_t *cmd_functions; +char *const cmd_null_string = ""; + + +/* <4aad> ../engine/cmd.c:47 */ +void Cmd_Wait_f(void) +{ + cmd_wait = 1; +} + +/* <4d6b> ../engine/cmd.c:69 */ +void Cbuf_Init(void) +{ + SZ_Alloc("cmd_text", &cmd_text, MAX_CMD_BUFFER); +} + +/* <4d80> ../engine/cmd.c:83 */ +// As new commands are generated from the console or keybindings, +// the text is added to the end of the command buffer. +void Cbuf_AddText(char *text) +{ + int len = Q_strlen(text); + + if (cmd_text.cursize + len >= cmd_text.maxsize) + { + Con_Printf(__FUNCTION__ ": overflow\n"); + return; + } + + SZ_Write(&cmd_text, text, len); +} + +/* <4dcf> ../engine/cmd.c:109 */ +// When a command wants to issue other commands immediately, the text is +// inserted at the beginning of the buffer, before any remaining unexecuted +// commands. +void Cbuf_InsertText(char *text) +{ + char *temp = NULL; + + int addLen = Q_strlen(text); + int currLen = cmd_text.cursize; + + if (cmd_text.cursize + addLen >= cmd_text.maxsize) + { + Con_Printf(__FUNCTION__ ": overflow\n"); + return; + } + + if (currLen) + { + temp = (char *)Z_Malloc(currLen); // TODO: Optimize: better use memmove without need for a temp buffer + Q_memcpy(temp, cmd_text.data, currLen); + SZ_Clear(&cmd_text); + } + + Cbuf_AddText(text); + + if (currLen) + { + SZ_Write(&cmd_text, temp, currLen); + Z_Free(temp); + } +} + +/* <4f05> ../engine/cmd.c:148 */ +void Cbuf_InsertTextLines(char *text) +{ + char *temp = NULL; + + int addLen = Q_strlen(text); + int currLen = cmd_text.cursize; + + if (cmd_text.cursize + addLen + 2 >= cmd_text.maxsize) + { + Con_Printf(__FUNCTION__ ": overflow\n"); + return; + } + + if (currLen) + { + temp = (char *)Z_Malloc(currLen); + Q_memcpy(temp, cmd_text.data, currLen); + SZ_Clear(&cmd_text); + } + + Cbuf_AddText("\n"); // TODO: Why we need leading \n, if there is no commands in the start? + Cbuf_AddText(text); + Cbuf_AddText("\n"); + + if (currLen) + { + SZ_Write(&cmd_text, temp, currLen); + Z_Free(temp); + } +} + +/* <5d96> ../engine/cmd.c:193 */ +// Pulls off \n terminated lines of text from the command buffer and sends +// them through Cmd_ExecuteString. Stops when the buffer is empty. +// Normally called once per frame, but may be explicitly invoked. +// Do not call inside a command function! +void Cbuf_Execute(void) +{ + int i; + char *text; + char line[MAX_CMD_LINE]; + int quotes; + + while (cmd_text.cursize) + { + // find a \n or ; line break + text = (char *)cmd_text.data; + + quotes = 0; + for (i = 0; i < cmd_text.cursize; i++) + { + if (text[i] == '"') + quotes++; + if (!(quotes & 1) && text[i] == ';') + break; // don't break if inside a quoted string + if (text[i] == '\n') + break; + } + + if (i > MAX_CMD_LINE - 1) + { + i = MAX_CMD_LINE - 1; + } + + Q_memcpy(line, text, i); + line[i] = 0; + + // delete the text from the command buffer and move remaining commands down + // this is necessary because commands (exec, alias) can insert data at the + // beginning of the text buffer + + if (i == cmd_text.cursize) + { + cmd_text.cursize = 0; + } + else + { + i++; + cmd_text.cursize -= i; + Q_memcpy(text, text + i, cmd_text.cursize); + } + + // execute the command line + Cmd_ExecuteString(line, src_command); + + if (cmd_wait) + { + // skip out while text still remains in buffer, leaving it + // for next frame + cmd_wait = FALSE; + break; + } + } +} + +/* <4e74> ../engine/cmd.c:271 */ +void Cmd_StuffCmds_f(void) +{ + int i; + int s; + char *build; + + if (Cmd_Argc() != 1) + { + Con_Printf("stuffcmds : execute command line parameters\n"); + return; + } + + if (com_argc <= 1) + { + return; + } + + // Get total length for the command line parameters + s = 0; + for (i = 1; i < com_argc; i++) + { + if (com_argv[i]) + { + s += Q_strlen(com_argv[i]) + 1; + } + } + + if (s == 0) + { + return; + } + + // Create buffer able to get all arguments + build = (char *)Z_Malloc(s + com_argc * 2); + build[0] = 0; + + // Iterate thru arguments searching for ones starting with + + for (i = 1; i < com_argc; i++) + { + if (com_argv[i] && com_argv[i][0] == '+') + { + // Add command or cvar + Q_strcat(build, &com_argv[i][1]); + // Then add all following parameters till we meet argument with + or -, which means next command/cvar/parameter + i++; + while (com_argv[i] && com_argv[i][0] != '+' && com_argv[i][0] != '-') + { + Q_strcat(build, " "); + Q_strcat(build, com_argv[i]); + i++; + } + // End up with new line which split commands for command processor + Q_strcat(build, "\n"); + i--; + } + } + + if (build[0] != 0) + { + Cbuf_InsertText(build); + } + + // Free buffers + Z_Free(build); +} + +/* <5e43> ../engine/cmd.c:347 */ +void Cmd_Exec_f(void) +{ + const char *pszFileName; + const char *pszFileExt; + char *pszFileData; + int nAddLen; + FileHandle_t hFile; + + if (Cmd_Argc() != 2) + { + Con_Printf("exec : execute a script file\n"); + return; + } + + pszFileName = Cmd_Argv(1); + if (!pszFileName || pszFileName[0] == 0) + { + return; + } + + if (Q_strstr(pszFileName, "\\") + || Q_strstr(pszFileName, ":") + || Q_strstr(pszFileName, "~") + || Q_strstr(pszFileName, "..") + || *pszFileName == '/') + { + Con_Printf("exec %s: invalid path.\n", pszFileName); + return; + } + + pszFileExt = COM_FileExtension((char *)pszFileName); + if (Q_stricmp(pszFileExt, "cfg") && Q_stricmp(pszFileExt, "rc")) + { + Con_Printf("exec %s: not a .cfg or .rc file\n", pszFileName); + return; + } + + hFile = FS_OpenPathID(pszFileName, "rb", "GAMECONFIG"); + if (!hFile) + { + hFile = FS_OpenPathID(pszFileName, "rb", "GAME"); + } + if (!hFile) + { + hFile = FS_Open(pszFileName, "rb"); + } + + if (!hFile) + { + if (!Q_strstr(pszFileName, "autoexec.cfg") + && !Q_strstr(pszFileName, "userconfig.cfg") + && !Q_strstr(pszFileName, "hw/opengl.cfg") + && !Q_strstr(pszFileName, "joystick.cfg") + && !Q_strstr(pszFileName, "game.cfg")) + { + Con_Printf("couldn't exec %s\n", pszFileName); + } + + return; + } + + nAddLen = FS_Size(hFile); + pszFileData = (char *)Mem_Malloc(nAddLen + 1); + + if (!pszFileData) + { + Con_Printf("exec: not enough space for %s", pszFileName); + FS_Close(hFile); + return; + } + + FS_Read(pszFileData, nAddLen, 1, hFile); + pszFileData[nAddLen] = 0; + FS_Close(hFile); + + Con_DPrintf("execing %s\n", pszFileName); + + if (cmd_text.cursize + nAddLen + 2 < cmd_text.maxsize) + { + Cbuf_InsertTextLines(pszFileData); + } + else + { + char *pszDataPtr = pszFileData; + while (true) + { + Cbuf_Execute(); // TODO: This doesn't obey the rule to first execute commands from the file, and then the others in the buffer + pszDataPtr = COM_ParseLine(pszDataPtr); + + if (com_token[0] == 0) + { + break; + } + + Cbuf_InsertTextLines(com_token); + } + } + + Mem_Free(pszFileData); +} + +/* <4ac1> ../engine/cmd.c:493 */ +void Cmd_Echo_f(void) +{ + int i; + int c = Cmd_Argc(); + + for (i = 1; i < c; i++) + { + Con_Printf("%s ", Cmd_Argv(i)); + } + + Con_Printf("\n"); +} + +/* <4c38> ../engine/cmd.c:510 */ +char *CopyString(char *in) +{ + char *out = (char *)Z_Malloc(Q_strlen(in) + 1); + Q_strcpy(out, in); + return out; +} + +/* <4c63> ../engine/cmd.c:521 */ +void Cmd_Alias_f(void) +{ + cmdalias_t *a; + const char *s; + char cmd[MAX_CMD_LINE]; + int i, c; + + if (Cmd_Argc() == 1) + { + // Output all aliases + Con_Printf("Current alias commands:\n"); + + for (a = cmd_alias; a; a = a->next) + { + Con_Printf("%s : %s", a->name, a->value); // Don't need \n here, because each alias value is appended with it + } + + return; + } + + s = Cmd_Argv(1); + + if (Q_strlen(s) >= MAX_ALIAS_NAME) + { + Con_Printf("Alias name is too long\n"); + return; + } + + if (Cvar_FindVar(s)) + { + Con_Printf("Alias name is invalid\n"); + return; + } + + SetCStrikeFlags(); // TODO: Do this once somewhere at the server start + + if ((g_bIsCStrike || g_bIsCZero) && + (!Q_stricmp(s, "cl_autobuy") + || !Q_stricmp(s, "cl_rebuy") + || !Q_stricmp(s, "gl_ztrick") + || !Q_stricmp(s, "gl_ztrick_old") + || !Q_stricmp(s, "gl_d3dflip"))) + { + Con_Printf("Alias name is invalid\n"); + return; + } + + // Say hello to my little friend! (c) + if (g_bIsTFC && (!Q_stricmp(s, "_special") || !Q_stricmp(s, "special"))) + { + Con_Printf("Alias name is invalid\n"); + return; + } + + // Gather arguments into one string + cmd[0] = 0; + c = Cmd_Argc(); + for (i = 2; i <= c; i++) + { + Q_strncat(cmd, Cmd_Argv(i), MAX_CMD_LINE - 2 - Q_strlen(cmd)); // always have a space for \n or ' ' and \0 + + if (i != c) + { + Q_strcat(cmd, " "); + } + } + Q_strcat(cmd, "\n"); + + // Search for existing alias + for (a = cmd_alias; a; a = a->next) + { + if (!Q_stricmp(a->name, s)) + { + if (!Q_strcmp(a->value, cmd)) + { + // Same value on the alias, return + return; + } + // Release value, will realloc + Z_Free(a->value); + break; + } + } + + if (!a) + { + // Alloc new alias + a = (cmdalias_t *)Z_Malloc(sizeof(cmdalias_t)); + a->next = cmd_alias; + cmd_alias = a; + + Q_strncpy(a->name, s, ARRAYSIZE(a->name) - 1); + a->name[ARRAYSIZE(a->name) - 1] = 0; + } + + a->value = CopyString(cmd); +} + +/* <5079> ../engine/cmd.c:632 */ +struct cmd_function_s *Cmd_GetFirstCmd(void) +{ + return cmd_functions; +} + +/* <5091> ../engine/cmd.c:646 */ +void Cmd_Init(void) +{ + Cmd_AddCommand("stuffcmds", Cmd_StuffCmds_f); + Cmd_AddCommand("exec", Cmd_Exec_f); + Cmd_AddCommand("echo", Cmd_Echo_f); + Cmd_AddCommand("alias", Cmd_Alias_f); + Cmd_AddCommand("cmd", Cmd_ForwardToServer); + Cmd_AddCommand("wait", Cmd_Wait_f); + Cmd_AddCommand("cmdlist", Cmd_CmdList_f); +} + +/* <5521> ../engine/cmd.c:663 */ +void Cmd_Shutdown(void) +{ + for (int i = 0; i < cmd_argc; i++) + { + Z_Free(cmd_argv[i]); + } + memset(cmd_argv, 0, sizeof(cmd_argv)); + cmd_argc = 0; + cmd_args = NULL; + + cmd_functions = NULL; // TODO: Check that memory from functions is released too +} + +/* <5536> ../engine/cmd.c:677 */ +int Cmd_Argc(void) +{ +#ifndef SWDS + g_engdstAddrs->Cmd_Argc(); +#endif + + return cmd_argc; +} + +/* <5547> ../engine/cmd.c:689 */ +const char *Cmd_Argv(int arg) +{ +#ifndef SWDS + g_engdstAddrs->Cmd_Argv(&arg); +#endif + + if (arg >= 0 && arg < cmd_argc) + { + return cmd_argv[arg]; + } + return ""; // TODO: Possibly better to return NULL here, but require to check all usages +} + +/* <5565> ../engine/cmd.c:703 */ +const char *Cmd_Args(void) +{ +#ifndef SWDS + g_engdstAddrs->Cmd_Args(); +#endif + + return cmd_args; +} + +/* <5575> ../engine/cmd.c:715 */ +/* +============ +Cmd_TokenizeString + +Parses the given string into command line tokens. +Takes a null terminated string. Does not need to be \n terminated. +Breaks the string up into arg tokens. +============ +*/ +void Cmd_TokenizeString(char *text) +{ + int i; + int arglen; + + // clear args from the last string + for (i = 0; i < cmd_argc; i++) + { + Z_Free(cmd_argv[i]); + cmd_argv[i] = NULL; + } + cmd_argc = 0; + cmd_args = NULL; + + while (true) + { + // Skip whitespace up to a \n + while (*text && *text <= ' ' && *text != '\n') + { + ++text; + } + + // A newline separates commands in the buffer + if (*text == '\n' || *text == 0) + { + break; + } + + // Store complete args string pointer + if (cmd_argc == 1) + { + cmd_args = text; + } + + // Break into token + text = COM_Parse(text); + + // If nothing was parsed + if (!text) + { + return; + } + + arglen = Q_strlen(com_token) + 1; + if (arglen >= 516) // TODO: What is that magic number? + { + return; + } + + cmd_argv[cmd_argc] = (char *)Z_Malloc(arglen); + Q_strcpy(cmd_argv[cmd_argc++], com_token); + + if (cmd_argc >= MAX_CMD_TOKENS) + { + // Will not fit any more + return; + } + } +} + +/* <55be> ../engine/cmd.c:773 */ +NOXREF cmd_function_t *Cmd_FindCmd(char *cmd_name) +{ + NOXREFCHECK; + + cmd_function_t *cmd; + + for (cmd = cmd_functions; cmd; cmd = cmd->next) + { + if (!Q_stricmp(cmd_name, cmd->name)) + { + return cmd; + } + } + + return NULL; +} + +/* <5611> ../engine/cmd.c:791 */ +NOXREF cmd_function_t *Cmd_FindCmdPrev(char *cmd_name) +{ + NOXREFCHECK; + + cmd_function_t *cmd = NULL; + + if (cmd_functions == NULL) + { + return NULL; + } + + for (cmd = cmd_functions; cmd->next; cmd = cmd->next) + { + if (!Q_stricmp(cmd_name, cmd->next->name)) + { + return cmd; + } + } + + return NULL; +} + +void Cmd_InsertCommand(cmd_function_t *cmd) +{ + cmd_function_t *c, **p; + + // Commands list is alphabetically sorted, search where to push + c = cmd_functions; + p = &cmd_functions; + while (c) + { + if (Q_stricmp(c->name, cmd->name) > 0) + { + // Current command name is bigger, insert before it + cmd->next = c; + *p = cmd; + return; + } + p = &c->next; + c = c->next; + } + + // All commands in the list are lower then the new one + cmd->next = NULL; + *p = cmd; +} + +/* <5664> ../engine/cmd.c:812 */ +// Use this for engine inside call only, not from user code, because it doesn't alloc string for the name. +void Cmd_AddCommand(char *cmd_name, xcommand_t function) +{ + cmd_function_t *cmd; + + if (host_initialized) + { + Sys_Error(__FUNCTION__ " after host_initialized"); + } + + // Check in variables list + if (Cvar_FindVar(cmd_name) != NULL) + { + Con_Printf(__FUNCTION__ ": \"%s\" already defined as a var\n", cmd_name); + return; + } + + // Check if this command is already defined + if (Cmd_Exists(cmd_name)) + { + Con_Printf(__FUNCTION__ ": \"%s\" already defined\n", cmd_name); + return; + } + + // Create cmd_function + cmd = (cmd_function_t *)Hunk_Alloc(sizeof(cmd_function_t)); + cmd->name = cmd_name; + cmd->function = function ? function : Cmd_ForwardToServer; + cmd->flags = 0; + + Cmd_InsertCommand(cmd); +} + +/* <5700> ../engine/cmd.c:891 */ +// Use this for call from user code, because it alloc string for the name. +void Cmd_AddMallocCommand(char *cmd_name, xcommand_t function, int flag) +{ + cmd_function_t *cmd; + + // Check in variables list + if (Cvar_FindVar(cmd_name) != NULL) + { + Con_Printf(__FUNCTION__ ": \"%s\" already defined as a var\n", cmd_name); + return; + } + + // Check if this command is already defined + if (Cmd_Exists(cmd_name)) + { + Con_Printf(__FUNCTION__ ": \"%s\" already defined\n", cmd_name); + return; + } + + // Create cmd_function + cmd = (cmd_function_t *)Mem_Malloc(sizeof(cmd_function_t)); + cmd->name = CopyString(cmd_name); // alloc string, so it will not dissapear on side modules unloading and to maintain the same name during run + cmd->function = function ? function : Cmd_ForwardToServer; + cmd->flags = flag; + + Cmd_InsertCommand(cmd); +} + +/* <5776> ../engine/cmd.c:934 */ +NOXREF void Cmd_AddHUDCommand(char *cmd_name, xcommand_t function) +{ + NOXREFCHECK; + + Cmd_AddMallocCommand(cmd_name, function, FCMD_HUD_COMMAND); +} + +/* <5824> ../engine/cmd.c:946 */ +NOXREF void Cmd_AddWrapperCommand(char *cmd_name, xcommand_t function) +{ + NOXREFCHECK; + + Cmd_AddMallocCommand(cmd_name, function, FCMD_WRAPPER_COMMAND); +} + +/* <58d2> ../engine/cmd.c:960 */ +void Cmd_AddGameCommand(char *cmd_name, xcommand_t function) +{ + Cmd_AddMallocCommand(cmd_name, function, FCMD_GAME_COMMAND); +} + +/* <5980> ../engine/cmd.c:970 */ +void Cmd_RemoveMallocedCmds(int flag) +{ + cmd_function_t *c, **p; + + c = cmd_functions; + p = &cmd_functions; + while (c) + { + if (c->flags & flag) + { + *p = c->next; + Z_Free(c->name); + Mem_Free(c); + c = *p; + continue; + } + p = &c->next; + c = c->next; + } +} + +/* <59f9> ../engine/cmd.c:1002 */ +NOXREF void Cmd_RemoveHudCmds(void) +{ + NOXREFCHECK; + + Cmd_RemoveMallocedCmds(FCMD_HUD_COMMAND); +} + +/* <5a4c> ../engine/cmd.c:1012 */ +void Cmd_RemoveGameCmds(void) +{ + Cmd_RemoveMallocedCmds(FCMD_GAME_COMMAND); +} + +/* <5a9f> ../engine/cmd.c:1022 */ +void Cmd_RemoveWrapperCmds(void) +{ + Cmd_RemoveMallocedCmds(FCMD_WRAPPER_COMMAND); +} + +/* <5af2> ../engine/cmd.c:1035 */ +qboolean Cmd_Exists(char *cmd_name) +{ + cmd_function_t *cmd = cmd_functions; + + while (cmd) + { + if (!Q_stricmp(cmd_name, cmd->name)) + { + return TRUE; + } + + cmd = cmd->next; + } + + return FALSE; +} + +/* <5b30> ../engine/cmd.c:1055 */ +NOXREF char *Cmd_CompleteCommand(char *search, int forward) +{ + NOXREFCHECK; + + // TODO: We have a command name length limit here: prepare for unforeseen consequences! + static char lastpartial[256]; + char partial[256]; + cmd_function_t *cmd; + int len; + char *pPartial; + + Q_strncpy(partial, search, 255); + partial[255] = 0; + len = Q_strlen(partial); + + // Trim tail spaces + for (pPartial = partial + len - 1; pPartial >= partial && *pPartial == ' '; pPartial--, len--) + { + *pPartial = 0; + } + + if (!len) + { + return NULL; + } + + if (!Q_stricmp(partial, lastpartial)) + { + // Same partial, find this then next/prev cvar, if any. + // TODO: But where it match for entered by user partial? Because we store full name + cmd = Cmd_FindCmd(partial); + if (cmd) + { + cmd = forward == 1 ? cmd->next : Cmd_FindCmdPrev(cmd->name); + if (cmd) + { + Q_strncpy(lastpartial, cmd->name, 255); + lastpartial[255] = 0; + return cmd->name; + } + } + } + + // Find first matching cvar + for (cmd = cmd_functions; cmd != NULL; cmd = cmd->next) + { + if (!Q_strnicmp(partial, cmd->name, len)) + { + // Store matched cvar name + Q_strncpy(lastpartial, cmd->name, 255); + lastpartial[255] = 0; + return cmd->name; + } + } + + return NULL; +} + +bool ValidateCmd_API(const char* cmd, cmd_source_t src, IGameClient* client) { + return true; +} + +/* <5d4e> ../engine/cmd.c:1133 */ +void Cmd_ExecuteString(char *text, cmd_source_t src) +{ + cmd_source = src; + Cmd_TokenizeString(text); + + if (!Cmd_Argc()) + { + return; + } + + IGameClient* cl = (src == src_client) ? GetRehldsApiClient(host_client) : NULL; + if (!g_RehldsHookchains.m_ValidateCommand.callChain(ValidateCmd_API, cmd_argv[0], src, cl)) + return; + + // Search in functions + cmd_function_t *cmd = cmd_functions; + while (cmd) + { + if (!Q_stricmp(cmd_argv[0], cmd->name)) + { + cmd->function(); + + if (g_pcls.demorecording && (cmd->flags & FCMD_HUD_COMMAND) && !g_pcls.spectator) + { + CL_RecordHUDCommand(cmd->name); + } + + return; + } + + cmd = cmd->next; + } + + // Search in aliases + cmdalias_t *a = cmd_alias; + while (a) + { + if (!Q_stricmp(cmd_argv[0], a->name)) + { + + Cbuf_InsertText(a->value); + return; + } + + a = a->next; + } + + // Search in cvars + if (!Cvar_Command() && g_pcls.state >= ca_connected) + { + // Send to a server if nothing processed locally and connected + Cmd_ForwardToServer(); + } +} + +/* <5c15> ../engine/cmd.c:1181 */ +qboolean Cmd_ForwardToServerInternal(sizebuf_t *pBuf) +{ + const char *cmd_name = Cmd_Argv(0); + + if (g_pcls.state <= ca_disconnected) + { + if (Q_stricmp(cmd_name, "setinfo")) + { + Con_Printf("Can't \"%s\", not connected\n", cmd_name); + } + + return FALSE; + } + + if (g_pcls.demoplayback || g_bIsDedicatedServer) + { + return FALSE; + } + + char tempData[4096]; + sizebuf_t tempBuf; + + tempBuf.buffername = __FUNCTION__ "::tempBuf"; + tempBuf.data = (byte *)tempData; + tempBuf.maxsize = 4096; + tempBuf.cursize = 0; + tempBuf.flags = SIZEBUF_ALLOW_OVERFLOW; + + MSG_WriteByte(&tempBuf, clc_stringcmd); + + if (Q_stricmp(cmd_name, "cmd")) + { + SZ_Print(&tempBuf, cmd_name); + SZ_Print(&tempBuf, " "); + } + + SZ_Print(&tempBuf, Cmd_Argc() <= 1 ? "\n" : Cmd_Args()); + + if (tempBuf.flags & SIZEBUF_OVERFLOWED) + { + return FALSE; + } + + if (tempBuf.cursize + pBuf->cursize <= pBuf->maxsize) + { + SZ_Write(pBuf, tempBuf.data, tempBuf.cursize); + return TRUE; + } + + return FALSE; +} + +/* <5cfd> ../engine/cmd.c:1247 */ +void Cmd_ForwardToServer(void) +{ + if (Q_stricmp(Cmd_Argv(0), "cmd") || Q_stricmp(Cmd_Argv(1), "dlfile")) + { + Cmd_ForwardToServerInternal(&g_pcls.netchan.message); + } +} + +/* <5f1b> ../engine/cmd.c:1258 */ +qboolean Cmd_ForwardToServerUnreliable(void) +{ + return Cmd_ForwardToServerInternal(&g_pcls.datagram); +} + +/* <5f35> ../engine/cmd.c:1273 */ +// Returns the position (1 to argc-1) in the command's argument list +// where the given parameter apears, or 0 if not present. +NOXREF int Cmd_CheckParm(char *parm) +{ + NOXREFCHECK; + + if (!parm) + { + Sys_Error(__FUNCTION__ ": NULL"); + } + + int c = Cmd_Argc(); + + for (int i = 1; i < c; i++) + { + if (!Q_stricmp(Cmd_Argv(i), parm)) + { + return i; + } + } + + return 0; +} + +/* <4b17> ../engine/cmd.c:1301 */ +void Cmd_CmdList_f(void) +{ + cmd_function_t *cmd; + int iCmds; + int iArgs; + const char *partial, *arg1; + int ipLen; + char szTemp[MAX_PATH]; + FileHandle_t f; + FileHandle_t fp; + qboolean bLogging; + + iCmds = 0; + partial = NULL; + f = NULL; + fp = NULL; + bLogging = FALSE; + + iArgs = Cmd_Argc(); + if (iArgs > 1) + { + arg1 = Cmd_Argv(1); + + if (!Q_stricmp(arg1, "?")) + { + Con_Printf("CmdList : List all commands\nCmdList [Partial] : List commands starting with 'Partial'\nCmdList log [Partial] : Logs commands to file \"cmdlist.txt\" in the gamedir.\n"); + return; + } + + if (!Q_stricmp(arg1, "log")) + { + // Open log + int i; + for (i = 0; i < 100; i++) + { + Q_snprintf(szTemp, ARRAYSIZE(szTemp) - 1, "cmdlist%02d.txt", i); + szTemp[ARRAYSIZE(szTemp) - 1] = 0; + + fp = FS_Open(szTemp, "r"); + if (!fp) + { + break; + } + FS_Close(fp); + } + + if (i >= 100) + { + Con_Printf("Can't cmdlist! Too many existing cmdlist output files in the gamedir!\n"); + return; + } + + f = FS_Open(szTemp, "wt"); + if (!f) + { + Con_Printf("Couldn't open \"%s\" for writing!\n", szTemp); + return; + } + bLogging = TRUE; + + // Get next argument into partial, if present + if (iArgs >= 2) + { + partial = Cmd_Argv(2); + ipLen = Q_strlen(partial); + } + } + else + { + partial = arg1; + ipLen = Q_strlen(partial); + } + } + + // Print commands + Con_Printf("Command List\n--------------\n"); + + for (cmd = cmd_functions; cmd; cmd = cmd->next) + { + if (partial && Q_strnicmp(cmd->name, partial, ipLen)) + { + continue; + } + + Con_Printf("%s\n", cmd->name); + + if (bLogging) + { + FS_FPrintf(f, "%s\n", cmd->name); + } + + iCmds++; + } + + if (partial && *partial) + { + Con_Printf("--------------\n%3i Commands for [%s]\nCmdList ? for syntax\n", iCmds, partial); + } + else + { + Con_Printf("--------------\n%3i Total Commands\nCmdList ? for syntax\n", iCmds); + } + + // Close log + if (bLogging) + { + FS_Close(f); + Con_Printf("cmdlist logged to %s\n", szTemp); + } +} diff --git a/rehlds/engine/cmd.h b/rehlds/engine/cmd.h new file mode 100644 index 0000000..f60800c --- /dev/null +++ b/rehlds/engine/cmd.h @@ -0,0 +1,123 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "maintypes.h" +#include "common.h" +#include "cmd_rehlds.h" + +/* +All command/alias names are case insensitive! Arguments not. +*/ + +#define MAX_CMD_BUFFER 16384 +#define MAX_CMD_TOKENS 80 +#define MAX_CMD_LINE 1024 + +/* + +Any number of commands can be added in a frame, from several different sources. +Most commands come from either keybindings or console line input, but remote +servers can also send across commands and entire text files can be execed. + +The + command line options are also added to the command buffer. + +*/ + +/* + +Command execution takes a null terminated string, breaks it into tokens, +then searches for a command or variable that matches the first token. + +Commands can come from three sources, but the handler functions may choose +to disallow the action or forward it to a remote server if the source is +not apropriate. + +*/ + +#ifdef HOOK_ENGINE +#define cmd_argc (*pcmd_argc) +#define cmd_argv (*pcmd_argv) +#define cmd_args (*pcmd_args) + +#define cmd_text (*pcmd_text) +#define cmd_source (*pcmd_source) +#define cmd_wait (*pcmd_wait) + +#define cmd_functions (*pcmd_functions) +#define cmd_alias (*pcmd_alias) +#endif // HOOK_ENGINE + +extern int cmd_argc; +extern char *cmd_argv[80]; +extern char *cmd_args; + +extern sizebuf_t cmd_text; +extern cmd_source_t cmd_source; +extern qboolean cmd_wait; + +extern cmd_function_t *cmd_functions; +extern cmdalias_t *cmd_alias; + +void Cmd_Wait_f(void); +void Cbuf_Init(void); +void Cbuf_AddText(char *text); +void Cbuf_InsertText(char *text); +void Cbuf_InsertTextLines(char *text); +void Cbuf_Execute(void); +void Cmd_StuffCmds_f(void); +void Cmd_Exec_f(void); +void Cmd_Echo_f(void); +char *CopyString(char *in); +void Cmd_Alias_f(void); +struct cmd_function_s *Cmd_GetFirstCmd(void); +void Cmd_Init(void); +void Cmd_Shutdown(void); +int Cmd_Argc(void); +const char *Cmd_Argv(int arg); +const char *Cmd_Args(void); +void Cmd_TokenizeString(char *text); +NOXREF cmd_function_t *Cmd_FindCmd(char *cmd_name); +NOXREF cmd_function_t *Cmd_FindCmdPrev(char *cmd_name); +void Cmd_AddCommand(char *cmd_name, xcommand_t function); +void Cmd_AddMallocCommand(char *cmd_name, xcommand_t function, int flag); +NOXREF void Cmd_AddHUDCommand(char *cmd_name, xcommand_t function); +NOXREF void Cmd_AddWrapperCommand(char *cmd_name, xcommand_t function); +void Cmd_AddGameCommand(char *cmd_name, xcommand_t function); +void Cmd_RemoveMallocedCmds(int flag); +NOXREF void Cmd_RemoveHudCmds(void); +void Cmd_RemoveGameCmds(void); +void Cmd_RemoveWrapperCmds(void); +qboolean Cmd_Exists(char *cmd_name); +NOXREF char *Cmd_CompleteCommand(char *search, int forward); +void Cmd_ExecuteString(char *text, cmd_source_t src); +qboolean Cmd_ForwardToServerInternal(sizebuf_t *pBuf); +void Cmd_ForwardToServer(void); +qboolean Cmd_ForwardToServerUnreliable(void); +NOXREF int Cmd_CheckParm(char *parm); +void Cmd_CmdList_f(void); diff --git a/rehlds/engine/cmodel.cpp b/rehlds/engine/cmodel.cpp new file mode 100644 index 0000000..8c5164d --- /dev/null +++ b/rehlds/engine/cmodel.cpp @@ -0,0 +1,288 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +unsigned char *gPAS; +unsigned char *gPVS; +int gPVSRowBytes; +unsigned char mod_novis[MODEL_MAX_PVS]; + + + + +/* <812a> ../engine/cmodel.c:23 */ +void Mod_Init(void) +{ + SW_Mod_Init(); + Q_memset(mod_novis, 255, MODEL_MAX_PVS); +} + +/* <813f> ../engine/cmodel.c:37 */ +unsigned char *Mod_DecompressVis(unsigned char *in, model_t *model) +{ + static unsigned char decompressed[MODEL_MAX_PVS]; + + if (in == NULL) + { + return mod_novis; + } + + int row = (model->numleafs + 7) / 8; + // TODO: Move to model loading code + if (row < 0 || row > MODEL_MAX_PVS) + { + Sys_Error(__FUNCTION__ ": oversized model->numleafs: %i", model->numleafs); + } + + CM_DecompressPVS(in, decompressed, row); + return decompressed; +} + +/* <824c> ../engine/cmodel.c:54 */ +unsigned char *Mod_LeafPVS(mleaf_t *leaf, model_t *model) +{ + if (leaf == model->leafs) + { + return mod_novis; + } + + if (!gPVS) + { + return Mod_DecompressVis(leaf->compressed_vis, model); + } + + int leafnum = leaf - model->leafs; + return CM_LeafPVS(leafnum); +} + +/* <8358> ../engine/cmodel.c:68 */ +void CM_DecompressPVS(unsigned char *in, unsigned char *decompressed, int byteCount) +{ + int c; + unsigned char *out; + + if (in == NULL) + { + // Make all visible + Q_memcpy(decompressed, mod_novis, byteCount); + return; + } + + out = decompressed; + while (out < decompressed + byteCount) + { + // Non zero is not copmpressed + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; // TODO: Check that input buffer is correct (last byte on the buffer could be zero and we will go out of the buffer - check the model) + in += 2; + + // Prevent buffer overrun + if (c > decompressed + byteCount - out) + { + c = decompressed + byteCount - out; + } + + // Unpack zeros + Q_memset(out, 0, c); + out += c; + } +} + +/* <8106> ../engine/cmodel.c:100 */ +unsigned char *CM_LeafPVS(int leafnum) +{ + if (gPVS) + { + return &gPVS[gPVSRowBytes * leafnum]; + } + return mod_novis; +} + +/* <83b7> ../engine/cmodel.c:109 */ +unsigned char *CM_LeafPAS(int leafnum) +{ + if (gPAS) + { + return &gPAS[gPVSRowBytes * leafnum]; + } + return mod_novis; +} + +/* <83ec> ../engine/cmodel.c:118 */ +void CM_FreePAS(void) +{ + if (gPAS) + Mem_Free(gPAS); + if (gPVS) + Mem_Free(gPVS); + gPAS = 0; + gPVS = 0; +} + +/* <83fd> ../engine/cmodel.c:139 */ +void CM_CalcPAS(model_t *pModel) +{ + int rows, rowwords; + int actualRowBytes; + int i, j, k, l; + int index; + int bitbyte; + unsigned int *dest, *src; + unsigned char *scan; + int count, vcount, acount; + + Con_DPrintf("Building PAS...\n"); + CM_FreePAS(); + + // Calculate memory: matrix of each to each leaf visibility + rows = (pModel->numleafs + 7) / 8; + count = pModel->numleafs + 1; + actualRowBytes = (rows + 3) & 0xFFFFFFFC; // 4-byte align + rowwords = actualRowBytes / 4; + gPVSRowBytes = actualRowBytes; + + // Alloc PVS + gPVS = (byte *)Mem_Calloc(gPVSRowBytes, count); + + // Decompress visibility data + scan = gPVS; + vcount = 0; + for (i = 0; i < count; i++, scan += gPVSRowBytes) + { + CM_DecompressPVS(pModel->leafs[i].compressed_vis, scan, rows); + + if (i == 0) + { + continue; + } + + for (j = 0; j < count; j++) + { + if (scan[j >> 3] & (1 << (j & 7))) + { + ++vcount; + } + } + } + + // Alloc PAS + gPAS = (byte *)Mem_Calloc(gPVSRowBytes, count); + + // Build PAS + acount = 0; + scan = gPVS; + dest = (unsigned int *)gPAS; + for (i = 0; i < count; i++, scan += gPVSRowBytes, dest += rowwords) + { + Q_memcpy(dest, scan, gPVSRowBytes); + + for (j = 0; j < gPVSRowBytes; j++) // bytes + { + bitbyte = scan[j]; + if (bitbyte == 0) + { + continue; + } + + for (k = 0; k < 8; k++) // bits + { + if (!(bitbyte & (1 << k))) + { + continue; + } + + index = j * 8 + k + 1; // bit index + if (index >= count) + { + continue; + } + + src = (unsigned int *)&gPVS[index * gPVSRowBytes]; + for (l = 0; l < rowwords; l++) + { + dest[l] |= src[l]; + } + } + } + + if (i == 0) + { + continue; + } + + for (j = 0; j < count; j++) + { + if (((byte *)dest)[j >> 3] & (1 << (j & 7))) + { + ++acount; + } + } + } + + Con_DPrintf("Average leaves visible / audible / total: %i / %i / %i\n", vcount / count, acount / count, count); +} + +/* <858a> ../engine/cmodel.c:218 */ +qboolean CM_HeadnodeVisible(mnode_t *node, unsigned char *visbits, int *first_visible_leafnum) +{ + int leafnum; + mleaf_t *leaf; + + leaf = (mleaf_t *)node; + while (leaf && leaf->contents != CONTENTS_SOLID) + { + if (leaf->contents < 0) + { + leafnum = leaf - g_psv.worldmodel->leafs - 1; + if ((visbits[leafnum >> 3] & (1 << (leafnum & 7))) == 0) + { + return 0; + } + if (first_visible_leafnum) + { + *first_visible_leafnum = leafnum; + } + return 1; + } + + if (CM_HeadnodeVisible(((mnode_t *)leaf)->children[0], visbits, first_visible_leafnum)) + { + return 1; + } + + leaf = (mleaf_t *)((mnode_t *)leaf)->children[1]; + } + + return 0; +} diff --git a/rehlds/engine/cmodel.h b/rehlds/engine/cmodel.h new file mode 100644 index 0000000..a81852f --- /dev/null +++ b/rehlds/engine/cmodel.h @@ -0,0 +1,67 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef CMODEL_H +#define CMODEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "model.h" + + +// Looks like no more than 8096 visibility leafs per world model +#define MODEL_MAX_PVS 1024 + + +#ifdef HOOK_ENGINE +#define gPAS (*pgPAS) +#define gPVS (*pgPVS) +#define gPVSRowBytes (*pgPVSRowBytes) +#define mod_novis (*pmod_novis) +#endif // HOOK_ENGINE + + +extern unsigned char *gPAS; +extern unsigned char *gPVS; +extern int gPVSRowBytes; +extern unsigned char mod_novis[MODEL_MAX_PVS]; + + +void Mod_Init(void); +unsigned char *Mod_DecompressVis(unsigned char *in, model_t *model); +unsigned char *Mod_LeafPVS(mleaf_t *leaf, model_t *model); +void CM_DecompressPVS(unsigned char *in, unsigned char *decompressed, int byteCount); +unsigned char *CM_LeafPVS(int leafnum); +unsigned char *CM_LeafPAS(int leafnum); +void CM_FreePAS(void); +void CM_CalcPAS(model_t *pModel); +qboolean CM_HeadnodeVisible(mnode_t *node, unsigned char *visbits, int *first_visible_leafnum); + +#endif // CMODEL_H diff --git a/rehlds/engine/com_custom.cpp b/rehlds/engine/com_custom.cpp new file mode 100644 index 0000000..2c7510f --- /dev/null +++ b/rehlds/engine/com_custom.cpp @@ -0,0 +1,201 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +/* <99d0> ../engine/com_custom.c:19 */ +void COM_ClearCustomizationList(customization_t *pHead, qboolean bCleanDecals) +{ + customization_s *pCurrent, *pNext; + cachewad_t *pWad; + cachepic_t *pic; + + pCurrent = pHead->pNext; + if (!pCurrent) + return; + + while (pCurrent) + { + pNext = pCurrent->pNext; + + if (pCurrent->bInUse) + { + if (pCurrent->pBuffer) + Mem_Free(pCurrent->pBuffer); + + if (pCurrent->pInfo) + { + if (pCurrent->resource.type == t_decal) + { + if (bCleanDecals && g_pcls.state == ca_active) + { + R_DecalRemoveAll(-1 - pCurrent->resource.playernum); + } + + pWad = (cachewad_t *)pCurrent->pInfo; + + Mem_Free(pWad->lumps); + + for (int i = 0; i < pWad->cacheCount; i++) + { + pic = &pWad->cache[i]; + if (Cache_Check(&pic->cache)) + Cache_Free(&pic->cache); + } + + Mem_Free(pWad->name); + Mem_Free(pWad->cache); + } + + Mem_Free(pCurrent->pInfo); + } + } + + Mem_Free(pCurrent); + pCurrent = pNext; + } + + pHead->pNext = NULL; +} + +/* <9a75> ../engine/com_custom.c:88 */ +qboolean COM_CreateCustomization(customization_t *pListHead, resource_t *pResource, int playernumber, int flags, customization_t **pCustomization, int *nLumps) +{ + customization_t *pCust; // 91 + qboolean bError; // 92 + + bError = 0; + if (pCustomization) + *pCustomization = 0; + pCust = (customization_t *)Mem_ZeroMalloc(sizeof(customization_t)); + + memcpy(&pCust->resource, pResource, sizeof(pCust->resource)); + if (pResource->nDownloadSize <= 0) + { + bError = 1; + goto CustomizationError; + } + + pCust->bInUse = 1; + + if (flags & 1) + { + if (!HPAK_GetDataPointer("custom.hpk", pResource, (uint8_t**)&pCust->pBuffer, 0)) + { + bError = 1; + goto CustomizationError; + } + } + else + { + pCust->pBuffer = COM_LoadFile(pResource->szFileName, 5, 0); + } + + if ((pCust->resource.ucFlags & RES_CUSTOM) && pCust->resource.type == t_decal) + { + pCust->resource.playernum = playernumber; + if (!CustomDecal_Validate(pCust->pBuffer, pResource->nDownloadSize)) + { + bError = 1; + goto CustomizationError; + } + + if (!(flags & 4)) + { + cachewad_t * pWad = (cachewad_t *)Mem_ZeroMalloc(0x2Cu); + pCust->pInfo = pWad; + if (pResource->nDownloadSize >= 1024 && pResource->nDownloadSize <= 20480) + { + bError = (0 == CustomDecal_Init(pWad, pCust->pBuffer, pResource->nDownloadSize, playernumber)); + if (bError) + goto CustomizationError; + + if (pWad->lumpCount > 0) + { + if (nLumps) + *nLumps = pWad->lumpCount; + + pCust->bTranslated = 1; + pCust->nUserData1 = 0; + pCust->nUserData2 = pWad->lumpCount; + if (flags & 2) + { + Mem_Free(pWad->name); + Mem_Free(pWad->cache); + Mem_Free(pWad->lumps); + Mem_Free(pCust->pInfo); + pCust->pInfo = 0; + } + } + } + } + } + +CustomizationError: + if (bError) + { + if (pCust->pBuffer) + Mem_Free(pCust->pBuffer); + if (pCust->pInfo) + Mem_Free(pCust->pInfo); + Mem_Free(pCust); + } + else + { + if (pCustomization) + *pCustomization = pCust; + pCust->pNext = pListHead->pNext; + pListHead->pNext = pCust; + } + return bError == 0; +} + +/* <9b41> ../engine/com_custom.c:229 */ +int COM_SizeofResourceList(resource_t *pList, resourceinfo_t *ri) +{ + resource_t *p; + int nSize; + + nSize = 0; + Q_memset(ri, 0, sizeof(*ri)); + for (p = pList->pNext; p != pList; p = p->pNext) + { + nSize += p->nDownloadSize; + if (p->type != t_model || p->nIndex != 1) + { + if ((unsigned int)p->type < sizeof(ri->info)) + ri->info[p->type].size += p->nDownloadSize; + } + else + { + ri->info[t_world].size += p->nDownloadSize; + } + } + return nSize; +} diff --git a/rehlds/engine/com_custom.h b/rehlds/engine/com_custom.h new file mode 100644 index 0000000..6bbb4db --- /dev/null +++ b/rehlds/engine/com_custom.h @@ -0,0 +1,43 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef COM_CUSTOM_H +#define COM_CUSTOM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "custom.h" + + +void COM_ClearCustomizationList(customization_t *pHead, qboolean bCleanDecals); +qboolean COM_CreateCustomization(customization_t *pListHead, resource_t *pResource, int playernumber, int flags, customization_t **pCustomization, int *nLumps); +int COM_SizeofResourceList(resource_t *pList, resourceinfo_t *ri); + +#endif // COM_CUSTOM_H diff --git a/rehlds/engine/common.cpp b/rehlds/engine/common.cpp new file mode 100644 index 0000000..0dd6b4c --- /dev/null +++ b/rehlds/engine/common.cpp @@ -0,0 +1,2693 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + + + + +char serverinfo[MAX_INFO_STRING]; + +char gpszVersionString[32]; +char gpszProductString[32]; + + +/* ../engine/common.c:80 */ +char *Info_Serverinfo(void) +{ + return serverinfo; +} + + +#ifdef Q_functions + +/* ../engine/common.c:123 */ +NOBODY void Q_memset(void *dest, int fill, int count); + +/* ../engine/common.c:143 */ +NOBODY void Q_memcpy(void *dest, const void *src, int count); + +/* ../engine/common.c:162 */ +NOBODY int Q_memcmp(void *m1, void *m2, int count); + +/* ../engine/common.c:180 */ +void Q_strcpy(char *dest, const char *src) +{ + char *c; + const char *s; + + s = src; + for (c = dest; s; *c++ = *s++) + { + if (!c) + break; + if (!*s) + break; + } + *c = 0; +} + +/* ../engine/common.c:189 */ +NOBODY void Q_strncpy(char *dest, const char *src, int count); + +/* ../engine/common.c:203 */ +int Q_strlen(const char *str) +{ + int result = 0; + if (str) + { + if (*str) + { + while (str[result++ + 1]); + } + } + return result; +} + +/* ../engine/common.c:219 */ +NOBODY char *Q_strrchr(char *s, char c); + +/* ../engine/common.c:228 */ +NOBODY void Q_strcat(char *dest, char *src); + +/* ../engine/common.c:234 */ +NOBODY int Q_strcmp(const char *s1, const char *s2); + +/* ../engine/common.c:252 */ +NOBODY int Q_strncmp(const char *s1, const char *s2, int count); + +/* ../engine/common.c:272 */ +NOBODY int Q_strncasecmp(const char *s1, const char *s2, int n); + +/* ../engine/common.c:311 */ +NOBODY int Q_strcasecmp(const char *s1, const char *s2); + +/* ../engine/common.c:316 */ +NOBODY int Q_stricmp(const char *s1, const char *s2); + +/* ../engine/common.c:321 */ +NOBODY int Q_strnicmp(const char *s1, const char *s2, int n); + +/* ../engine/common.c:326 */ +NOBODY int Q_atoi(const char *str); + +/* ../engine/common.c:385 */ +NOBODY float Q_atof(const char *str); + +/* ../engine/common.c:460 */ +NOBODY char *Q_strlwr(char *src); + +/* ../engine/common.c:475 */ +NOBODY int Q_FileNameCmp(char *file1, char *file2); + +/* ../engine/common.c:495 */ +NOBODY char *Q_strstr(const char *s1, const char *search); + +/* ../engine/common.c:502 */ +NOBODY uint64 Q_strtoull(char *str); + +#endif // Q_functions + + +#ifndef COM_Functions_region + +/* ../engine/common.c:550 */ +unsigned char COM_Nibble(char c) +{ + if (c >= '0' && c <= '9') + { + return (unsigned char)(c - '0'); + } + + if (c >= 'A' && c <= 'F') + { + return (unsigned char)(c - 'A' + 0x0A); + } + + if (c >= 'a' && c <= 'f') + { + return (unsigned char)(c - 'a' + 0x0A); + } + + return '0'; +} + +/* ../engine/common.c:580 */ +void COM_HexConvert(const char *pszInput, int nInputLength, unsigned char *pOutput) +{ + unsigned char *p; + int i; + const char *pIn; + + p = pOutput; + for (i = 0; i < nInputLength - 1; i += 2) + { + pIn = &pszInput[i]; + if (pIn[0] == 0 || pIn[1] == 0) + break; + + *p = COM_Nibble(pIn[0]) << 4 | COM_Nibble(pIn[1]); + + p++; + } +} + +/* ../engine/common.c:597 */ +NOXREF char *COM_BinPrintf(unsigned char *buf, int nLen) +{ + static char szReturn[4096]; + unsigned char c; + char szChunk[10]; + int i; + + Q_memset(szReturn, 0, sizeof(szReturn)); + + for (i = 0; i < nLen; i++) + { + c = (unsigned char)buf[i]; + + Q_snprintf(szChunk, sizeof(szChunk), "%02x", c); + Q_strncat(szReturn, szChunk, sizeof(szReturn) - Q_strlen(szReturn) - 1); + } + return szReturn; +} + +/* ../engine/common.c:616 */ +void COM_ExplainDisconnection(qboolean bPrint, char *fmt, ...) +{ + va_list argptr; + static char string[1024]; + + va_start(argptr, fmt); + Q_vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + Q_strncpy(gszDisconnectReason, string, sizeof(gszDisconnectReason) - 1); + gszDisconnectReason[sizeof(gszDisconnectReason) - 1] = 0; + gfExtendedError = 1; + if (bPrint) + { + if (gszDisconnectReason[0] != '#') + Con_Printf("%s\n", gszDisconnectReason); + } +} + +/* ../engine/common.c:636 */ +NOXREF void COM_ExtendedExplainDisconnection(qboolean bPrint, char *fmt, ...) +{ + NOXREFCHECK; + + va_list argptr; + static char string[1024]; + + va_start(argptr, fmt); + Q_vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + Q_strncpy(gszExtendedDisconnectReason, string, sizeof(gszExtendedDisconnectReason) - 1); + gszExtendedDisconnectReason[sizeof(gszExtendedDisconnectReason) - 1] = 0; + if (bPrint) + { + if (gszExtendedDisconnectReason[0] != '#') + Con_Printf("%s\n", gszExtendedDisconnectReason); + } +} + +#endif // COM_Functions_region + + +#ifndef Byte_Functions_region + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +qboolean bigendien; +short (*BigShort)(short l); +short (*LittleShort)(short l); +int (*BigLong)(int l); +int (*LittleLong)(int l); +float (*BigFloat)(float l); +float (*LittleFloat)(float l); + + +int LongSwap(int l) +{ + byte b1, b2, b3, b4; + + b1 = l & 0xFF; + b2 = (l >> 8) & 0xFF; + b3 = (l >> 16) & 0xFF; + b4 = (l >> 24) & 0xFF; + + return ((int)b1 << 24) + ((int)b2 << 16) + ((int)b3 << 8) + b4; +} + +int LongNoSwap(int l) +{ + return l; +} + +short ShortSwap(short l) +{ + byte b1, b2; + + b1 = l & 0xFF; + b2 = (l >> 8) & 0xFF; + + return (b1 << 8) + b2; +} + +short ShortNoSwap(short l) +{ + return l; +} + +float FloatSwap(float f) +{ + union + { + float f; + byte b[4]; + } dat1, dat2; + + dat1.f = f; + dat2.b[0] = dat1.b[3]; + dat2.b[1] = dat1.b[2]; + dat2.b[2] = dat1.b[1]; + dat2.b[3] = dat1.b[0]; + + return dat2.f; +} + +float FloatNoSwap(float f) +{ + return f; +} + +#endif // Byte_Functions_region + + +#ifndef MSG_Functions_region + +/* +============================================================================== + + MESSAGE IO FUNCTIONS + +Handles byte ordering and avoids alignment errors +============================================================================== +*/ + +int msg_badread; +int msg_readcount; + +// Some bit tables... +const uint32_t BITTABLE[] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x00000100, 0x00000200, 0x00000400, 0x00000800, + 0x00001000, 0x00002000, 0x00004000, 0x00008000, + 0x00010000, 0x00020000, 0x00040000, 0x00080000, + 0x00100000, 0x00200000, 0x00400000, 0x00800000, + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x00000000, +}; + +const uint32_t ROWBITTABLE[] = +{ + 0x00000000, 0x00000001, 0x00000003, 0x00000007, + 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F, + 0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF, + 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, + 0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, + 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, + 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, + 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, + 0xFFFFFFFF, +}; + +const uint32_t INVBITTABLE[] = +{ + 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFB, 0xFFFFFFF7, + 0xFFFFFFEF, 0xFFFFFFDF, 0xFFFFFFBF, 0xFFFFFF7F, + 0xFFFFFEFF, 0xFFFFFDFF, 0xFFFFFBFF, 0xFFFFF7FF, + 0xFFFFEFFF, 0xFFFFDFFF, 0xFFFFBFFF, 0xFFFF7FFF, + 0xFFFEFFFF, 0xFFFDFFFF, 0xFFFBFFFF, 0xFFF7FFFF, + 0xFFEFFFFF, 0xFFDFFFFF, 0xFFBFFFFF, 0xFF7FFFFF, + 0xFEFFFFFF, 0xFDFFFFFF, 0xFBFFFFFF, 0xF7FFFFFF, + 0xEFFFFFFF, 0xDFFFFFFF, 0xBFFFFFFF, 0x7FFFFFFF, + 0xFFFFFFFF, +}; + + +void MSG_WriteChar(sizebuf_t *sb, int c) +{ + unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 1); + *(char *)buf = (char)c; +} + +void MSG_WriteByte(sizebuf_t *sb, int c) +{ + unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 1); + *(byte *)buf = (byte)c; +} + +void MSG_WriteShort(sizebuf_t *sb, int c) +{ + unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 2); + *(int16_t *)buf = (int16_t)c; +} + +void MSG_WriteWord(sizebuf_t *sb, int c) +{ + unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 2); + *(uint16_t *)buf = (uint16_t)c; +} + +void MSG_WriteLong(sizebuf_t *sb, int c) +{ + unsigned char *buf = (unsigned char *)SZ_GetSpace(sb, 4); + *(uint32_t *)buf = (uint32_t)c; +} + +void MSG_WriteFloat(sizebuf_t *sb, float f) +{ + int i = LittleLong(*(int *)&f); + SZ_Write(sb, &i, 4); +} + +void MSG_WriteString(sizebuf_t *sb, const char *s) +{ + if (s) + { + SZ_Write(sb, s, Q_strlen(s) + 1); + } + else + { + SZ_Write(sb, "", 1); + } +} + +void MSG_WriteBuf(sizebuf_t *sb, int iSize, void *buf) +{ + if (buf) + { + SZ_Write(sb, buf, iSize); + } +} + +void MSG_WriteAngle(sizebuf_t *sb, float f) +{ + MSG_WriteByte(sb, (int64_t)(fmod((double)f, 360.0) * 256.0 / 360.0) & 0xFF); +} + +void MSG_WriteHiresAngle(sizebuf_t *sb, float f) +{ + MSG_WriteShort(sb, (int64_t)(fmod((double)f, 360.0) * 65536.0 / 360.0) & 0xFFFF); +} + +void MSG_WriteUsercmd(sizebuf_t *buf, usercmd_t *to, usercmd_t *from) +{ + delta_t **ppdesc; + + ppdesc = (delta_t **)DELTA_LookupRegistration("usercmd_t"); + MSG_StartBitWriting(buf); + DELTA_WriteDelta((byte *)from, (byte *)to, 1, *ppdesc, 0); + MSG_EndBitWriting(buf); +} + + +typedef struct bf_write_s +{ + int nCurOutputBit; + unsigned char *pOutByte; + sizebuf_t *pbuf; +} bf_write_t; + +typedef struct bf_read_s +{ + int nMsgReadCount; // was msg_readcount + sizebuf_t *pbuf; + int nBitFieldReadStartByte; + int nBytesRead; + int nCurInputBit; + unsigned char *pInByte; +} bf_read_t; + +// Bit field reading/writing storage. +bf_read_t bfread; +bf_write_t bfwrite; + + +void COM_BitOpsInit(void) +{ + Q_memset(&bfwrite, 0, sizeof(bf_write_t)); + Q_memset(&bfread, 0, sizeof(bf_read_t)); +} + +void MSG_WriteOneBit(int nValue) +{ + if (bfwrite.nCurOutputBit >= 8) + { + SZ_GetSpace(bfwrite.pbuf, 1); + bfwrite.nCurOutputBit = 0; + ++bfwrite.pOutByte; + } + + if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED)) + { + if (nValue) + { + *bfwrite.pOutByte |= BITTABLE[bfwrite.nCurOutputBit]; + } + else + { + *bfwrite.pOutByte &= INVBITTABLE[bfwrite.nCurOutputBit * 4]; + } + + bfwrite.nCurOutputBit++; + } +} + +void MSG_StartBitWriting(sizebuf_t *buf) +{ + bfwrite.nCurOutputBit = 0; + bfwrite.pbuf = buf; + bfwrite.pOutByte = &buf->data[buf->cursize]; +} + +NOXREF qboolean MSG_IsBitWriting(void) +{ + NOXREFCHECK; + + return bfwrite.pbuf != 0; +} + +void MSG_EndBitWriting(sizebuf_t *buf) +{ + if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED)) + { + *bfwrite.pOutByte &= 255 >> (8 - bfwrite.nCurOutputBit); + SZ_GetSpace(bfwrite.pbuf, 1); + bfwrite.nCurOutputBit = 0; + bfwrite.pOutByte = 0; + bfwrite.pbuf = 0; + } +} + +void MSG_WriteBits(uint32_t data, int numbits) +{ + if (numbits < 32) + { + if (data >= (uint32_t)(1 << numbits)) + data = ROWBITTABLE[numbits]; + } + + int surplusBytes = 0; + if ((uint32_t)bfwrite.nCurOutputBit >= 8) + { + surplusBytes = 1; + bfwrite.nCurOutputBit = 0; + ++bfwrite.pOutByte; + } + + int bits = numbits + bfwrite.nCurOutputBit; + if (bits <= 32) + { + int bytesToWrite = bits >> 3; + int bitsLeft = bits & 7; + if (!bitsLeft) + --bytesToWrite; + SZ_GetSpace(bfwrite.pbuf, surplusBytes + bytesToWrite); + if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED)) + { + *(uint32_t *)bfwrite.pOutByte = (data << bfwrite.nCurOutputBit) | *(uint32_t *)bfwrite.pOutByte & ROWBITTABLE[bfwrite.nCurOutputBit]; + bfwrite.nCurOutputBit = 8; + if (bitsLeft) + bfwrite.nCurOutputBit = bitsLeft; + bfwrite.pOutByte = &bfwrite.pOutByte[bytesToWrite]; + } + } + else + { + SZ_GetSpace(bfwrite.pbuf, surplusBytes + 4); + if (!(bfwrite.pbuf->flags & SIZEBUF_OVERFLOWED)) + { + *(uint32_t *)bfwrite.pOutByte = (data << bfwrite.nCurOutputBit) | *(uint32_t *)bfwrite.pOutByte & ROWBITTABLE[bfwrite.nCurOutputBit]; + int leftBits = 32 - bfwrite.nCurOutputBit; + bfwrite.nCurOutputBit = bits & 7; + bfwrite.pOutByte += 4; + *(uint32_t *)bfwrite.pOutByte = data >> leftBits; + } + } +} + +void MSG_WriteSBits(int data, int numbits) +{ + int idata = data; + + if (numbits < 32) + { + int maxnum = (1 << (numbits - 1)) - 1; + + if (data > maxnum || (maxnum = -maxnum, data < maxnum)) + { + idata = maxnum; + } + } + + int sigbits = idata < 0; + + MSG_WriteOneBit(sigbits); + MSG_WriteBits(abs(idata), numbits - 1); +} + +void MSG_WriteBitString(const char *p) +{ + char *pch = (char *)p; + + while (*pch) + { + MSG_WriteBits(*pch, 8); + ++pch; + } + + MSG_WriteBits(0, 8); +} + +void MSG_WriteBitData(void *src, int length) +{ + int i; + byte *p = (byte *)src; + + for (i = 0; i < length; i++, p++) + { + MSG_WriteBits(*p, 8); + } +} + +void MSG_WriteBitAngle(float fAngle, int numbits) +{ + if (numbits >= 32) + { + Sys_Error(__FUNCTION__ ": Can't write bit angle with 32 bits precision\n"); + } + + uint32_t shift = (1 << numbits); + uint32_t mask = shift - 1; + + int d = (int)(shift * fmod((double)fAngle, 360.0)) / 360; + d &= mask; + + MSG_WriteBits(d, numbits); +} + +float MSG_ReadBitAngle(int numbits) +{ + return (float)(MSG_ReadBits(numbits) * (360.0 / (1 << numbits))); +} + +int MSG_CurrentBit(void) +{ + int nbits; + + if (bfread.pbuf) + { + nbits = bfread.nCurInputBit + 8 * bfread.nBytesRead; + } + else + { + nbits = 8 * msg_readcount; + } + return nbits; +} + +NOXREF qboolean MSG_IsBitReading(void) +{ + NOXREFCHECK; + + return bfread.pbuf != 0; +} + +void MSG_StartBitReading(sizebuf_t *buf) +{ + bfread.nCurInputBit = 0; + bfread.nBytesRead = 0; + bfread.nBitFieldReadStartByte = msg_readcount; + bfread.pbuf = buf; + bfread.pInByte = &buf->data[msg_readcount]; + bfread.nMsgReadCount = msg_readcount + 1; + + if (msg_readcount + 1 > buf->cursize) + { + msg_badread = 1; + } +} + +void MSG_EndBitReading(sizebuf_t *buf) +{ + if (bfread.nMsgReadCount > buf->cursize) + { + msg_badread = 1; + } + + msg_readcount = bfread.nMsgReadCount; + bfread.nBitFieldReadStartByte = 0; + bfread.nCurInputBit = 0; + bfread.nBytesRead = 0; + bfread.pInByte = 0; + bfread.pbuf = 0; +} + +int MSG_ReadOneBit(void) +{ + int nValue; + + if (msg_badread) + { + nValue = 1; + } + else + { + if (bfread.nCurInputBit >= 8) + { + ++bfread.nMsgReadCount; + bfread.nCurInputBit = 0; + ++bfread.nBytesRead; + ++bfread.pInByte; + } + + if (bfread.nMsgReadCount <= bfread.pbuf->cursize) + { + nValue = (*bfread.pInByte & BITTABLE[bfread.nCurInputBit]) != 0; + ++bfread.nCurInputBit; + } + else + { + nValue = 1; + msg_badread = 1; + } + } + + return nValue; +} + +uint32_t MSG_ReadBits(int numbits) +{ + uint32_t result; + + if (msg_badread) + { + result = 1; + } + else + { + if (bfread.nCurInputBit >= 8) + { + ++bfread.nMsgReadCount; + ++bfread.nBytesRead; + ++bfread.pInByte; + + bfread.nCurInputBit = 0; + } + + uint32_t bits = (bfread.nCurInputBit + numbits) & 7; + + if ((unsigned int)(bfread.nCurInputBit + numbits) <= 32) + { + result = (*(unsigned int *)bfread.pInByte >> bfread.nCurInputBit) & ROWBITTABLE[numbits]; + + uint32_t bytes = (bfread.nCurInputBit + numbits) >> 3; + + if (bits) + { + bfread.nCurInputBit = bits; + } + else + { + bfread.nCurInputBit = 8; + bytes--; + } + + bfread.pInByte += bytes; + bfread.nMsgReadCount += bytes; + bfread.nBytesRead += bytes; + } + else + { + result = ((*(unsigned int *)(bfread.pInByte + 4) & ROWBITTABLE[bits]) << (32 - bfread.nCurInputBit)) | (*(unsigned int *)bfread.pInByte >> bfread.nCurInputBit); + bfread.nCurInputBit = bits; + bfread.pInByte += 4; + bfread.nMsgReadCount += 4; + bfread.nBytesRead += 4; + } + + if (bfread.nMsgReadCount > bfread.pbuf->cursize) + { + result = 1; + msg_badread = 1; + } + } + + return result; +} + +NOXREF uint32_t MSG_PeekBits(int numbits) +{ + NOXREFCHECK; + + bf_read_t savebf = bfread; + uint32_t r = MSG_ReadBits(numbits); + bfread = savebf; + + return r; +} + +int MSG_ReadSBits(int numbits) +{ + int nSignBit = MSG_ReadOneBit(); + int result = MSG_ReadBits(numbits - 1); + + if (nSignBit) + { + result = -result; + } + + return result; +} + +NOXREF char *MSG_ReadBitString(void) +{ + NOXREFCHECK; + + static char buf[8192]; + + char *p = &buf[0]; + + for (char c = MSG_ReadBits(8); c; c = MSG_ReadBits(8)) + { +#ifdef REHLDS_FIXES + if (msg_badread) // Prevent infinite cycle if msg_badread + { + break; + } +#endif + *p++ = c; + } + + *p = 0; + + return buf; +} + +int MSG_ReadBitData(void *dest, int length) +{ + if (length > 0) + { + int i = length; + unsigned char * p = (unsigned char *)dest; + + do + { + *p = (unsigned char)MSG_ReadBits(8); + p++; + --i; + } + while (i); + } + + return length; +} + +NOXREF float MSG_ReadBitCoord(void) +{ + NOXREFCHECK; + + float value = 0; + + int intval = MSG_ReadOneBit(); + int fractval = MSG_ReadOneBit(); + + if (intval || fractval) + { + int signbit = MSG_ReadOneBit(); + + if (intval) + { + intval = MSG_ReadBits(12); + } + + if (fractval) + { + fractval = MSG_ReadBits(3); + } + + value = (float)(fractval / 8.0 + intval); + + if (signbit) + { + value = -value; + } + } + + return value; +} + +void MSG_WriteBitCoord(const float f) +{ + int signbit = f <= -0.125; + int intval = abs((int32_t)f); + int fractval = abs((int32_t)f * 8) & 7; + + MSG_WriteOneBit(intval); + MSG_WriteOneBit(fractval); + + if (intval || fractval) + { + MSG_WriteOneBit(signbit); + if (intval) + MSG_WriteBits(intval, 12); + if (fractval) + MSG_WriteBits(fractval, 3); + } +} + +NOXREF void MSG_ReadBitVec3Coord(vec3_t fa) +{ + NOXREFCHECK; + + int xflag = MSG_ReadOneBit(); + int yflag = MSG_ReadOneBit(); + int zflag = MSG_ReadOneBit(); + + if (xflag) + fa[0] = MSG_ReadBitCoord(); + if (yflag) + fa[1] = MSG_ReadBitCoord(); + if (zflag) + fa[2] = MSG_ReadBitCoord(); +} + +void MSG_WriteBitVec3Coord(const vec3_t fa) +{ + bool xflag = fa[0] <= -0.125 || fa[0] >= 0.125; + bool yflag = fa[1] <= -0.125 || fa[1] >= 0.125; + bool zflag = fa[2] <= -0.125 || fa[2] >= 0.125; + + MSG_WriteOneBit(xflag); + MSG_WriteOneBit(yflag); + MSG_WriteOneBit(zflag); + + if (xflag) + MSG_WriteBitCoord(fa[0]); + if (yflag) + MSG_WriteBitCoord(fa[1]); + if (zflag) + MSG_WriteBitCoord(fa[2]); +} + +NOXREF float MSG_ReadCoord(void) +{ + NOXREFCHECK; + + return (float)(MSG_ReadShort() * (1.0 / 8)); +} + +void MSG_WriteCoord(sizebuf_t *sb, const float f) +{ + MSG_WriteShort(sb, (int)(f * 8.0)); +} + +NOXREF void MSG_ReadVec3Coord(sizebuf_t *sb, vec3_t fa) +{ + NOXREFCHECK; + + if (MSG_IsBitReading()) + { + MSG_ReadBitVec3Coord(fa); + } + else + { + MSG_StartBitReading(sb); + MSG_ReadBitVec3Coord(fa); + MSG_EndBitReading(sb); + } +} + +NOXREF void MSG_WriteVec3Coord(sizebuf_t *sb, const vec3_t fa) +{ + NOXREFCHECK; + + MSG_StartBitWriting(sb); + MSG_WriteBitVec3Coord(fa); + MSG_EndBitWriting(sb); +} + +void MSG_BeginReading(void) +{ + msg_readcount = 0; + msg_badread = 0; +} + +int MSG_ReadChar(void) +{ + int c; + + if (msg_readcount < net_message.cursize) + { + c = net_message.data[msg_readcount]; + msg_readcount++; + } + else + { + msg_badread = 1; + c = -1; + } + + return c; +} + +int MSG_ReadByte(void) +{ + int c; + + if (msg_readcount < net_message.cursize) + { + c = net_message.data[msg_readcount]; + msg_readcount++; + } + else + { + msg_badread = 1; + c = -1; + } + + return c; +} + +int MSG_ReadShort(void) +{ + int c; + + if (msg_readcount + 2 <= net_message.cursize ) + { + c = *(int16_t *)&net_message.data[msg_readcount]; + msg_readcount += 2; + } + else + { + msg_badread = 1; + c = -1; + } + + return c; +} + +NOXREF int MSG_ReadWord(void) +{ + NOXREFCHECK; + + int c; + + if (msg_readcount + 2 <= net_message.cursize) + { + c = *(uint16_t *)&net_message.data[msg_readcount]; + msg_readcount += 2; + } + else + { + msg_badread = 1; + c = -1; + } + + return c; +} + +int MSG_ReadLong(void) +{ + int c; + + if (msg_readcount + 4 <= net_message.cursize) + { + c = *(uint32_t *)&net_message.data[msg_readcount]; + msg_readcount += 4; + } + else + { + msg_badread = 1; + c = -1; + } + + return c; +} + +NOXREF float MSG_ReadFloat(void) +{ + NOXREFCHECK; + + float f; + + if (msg_readcount + 4 <= net_message.cursize) + { + f = *((float*)LittleLong(*(int *)&net_message.data[msg_readcount])); + msg_readcount += 4; + } + else + { + msg_badread = 1; + f = -1.0; + } + + return f; +} + +int MSG_ReadBuf(int iSize, void *pbuf) +{ + if (msg_readcount + iSize <= net_message.cursize) + { + Q_memcpy(pbuf, &net_message.data[msg_readcount], iSize); + msg_readcount += iSize; + + return 1; + } + + msg_badread = 1; + return -1; +} + +char *MSG_ReadString(void) +{ + int c = 0, l = 0; + static char string[8192]; + + while ((c = MSG_ReadChar(), c) && c != -1 && l < ARRAYSIZE(string) - 1) + { + string[l++] = c; + } + string[l] = 0; + + return string; +} + +char *MSG_ReadStringLine(void) +{ + int c = 0, l = 0; + static char string[2048]; + + while ((c = MSG_ReadChar(), c) && c != '\n' && c != -1 && l < ARRAYSIZE(string) - 1) + { + string[l++] = c; + } + string[l] = 0; + + return string; +} + +NOXREF float MSG_ReadAngle(void) +{ + NOXREFCHECK; + + int c = MSG_ReadChar(); +#ifdef REHLDS_FIXES + if (c == -1) // FIXED: Added check for wrong value, but just return 0 instead of -1 * (360.0 / 256) + { + return 0; + } +#endif + return (float)(c * (360.0 / 256)); +} + +NOXREF float MSG_ReadHiresAngle(void) +{ + NOXREFCHECK; + + int c = MSG_ReadShort(); +#ifdef REHLDS_FIXES + if (c == -1) // FIXED: Added check for wrong value, but just return 0 instead of -1 * (360.0 / 65536) + { + return 0; + } +#endif + return (float)(MSG_ReadShort() * (360.0 / 65536)); +} + +void MSG_ReadUsercmd(usercmd_t *to, usercmd_t* from) +{ + delta_t *pdesc = SV_LookupDelta("usercmd_t"); + MSG_StartBitReading(&net_message); + DELTA_ParseDelta((byte *)from, (byte *)to, pdesc); + MSG_EndBitReading(&net_message); + COM_NormalizeAngles(to->viewangles); +} + +#endif // MSG_Functions_region + + +#ifndef SZ_Functions_region + +void SZ_Alloc(const char *name, sizebuf_t *buf, int startsize) +{ + buf->buffername = name; + + if (startsize < 256) + { + startsize = 256; + } + + buf->data = (byte *)Hunk_AllocName(startsize, name); + buf->maxsize = startsize; + buf->cursize = 0; + buf->flags = SIZEBUF_CHECK_OVERFLOW; +} + +void SZ_Clear(sizebuf_t *buf) +{ + buf->flags &= ~SIZEBUF_OVERFLOWED; + buf->cursize = 0; +} + +void *SZ_GetSpace(sizebuf_t *buf, int length) +{ + void *data; + const char *buffername = buf->buffername ? buf->buffername : "???"; + + if (length < 0) + { + Sys_Error(__FUNCTION__ ": %i negative length on %s", length, buffername); + } + + if (buf->cursize + length > buf->maxsize) + { +#ifdef REHLDS_FIXES + if (!(buf->flags & SIZEBUF_ALLOW_OVERFLOW)) + { + if (!buf->maxsize) + { + Sys_Error(__FUNCTION__ ": tried to write to an uninitialized sizebuf_t: %s", buffername); + } + else if (length > buf->maxsize) + { + Sys_Error(__FUNCTION__ ": %i is > full buffer size on %s", length, buffername); + } + else + { + Sys_Error(__FUNCTION__ ": overflow without FSB_ALLOWOVERFLOW set on %s", buffername); + } + } + + if (length > buf->maxsize) + { + Con_DPrintf(__FUNCTION__ ": %i is > full buffer size on %s, ignoring", length, buffername); + } +#else // REHLDS_FIXES + if (!(buf->flags & SIZEBUF_ALLOW_OVERFLOW)) + { + if (!buf->maxsize) + { + Sys_Error(__FUNCTION__ ": Tried to write to an uninitialized sizebuf_t: %s", buffername); + } + else + { + Sys_Error(__FUNCTION__ ": overflow without FSB_ALLOWOVERFLOW set on %s", buffername); + } + } + + if (length > buf->maxsize) + { + if (!(buf->flags & SIZEBUF_ALLOW_OVERFLOW)) + { + Sys_Error(__FUNCTION__ ": %i is > full buffer size on %s", length, buffername); + } + + Con_DPrintf(__FUNCTION__ ": %i is > full buffer size on %s, ignoring", length, buffername); + } +#endif // REHLDS_FIXES + + Con_Printf(__FUNCTION__ ": overflow on %s\n", buffername); + + SZ_Clear(buf); + buf->flags |= SIZEBUF_OVERFLOWED; + } + + data = &buf->data[buf->cursize]; + buf->cursize = length + buf->cursize; + + return data; +} + +void SZ_Write(sizebuf_t *buf, const void *data, int length) +{ + unsigned char *pData = (unsigned char *)SZ_GetSpace(buf, length); + + if (!(buf->flags & SIZEBUF_OVERFLOWED)) + { + Q_memcpy(pData, data, length); + } +} + +void SZ_Print(sizebuf_t *buf, const char *data) +{ + unsigned char *pData; + int len = Q_strlen(data) + 1; + + if (buf->data[buf->cursize - 1]) + { + pData = (unsigned char *)SZ_GetSpace(buf, len); + } + else + { + pData = (unsigned char *)SZ_GetSpace(buf, len - 1) - 1; + } + + if (!(buf->flags & SIZEBUF_OVERFLOWED)) + { + Q_memcpy(pData, data, len); + } +} + +#endif // SZ_Functions_region + + +#ifndef COM_Functions_region + +int com_argc; +char **com_argv; + +char com_token[COM_TOKEN_LEN]; + +qboolean com_ignorecolons; +qboolean s_com_token_unget; +char *com_last_in_quotes_data = NULL; +char com_clientfallback[MAX_PATH]; +char com_gamedir[MAX_PATH]; +char com_cmdline[COM_MAX_CMD_LINE]; + +cache_user_t *loadcache; +unsigned char *loadbuf; +int loadsize; + +const unsigned char mungify_table[] = +{ + 0x7A, 0x64, 0x05, 0xF1, + 0x1B, 0x9B, 0xA0, 0xB5, + 0xCA, 0xED, 0x61, 0x0D, + 0x4A, 0xDF, 0x8E, 0xC7 +}; + +const unsigned char mungify_table2[] = +{ + 0x05, 0x61, 0x7A, 0xED, + 0x1B, 0xCA, 0x0D, 0x9B, + 0x4A, 0xF1, 0x64, 0xC7, + 0xB5, 0x8E, 0xDF, 0xA0 +}; + +unsigned char mungify_table3[] = +{ + 0x20, 0x07, 0x13, 0x61, + 0x03, 0x45, 0x17, 0x72, + 0x0A, 0x2D, 0x48, 0x0C, + 0x4A, 0x12, 0xA9, 0xB5 +}; + + +/* <1118a> ../engine/common.c:1808 */ +NOXREF char *COM_SkipPath(char *pathname) +{ + NOXREFCHECK; + + char *last = pathname; + + while (*pathname) + { + if (*pathname == '/' || *pathname == '\\') + last = pathname + 1; + pathname++; + } + return last; +} + +/* <111c8> ../engine/common.c:1827 */ +void COM_StripExtension(char *in, char *out) +{ + char *c, *d = NULL; + int i; + + // Search for the first dot after the last path separator + c = in; + while (*c) + { + if (*c == '/' || *c == '\\') + { + d = NULL; // reset dot location on path separator + } + else if (d == NULL && *c == '.') + { + d = c; // store first dot location in the file name + } + c++; + } + + if (out == in) + { + if (d != NULL) + { + *d = 0; + } + } + else + { + if (d != NULL) + { + i = d - in; + Q_memcpy(out, in, i); + out[i] = 0; + } + else + { + Q_strcpy(out, in); + } + } +} + +/* <11285> ../engine/common.c:1855 */ +char *COM_FileExtension(char *in) +{ + static char exten[MAX_PATH]; + char *c, *d = NULL; + int i; + + // Search for the first dot after the last path separator + c = in; + while (*c) + { + if (*c == '/' || *c == '\\') + { + d = NULL; // reset dot location on path separator + } + else if (d == NULL && *c == '.') + { + d = c; // store first dot location in the file name + } + c++; + } + + if (d == NULL) + { + return ""; + } + + d++; // skip dot + // Copy extension + for (i = 0; i < (ARRAYSIZE(exten) - 1) && *d; i++, d++) + { + exten[i] = *d; + } + exten[i] = 0; + + return exten; +} + +/* <112d2> ../engine/common.c:1877 */ +/// Fills "out" with the file name without path and extension. +void COM_FileBase(const char *in, char *out) +{ + const char *start, *end; + int len; + + *out = 0; + + len = Q_strlen(in); + if (len <= 0) + return; + + start = in + len - 1; + end = in + len; + while (start >= in && *start != '/' && *start != '\\') + { + if (*start == '.') + end = start; + start--; + } + start++; + + len = end - start; + Q_strncpy(out, start, len); + out[len] = 0; +} + +/* <11396> ../engine/common.c:1922 */ +void COM_DefaultExtension(char *path, char *extension) +{ + char *src; + src = path + Q_strlen(path) - 1; + + while (*src != '/' && *src != '\\' && src != path) + { + if (*src == '.') + { + return; + } + + src--; + } + + Q_strcat(path, extension); +} + +/* <11407> ../engine/common.c:1948 */ +void COM_UngetToken(void) +{ + s_com_token_unget = 1; +} + +/* <1141c> ../engine/common.c:1960 */ +char *COM_Parse(char *data) +{ + int c; + uchar32 wchar; + int len; + + if (s_com_token_unget) + { + s_com_token_unget = 0; + return data; + } + + len = 0; + com_token[0] = 0; + + if (!data) + { + return NULL; + } + + if (com_last_in_quotes_data == data) + { + // continue to parse quoted string + com_last_in_quotes_data = NULL; + goto inquotes; + } + +skipwhite: + // skip whitespace + while (!V_UTF8ToUChar32(data, &wchar) && wchar <= 32) + { + if (!wchar) + return NULL; + data = Q_UnicodeAdvance(data, 1); + } + + c = *data; + + // skip // comments till the next line + if (c == '/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; // start over new line + } + + // handle quoted strings specially: copy till the end or another quote + if (c == '\"') + { + data++; // skip starting quote + while (true) + { +inquotes: + c = *data++; // get char and advance + if (!c) // EOL + { + com_token[len] = 0; + return data - 1; // we are done with that, but return data to show that token is present + } + if (c == '\"') // closing quote + { + com_token[len] = 0; + return data; + } + + com_token[len] = c; + len++; + + if (len == COM_TOKEN_LEN - 1) // check if buffer is full + { + // remember in-quotes state + com_last_in_quotes_data = data; + + com_token[len] = 0; + return data; + } + } + } + + // parse single characters + if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' || (!com_ignorecolons && c == ':')) + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data + 1; + } + + // parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ',' || (!com_ignorecolons && c == ':')) + break; + } while (len < COM_TOKEN_LEN - 1 && (c < 0 || c > 32)); + + com_token[len] = 0; + return data; +} + +/* <11495> ../engine/common.c:2049 */ +char *COM_ParseLine(char *data) +{ + int c; + int len; + + if (s_com_token_unget) + { + s_com_token_unget = 0; + return data; + } + + len = 0; + com_token[0] = 0; + + if (!data) + { + return NULL; + } + + c = *data; // TODO: data is signed, so will c, next check for >= ' ' will fail for upper ASCII + + // parse a line out of the data + do + { + com_token[len] = c; // TODO: Here c may be any ASCII, \n for example, but we are copy it in the token + data++; + len++; + c = *data; + } while (c >= ' ' && (len < COM_TOKEN_LEN - 1)); // TODO: Will break on \t, may be it shouldn't? + + com_token[len] = 0; + + if (c == 0) // end of file + { + return NULL; + } + + // eat whitespace (LF,CR,etc.) at the end of this line + while ((c = *data) < ' ') + { + if (c == 0) + { + return NULL; // end of file; + } + data++; + } + + return data; +} + +/* <114e2> ../engine/common.c:2100 */ +int COM_TokenWaiting(char *buffer) +{ + char *p; + + p = buffer; + while (*p && *p != '\n') + { + if (!isspace(*p) || isalnum(*p)) + return 1; + + p++; + } + + return 0; +} + +/* <1151e> ../engine/common.c:2125 */ +int COM_CheckParm(char *parm) +{ + int i; + + for (i = 1 ; i < com_argc; i++) + { + if (!com_argv[i]) + { + continue; + } + + if (!Q_strcmp(parm, (const char*)com_argv[i])) + { + return i; + } + } + + return 0; +} + +/* <11592> ../engine/common.c:2145 */ +void COM_InitArgv(int argc, char *argv[]) +{ + qboolean safe = 0; + + static char *safeargvs[NUM_SAFE_ARGVS] = + { + "-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly" + }; + static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1]; + + int i, j; + char *c; + + // Reconstruct full command line + com_cmdline[0] = 0; + for (i = 0, j = 0; i < MAX_NUM_ARGVS && i < argc && j < COM_MAX_CMD_LINE - 1; i++) + { + c = argv[i]; + if (*c) + { + while (*c && j < COM_MAX_CMD_LINE - 1) + { + com_cmdline[j++] = *c++; + } + if (j >= COM_MAX_CMD_LINE - 1) + { + break; + } + com_cmdline[j++] = ' '; + } + } + com_cmdline[j] = 0; + + // Copy args pointers to our array + for (com_argc = 0; (com_argc < MAX_NUM_ARGVS) && (com_argc < argc); com_argc++) + { + largv[com_argc] = argv[com_argc]; + + if (!Q_strcmp("-safe", argv[com_argc])) + { + safe = 1; + } + } + + // Add arguments introducing more failsafeness + if (safe) + { + // force all the safe-mode switches. Note that we reserved extra space in + // case we need to add these, so we don't need an overflow check + for (int i = 0; i < NUM_SAFE_ARGVS; i++) + { + largv[com_argc] = safeargvs[i]; + com_argc++; + } + } + + largv[com_argc] = " "; + com_argv = largv; +} + +/* <11628> ../engine/common.c:2204 */ +void COM_Init(char *basedir) +{ + unsigned short swaptest = 1; + + if (*(byte *)&swaptest == 1) + { + bigendien = 0; + BigShort = ShortSwap; + LittleShort = ShortNoSwap; + BigLong = LongSwap; + LittleLong = LongNoSwap; + BigFloat = FloatSwap; + LittleFloat = FloatNoSwap; + } + else + { + bigendien = 1; + BigShort = ShortNoSwap; + LittleShort = ShortSwap; + BigLong = LongNoSwap; + LittleLong = LongSwap; + BigFloat = FloatNoSwap; + LittleFloat = FloatSwap; + } + + COM_BitOpsInit(); +} + +/* <116ca> ../engine/common.c:2242 */ +char *va(char *format, ...) +{ + va_list argptr; + static int current = 0; + static char string[16][1024]; + + current = (current + 1) % 16; + + va_start(argptr, format); + Q_vsnprintf(string[current], ARRAYSIZE(string[current]), format, argptr); + va_end(argptr); + + return string[current]; +} + +/* <11743> ../engine/common.c:2267 */ +NOXREF char *vstr(vec_t *v) +{ + NOXREFCHECK; + + static int idx = 0; + static char string[16][1024]; + + idx++; + idx &= 15; + + Q_snprintf(string[idx], ARRAYSIZE(string[idx]), "%.4f %.4f %.4f", v[0], v[1], v[2]); + return string[idx]; +} + +/* <117aa> ../engine/common.c:2280 */ +NOXREF int memsearch(unsigned char *start, int count, int search) +{ + NOXREFCHECK; + + for (int i = 0; i < count; i++) + { + if (start[i] == search) + { + return i; + } + } + + return -1; +} + +/* <11838> ../engine/common.c:2308 */ +NOXREF void COM_WriteFile(char *filename, void *data, int len) +{ + NOXREFCHECK; + + char path[MAX_PATH]; + Q_snprintf(path, MAX_PATH - 1, "%s", filename); + path[MAX_PATH - 1] = 0; + + COM_FixSlashes(path); + COM_CreatePath(path); + + FileHandle_t fp = FS_Open(path, "wb"); + + if (fp) + { + Sys_Printf(__FUNCTION__ ": %s\n", path); + FS_Write(data, len, 1, fp); + FS_Close(fp); + } + else + { + Sys_Printf(__FUNCTION__ ": failed on %s\n", path); + } +} + +/* ../engine/common.c:2338 */ +void COM_FixSlashes(char *pname) +{ + while (*pname) + { +#ifdef _WIN32 + if (*pname == '/') + { + *pname = '\\'; + } +#else + if (*pname == '\\') + { + *pname = '/'; + } +#endif + + pname++; + } +} + +/* <11804> ../engine/common.c:2362 */ +void COM_CreatePath(char *path) +{ + char *ofs; + char old; + + if (*path == 0) + { + return; + } + + for (ofs = path + 1; *ofs; ofs++) + { + if (*ofs == '/' || *ofs == '\\') + { + old = *ofs; + *ofs = 0; + FS_CreateDirHierarchy(path, 0); + *ofs = old; + } + } +} + +/* <1193e> ../engine/common.c:2388 */ +NOXREF void COM_CopyFile(char *netpath, char *cachepath) +{ + NOXREFCHECK; + + int count; + int remaining; + char buf[4096]; + + FileHandle_t out; + FileHandle_t in = FS_Open(netpath, "rb"); + + if (!in) + { + return; + } + + count = FS_Size(in); + COM_CreatePath(cachepath); + + for (out = FS_Open(cachepath, "wb"); count; count -= remaining) + { + remaining = count; + + if (remaining > 4096) + { + remaining = 4096; + } + + FS_Read(buf, remaining, 1, in); + FS_Write(buf, remaining, 1, out); + } + + FS_Close(in); + FS_Close(out); +} + +/* <119f8> ../engine/common.c:2426 */ +NOXREF int COM_ExpandFilename(char *filename) +{ + NOXREFCHECK; + + char netpath[MAX_PATH]; + + FS_GetLocalPath(filename, netpath, ARRAYSIZE(netpath)); + strcpy(filename, netpath); + return *filename != 0; +} + +/* <11a36> ../engine/common.c:2446 */ +int COM_FileSize(char *filename) +{ + FileHandle_t fp; + int iSize; + + iSize = -1; + fp = FS_Open(filename, "rb"); + if (fp) + { + iSize = FS_Size(fp); + FS_Close(fp); + } + return iSize; +} + +/* <11a83> ../engine/common.c:2472 */ +unsigned char *COM_LoadFile(const char *path, int usehunk, int *pLength) +{ + char base[33]; + unsigned char *buf = NULL; + +#ifndef SWDS + g_engdstAddrs->COM_LoadFile(&path, &usehunk, &pLength); +#endif + + if (pLength) + { + *pLength = 0; + } + + FileHandle_t hFile = FS_Open(path, "rb"); + + if (!hFile) + { + return NULL; + } + + int len = FS_Size(hFile); + COM_FileBase(path, base); + base[32] = 0; + + switch (usehunk) + { + case 0: + buf = (unsigned char *)Z_Malloc(len + 1); + break; + + case 1: + buf = (unsigned char *)Hunk_AllocName(len + 1, base); + break; + + case 2: + buf = (unsigned char *)Hunk_TempAlloc(len + 1); + break; + + case 3: + buf = (unsigned char *)Cache_Alloc(loadcache, len + 1, base); + break; + + case 4: + if (len + 1 <= loadsize) + { + buf = loadbuf; + } + else + { + buf = (unsigned char *)Hunk_TempAlloc(len + 1); + } + break; + + case 5: + buf = (unsigned char *)Mem_Malloc(len + 1); + break; + + default: + Sys_Error(__FUNCTION__ ": bad usehunk"); + } + + if (!buf) + { + FS_Close(hFile); + Sys_Error(__FUNCTION__ ": not enough space for %s", path); + } + + FS_Read(buf, len, 1, hFile); + FS_Close(hFile); + + buf[len] = 0; + + if (pLength) + { + *pLength = len; + } + + return buf; +} + +/* <11b0f> ../engine/common.c:2538 */ +void COM_FreeFile(void *buffer) +{ +#ifndef SWDS + g_engdstAddrs->COM_FreeFile(); +#endif + + if (buffer) + { + Mem_Free(buffer); + } +} + +/* <11b39> ../engine/common.c:2554 */ +void COM_CopyFileChunk(FileHandle_t dst, FileHandle_t src, int nSize) +{ + int copysize; + char copybuf[COM_COPY_CHUNK_SIZE]; + + copysize = nSize; + + while (copysize > COM_COPY_CHUNK_SIZE) + { + FS_Read(copybuf, 1, COM_COPY_CHUNK_SIZE, src); + FS_Write(copybuf, 1, COM_COPY_CHUNK_SIZE, dst); + copysize -= COM_COPY_CHUNK_SIZE; + } + + FS_Read(copybuf, copysize, 1, src); + FS_Write(copybuf, copysize, 1, dst); + FS_Flush(src); + FS_Flush(dst); +} + +/* <11ba1> ../engine/common.c:2589 */ +NOXREF unsigned char *COM_LoadFileLimit(char *path, int pos, int cbmax, int *pcbread, FileHandle_t *phFile) +{ + FileHandle_t hFile; + unsigned char *buf; + char base[32]; + int len; + int cbload; + + hFile = *phFile; + if (!hFile) + { + hFile = FS_Open(path, "rb"); + if (!hFile) + return NULL; + } + + len = FS_Size(hFile); + if (len < pos) + Sys_Error("COM_LoadFileLimit: invalid seek position for %s", path); + + FS_Seek(hFile, pos, FILESYSTEM_SEEK_HEAD); + + if (len > cbmax) + cbload = cbmax; + else + cbload = len; + + *pcbread = cbload; + + if (path) + COM_FileBase(path, base); + + buf = (unsigned char *)Hunk_TempAlloc(cbload + 1); + if (!buf) + { + if (path) + Sys_Error("COM_LoadFileLimit: not enough space for %s", path); + + FS_Close(hFile); + return NULL; + } + + buf[cbload] = 0; + FS_Read(buf, cbload, 1, hFile); + *phFile = hFile; + + return buf; +} + +/* <11c60> ../engine/common.c:2647 */ +unsigned char *COM_LoadHunkFile(char *path) +{ + return COM_LoadFile(path, 1, NULL); +} + +/* <11c8e> ../engine/common.c:2652 */ +unsigned char *COM_LoadTempFile(char *path, int *pLength) +{ + return COM_LoadFile(path, 2, pLength); +} + +/* <11ccb> ../engine/common.c:2657 */ +void COM_LoadCacheFile(char *path, struct cache_user_s *cu) +{ + loadcache = cu; + COM_LoadFile(path, 3, 0); +} + +/* <11d09> ../engine/common.c:2664 */ +NOXREF unsigned char *COM_LoadStackFile(char *path, void *buffer, int bufsize, int *length) +{ + NOXREFCHECK; + + loadbuf = (unsigned char *)buffer; + loadsize = bufsize; + + return COM_LoadFile(path, 4, length); +} + +/* <11d6f> ../engine/common.c:2682 */ +void COM_Shutdown(void) +{ + // Do nothing. +} + +/* <11d84> ../engine/common.c:2693 */ +NOXREF void COM_AddAppDirectory(char *pszBaseDir, const char *appName) +{ + NOXREFCHECK; + + FS_AddSearchPath(pszBaseDir, "PLATFORM"); +} + +/* <11dbc> ../engine/common.c:2707 */ +void COM_AddDefaultDir(char *pszDir) +{ + if (pszDir && *pszDir) + { + FileSystem_AddFallbackGameDir(pszDir); + } +} + +/* <11de5> ../engine/common.c:2715 */ +void COM_StripTrailingSlash(char *ppath) +{ + int len = Q_strlen(ppath); + + if (len > 0) + { + if ((ppath[len - 1] == '\\') || (ppath[len - 1] == '/')) + { + ppath[len - 1] = 0; + } + } +} + +/* <11e34> ../engine/common.c:2729 */ +void COM_ParseDirectoryFromCmd(const char *pCmdName, char *pDirName, const char *pDefault) +{ + const char *pParameter = NULL; + int cmdParameterIndex = COM_CheckParm((char *)pCmdName); + + if (cmdParameterIndex && cmdParameterIndex < com_argc - 1) + { + pParameter = com_argv[cmdParameterIndex + 1]; + + if (*pParameter == '-' || *pParameter == '+') + { + pParameter = NULL; + } + } + + // Found a valid parameter on the cmd line? + if (pParameter) + { + // Grab it + strcpy(pDirName, pParameter); + } + else if (pDefault) + { + // Ok, then use the default + strcpy(pDirName, pDefault); + } + else + { + // If no default either, then just terminate the string + pDirName[0] = 0; + } + + COM_StripTrailingSlash(pDirName); +} + +// TODO: finish me! +/* <11f12> ../engine/common.c:2766 */ +qboolean COM_SetupDirectories(void) +{ + char pDirName[512]; + + com_clientfallback[0] = 0; + com_gamedir[0] = 0; + + COM_ParseDirectoryFromCmd("-basedir", pDirName, "valve"); + COM_ParseDirectoryFromCmd("-game", com_gamedir, pDirName); + + if (FileSystem_SetGameDirectory(pDirName, (const char *)(com_gamedir[0] != 0 ? com_gamedir : 0))) + { + Info_SetValueForStarKey(Info_Serverinfo(), "*gamedir", com_gamedir, MAX_INFO_STRING); + + return 1; + } + + return 0; +} + +/* ../engine/common.c:2796 */ +void COM_CheckPrintMap(dheader_t *header, const char *mapname, qboolean bShowOutdated) +{ + if (header->version == BSPVERSION) + { + if (!bShowOutdated) + { + Con_Printf("%s\n", mapname); + } + } + else + { + if (bShowOutdated) + { + Con_Printf("OUTDATED: %s\n", mapname); + } + } +} + +/* <11f41> ../engine/common.c:2821 */ +void COM_ListMaps(char *pszSubString) +{ + dheader_t header; + FileHandle_t fp; + + char mapwild[64]; + char curDir[4096]; + char pFileName[64]; + const char *findfn; + + int nSubStringLen = 0; + + if (pszSubString && *pszSubString) + { + nSubStringLen = Q_strlen(pszSubString); + } + + Con_Printf("-------------\n"); + + for (int bShowOutdated = 1; bShowOutdated >= 0; bShowOutdated--) + { + Q_strcpy(mapwild, "maps/*.bsp"); + findfn = Sys_FindFirst(mapwild, NULL); + + while (findfn != NULL) + { + Q_snprintf(curDir, ARRAYSIZE(curDir), "maps/%s", findfn); + FS_GetLocalPath(curDir, curDir, ARRAYSIZE(curDir)); + + if (strstr(curDir, com_gamedir) && (!nSubStringLen || !Q_strnicmp(findfn, pszSubString, nSubStringLen))) + { + Q_memset(&header, 0, sizeof(dheader_t)); + Q_sprintf(pFileName, "maps/%s", findfn); + + fp = FS_Open(pFileName, "rb"); + + if (fp) + { + FS_Read(&header, sizeof(dheader_t), 1, fp); + FS_Close(fp); + } + + COM_CheckPrintMap(&header, findfn, bShowOutdated != 0); + } + + findfn = Sys_FindNext(NULL); + } + + Sys_FindClose(); + } +} + +/* <1202d> ../engine/common.c:2873 */ +void COM_Log(char *pszFile, char *fmt, ...) +{ + char *pfilename; + char string[1024]; + + if (!pszFile) + { + // Why so serious? + pfilename = "c:\\hllog.txt"; + } + else + { + pfilename = pszFile; + } + + va_list argptr; + va_start(argptr, fmt); + Q_vsnprintf(string, ARRAYSIZE(string) - 1, fmt, argptr); + va_end(argptr); + + string[ARRAYSIZE(string) - 1] = 0; + + FileHandle_t fp = FS_Open(pfilename, "a+t"); + + if (fp) + { + FS_FPrintf(fp, "%s", string); + FS_Close(fp); + } +} + +/* <120a6> ../engine/common.c:2900 */ +unsigned char *COM_LoadFileForMe(char *filename, int *pLength) +{ + return COM_LoadFile(filename, 5, pLength); +} + +/* <120e3> ../engine/common.c:2905 */ +int COM_CompareFileTime(char *filename1, char *filename2, int *iCompare) +{ + int ft1; + int ft2; + + *iCompare = 0; + + if (filename1 && filename2) + { + ft1 = FS_GetFileTime(filename1); + ft2 = FS_GetFileTime(filename2); + + if (ft1 >= ft2) + { + if (ft1 > ft2) + { + *iCompare = 1; + } + + return 1; + } + else + { + *iCompare = -1; + return 1; + } + } + + return 0; +} + +/* <12165> ../engine/common.c:2930 */ +void COM_GetGameDir(char *szGameDir) +{ + if (szGameDir) + { + Q_snprintf(szGameDir, MAX_PATH - 1 , "%s", com_gamedir); + } +} + +/* <1218f> ../engine/common.c:2947 */ +int COM_EntsForPlayerSlots(int nPlayers) +{ + int numedicts = gmodinfo.num_edicts; + int p = COM_CheckParm("-num_edicts"); + + if (p && p < com_argc - 1) + { + p = Q_atoi(com_argv[p + 1]); + + if (numedicts < p) + { + numedicts = p; + } + } + + return (numedicts + 15 * (nPlayers - 1)); +} + +/* <12270> ../engine/common.c:2965 */ +void COM_NormalizeAngles(vec_t *angles) +{ + int i; + + for (i = 0; i < 3; i++) + { + if (angles[i] > 180.0) + { + angles[i] = (float)(fmod((double)angles[i], 360.0) - 360.0); + } + else if (angles[i] < -180.0) + { + angles[i] = (float)(fmod((double)angles[i], 360.0) + 360.0); + } + } +} + +/* +================ +COM_Munge funcs + +Anti-proxy/aimbot obfuscation code + +COM_UnMunge should reversably fixup the data +================ +*/ +/* <12320> ../engine/common.c:3018 */ +void COM_Munge(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= ~seq; + c = LongSwap(c); + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table[(i + j) & 0x0f]); + } + + c ^= seq; + *pc = c; + } +} + +/* <123f7> ../engine/common.c:3060 */ +void COM_UnMunge(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= seq; + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table[(i + j) & 0x0f]); + } + + c = LongSwap(c); + c ^= ~seq; + *pc = c; + } +} + +/* <124de> ../engine/common.c:3104 */ +void COM_Munge2(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= ~seq; + c = LongSwap(c); + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table2[(i + j) & 0x0f]); + } + + c ^= seq; + *pc = c; + } +} + +/* <125b5> ../engine/common.c:3146 */ +void COM_UnMunge2(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= seq; + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table2[(i + j) & 0x0f]); + } + + c = LongSwap(c); + c ^= ~seq; + *pc = c; + } +} + +/* <1269c> ../engine/common.c:3190 */ +void COM_Munge3(unsigned char *data, int len, int seq) +{ + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= ~seq; + c = LongSwap(c); + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table3[(i + j) & 0x0f]); + } + + c ^= seq; + *pc = c; + } +} + +/* <12773> ../engine/common.c:3232 */ +NOXREF void COM_UnMunge3(unsigned char *data, int len, int seq) +{ + NOXREFCHECK; + + int i; + int mungelen; + int c; + int *pc; + unsigned char *p; + int j; + + mungelen = len & ~3; + mungelen /= 4; + + for (i = 0; i < mungelen; i++) + { + pc = (int *)&data[i * 4]; + c = *pc; + c ^= seq; + + p = (unsigned char *)&c; + for (j = 0; j < 4; j++) + { + *p++ ^= (0xa5 | (j << j) | j | mungify_table3[(i + j) & 0x0f]); + } + + c = LongSwap(c); + c ^= ~seq; + *pc = c; + } +} + +/* ../engine/common.c:3272 */ +typedef struct +{ + unsigned char chunkID[4]; + long int chunkSize; + short int wFormatTag; + short unsigned int wChannels; + long unsigned int dwSamplesPerSec; + long unsigned int dwAvgBytesPerSec; + short unsigned int wBlockAlign; + short unsigned int wBitsPerSample; +} FormatChunk; + +#define WAVE_HEADER_LENGTH 128 + +/* <1285a> ../engine/common.c:3287 */ +unsigned int COM_GetApproxWavePlayLength(const char *filepath) +{ + char buf[WAVE_HEADER_LENGTH + 1]; + int filelength; + FileHandle_t hFile; + FormatChunk format; + + hFile = FS_Open(filepath, "rb"); + + if (hFile) + { + filelength = FS_Size(hFile); + + if (filelength <= WAVE_HEADER_LENGTH) + return 0; + + FS_Read(buf, WAVE_HEADER_LENGTH, 1, hFile); + FS_Close(hFile); + + buf[WAVE_HEADER_LENGTH] = 0; + + if (!Q_strnicmp(buf, "RIFF", 4) && !Q_strnicmp(&buf[8], "WAVE", 4) && !Q_strnicmp(&buf[12], "fmt ", 4)) + { + Q_memcpy(&format, &buf[12], sizeof(FormatChunk)); + + filelength -= WAVE_HEADER_LENGTH; + + if (format.dwAvgBytesPerSec > 999) + { + return filelength / (format.dwAvgBytesPerSec / 1000); + } + + return 1000 * filelength / format.dwAvgBytesPerSec; + } + } + + return 0; +} + +#endif // COM_Functions_region diff --git a/rehlds/engine/common.h b/rehlds/engine/common.h new file mode 100644 index 0000000..3f0d1c8 --- /dev/null +++ b/rehlds/engine/common.h @@ -0,0 +1,297 @@ +#pragma once +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#include "common_rehlds.h" +#include "bspfile.h" +#include "FileSystem.h" +#include "quakedef.h" +#include "usercmd.h" +#include "info.h" +#include "com_model.h" + + +#ifdef HOOK_ENGINE +#define serverinfo (*pserverinfo) + +#define gpszVersionString (*pgpszVersionString) +#define gpszProductString (*pgpszProductString) + +#define bfread (*pbfread) +#define bfwrite (*pbfwrite) + +#define msg_badread (*pmsg_badread) +#define msg_readcount (*pmsg_readcount) + +#define bigendien (*pbigendien) + +#define BigShort (*pBigShort) +#define LittleShort (*pLittleShort) +#define BigLong (*pBigLong) +#define LittleLong (*pLittleLong) +#define BigFloat (*pBigFloat) +#define LittleFloat (*pLittleFloat) + +#define com_argc (*pcom_argc) +#define com_argv (*pcom_argv) +#define com_token (*pcom_token) +#define com_ignorecolons (*pcom_ignorecolons) +#define s_com_token_unget (*ps_com_token_unget) +#define com_clientfallback (*pcom_clientfallback) +#define com_gamedir (*pcom_gamedir) +#define com_cmdline (*pcom_cmdline) + +#define loadcache (*ploadcache) +#define loadbuf (*ploadbuf) +#define loadsize (*ploadsize) +#endif // HOOK_ENGINE + + +extern char serverinfo[MAX_INFO_STRING]; + +extern char gpszVersionString[32]; +extern char gpszProductString[32]; + +typedef struct bf_read_s bf_read_t; +typedef struct bf_write_s bf_write_t; + +extern bf_read_t bfread; +extern bf_write_t bfwrite; + +extern int msg_badread; +extern int msg_readcount; + +extern qboolean bigendien; + +extern short(*BigShort)(short l); +extern short(*LittleShort)(short l); +extern int(*BigLong)(int l); +extern int(*LittleLong)(int l); +extern float(*BigFloat)(float l); +extern float(*LittleFloat)(float l); + +extern int com_argc; +extern char **com_argv; + +extern char com_token[COM_TOKEN_LEN]; + +extern qboolean com_ignorecolons; +extern qboolean s_com_token_unget; +extern char com_clientfallback[MAX_PATH]; +extern char com_gamedir[MAX_PATH]; +extern char com_cmdline[COM_MAX_CMD_LINE]; + +extern cache_user_t *loadcache; +extern unsigned char *loadbuf; +extern int loadsize; + + +//#define Q_functions +#ifndef Q_functions + +#ifndef _WIN32 +#define _strlwr(p) for (int i = 0; p[i] != 0; i++) p[i] = tolower(p[i]); +#endif + +#define Q_memset memset +#define Q_memcpy memcpy +#define Q_strlen strlen +#define Q_memcmp memcmp +#define Q_strcpy strcpy +#define Q_strncpy strncpy +#define Q_strrchr strrchr +#define Q_strcat strcat +#define Q_strncat strncat +#define Q_strcmp strcmp +#define Q_strncmp strncmp +//#define Q_strcasecmp _stricmp // Use Q_stricmp +//#define Q_strncasecmp _strnicmp // Use Q_strnicmp +#define Q_stricmp _stricmp +#define Q_strnicmp _strnicmp +#define Q_strstr strstr +#define Q_strchr strchr +#define Q_strrchr strrchr +#define Q_strlwr _strlwr +#define Q_sprintf sprintf +#define Q_snprintf _snprintf +#define Q_atoi atoi +#define Q_atof atof +//#define Q_strtoull strtoull +//#define Q_FileNameCmp FileNameCmp +#define Q_vsnprintf _vsnprintf + +#else // Q_functions + +void Q_strcpy(char *dest, const char *src); +int Q_strlen(const char *str); +NOBODY void Q_memset(void *dest, int fill, int count); +NOBODY void Q_memcpy(void *dest, const void *src, int count); +NOBODY int Q_memcmp(void *m1, void *m2, int count); +NOBODY void Q_strncpy(char *dest, const char *src, int count); +NOBODY char *Q_strrchr(char *s, char c); +NOBODY void Q_strcat(char *dest, char *src); +NOBODY int Q_strcmp(const char *s1, const char *s2); +NOBODY int Q_strncmp(const char *s1, const char *s2, int count); +NOBODY int Q_strncasecmp(const char *s1, const char *s2, int n); +NOBODY int Q_strcasecmp(const char *s1, const char *s2); +NOBODY int Q_stricmp(const char *s1, const char *s2); +NOBODY int Q_strnicmp(const char *s1, const char *s2, int n); +NOBODY int Q_atoi(const char *str); +NOBODY float Q_atof(const char *str); +NOBODY char *Q_strlwr(char *src); +NOBODY int Q_FileNameCmp(char *file1, char *file2); +NOBODY char *Q_strstr(const char *s1, const char *search); +NOBODY uint64 Q_strtoull(char *str); + +#endif // Q_functions + +int build_number(void); +char *Info_Serverinfo(void); + +unsigned char COM_Nibble(char c); +void COM_HexConvert(const char *pszInput, int nInputLength, unsigned char *pOutput); +NOXREF char *COM_BinPrintf(unsigned char *buf, int nLen); +void COM_ExplainDisconnection(qboolean bPrint, char *fmt, ...); +NOXREF void COM_ExtendedExplainDisconnection(qboolean bPrint, char *fmt, ...); + +int LongSwap(int l); +short ShortSwap(short l); +short ShortNoSwap(short l); +int LongNoSwap(int l); +float FloatSwap(float f); +float FloatNoSwap(float f); + +void MSG_WriteChar(sizebuf_t *sb, int c); +void MSG_WriteByte(sizebuf_t *sb, int c); +void MSG_WriteShort(sizebuf_t *sb, int c); +void MSG_WriteWord(sizebuf_t *sb, int c); +void MSG_WriteLong(sizebuf_t *sb, int c); +void MSG_WriteFloat(sizebuf_t *sb, float f); +void MSG_WriteString(sizebuf_t *sb, const char *s); +void MSG_WriteBuf(sizebuf_t *sb, int iSize, void *buf); +void MSG_WriteAngle(sizebuf_t *sb, float f); +void MSG_WriteHiresAngle(sizebuf_t *sb, float f); +void MSG_WriteUsercmd(sizebuf_t *buf, usercmd_t *to, usercmd_t *from); +void COM_BitOpsInit(void); +void MSG_WriteOneBit(int nValue); +void MSG_StartBitWriting(sizebuf_t *buf); +NOXREF qboolean MSG_IsBitWriting(void); +void MSG_EndBitWriting(sizebuf_t *buf); +void MSG_WriteBits(uint32_t data, int numbits); +void MSG_WriteSBits(int data, int numbits); +void MSG_WriteBitString(const char *p); +void MSG_WriteBitData(void *src, int length); +void MSG_WriteBitAngle(float fAngle, int numbits); +float MSG_ReadBitAngle(int numbits); +int MSG_CurrentBit(void); +NOXREF qboolean MSG_IsBitReading(void); +void MSG_StartBitReading(sizebuf_t *buf); +void MSG_EndBitReading(sizebuf_t *buf); +int MSG_ReadOneBit(void); +uint32_t MSG_ReadBits(int numbits); +NOXREF uint32_t MSG_PeekBits(int numbits); +int MSG_ReadSBits(int numbits); +NOXREF char *MSG_ReadBitString(void); +int MSG_ReadBitData(void *dest, int length); +NOXREF float MSG_ReadBitCoord(void); +void MSG_WriteBitCoord(const float f); +NOXREF void MSG_ReadBitVec3Coord(vec3_t fa); +void MSG_WriteBitVec3Coord(const vec3_t fa); +NOXREF float MSG_ReadCoord(void); +void MSG_WriteCoord(sizebuf_t *sb, const float f); +NOXREF void MSG_ReadVec3Coord(sizebuf_t *sb, vec3_t fa); +NOXREF void MSG_WriteVec3Coord(sizebuf_t *sb, const vec3_t fa); +void MSG_BeginReading(void); +int MSG_ReadChar(void); +int MSG_ReadByte(void); +int MSG_ReadShort(void); +NOXREF int MSG_ReadWord(void); +int MSG_ReadLong(void); +NOXREF float MSG_ReadFloat(void); +int MSG_ReadBuf(int iSize, void *pbuf); +char *MSG_ReadString(void); +char *MSG_ReadStringLine(void); +NOXREF float MSG_ReadAngle(void); +NOXREF float MSG_ReadHiresAngle(void); +void MSG_ReadUsercmd(usercmd_t *to, usercmd_t *from); + +void SZ_Alloc(const char *name, sizebuf_t *buf, int startsize); +void SZ_Clear(sizebuf_t *buf); +void *SZ_GetSpace(sizebuf_t *buf, int length); +void SZ_Write(sizebuf_t *buf, const void *data, int length); +void SZ_Print(sizebuf_t *buf, const char *data); + +NOXREF char *COM_SkipPath(char *pathname); +void COM_StripExtension(char *in, char *out); +char *COM_FileExtension(char *in); +void COM_FileBase(const char *in, char *out); +void COM_DefaultExtension(char *path, char *extension); +void COM_UngetToken(void); +char *COM_Parse(char *data); +char *COM_ParseLine(char *data); +int COM_TokenWaiting(char *buffer); +int COM_CheckParm(char *parm); +void COM_InitArgv(int argc, char *argv[]); +void COM_Init(char *basedir); +char *va(char *format, ...); +char *vstr(vec_t *v); +NOXREF int memsearch(unsigned char *start, int count, int search); +NOXREF void COM_WriteFile(char *filename, void *data, int len); +void COM_FixSlashes(char *pname); +void COM_CreatePath(char *path); +NOXREF void COM_CopyFile(char *netpath, char *cachepath); +NOXREF int COM_ExpandFilename(char *filename); +int COM_FileSize(char *filename); +unsigned char *COM_LoadFile(const char *path, int usehunk, int *pLength); +void COM_FreeFile(void *buffer); +void COM_CopyFileChunk(FileHandle_t dst, FileHandle_t src, int nSize); +NOXREF unsigned char *COM_LoadFileLimit(char *path, int pos, int cbmax, int *pcbread, FileHandle_t *phFile); +unsigned char *COM_LoadHunkFile(char *path); +unsigned char *COM_LoadTempFile(char *path, int *pLength); +void COM_LoadCacheFile(char *path, struct cache_user_s *cu); +NOXREF unsigned char *COM_LoadStackFile(char *path, void *buffer, int bufsize, int *length); +void COM_Shutdown(void); +NOXREF void COM_AddAppDirectory(char *pszBaseDir, const char *appName); +void COM_AddDefaultDir(char *pszDir); +void COM_StripTrailingSlash(char *ppath); +void COM_ParseDirectoryFromCmd(const char *pCmdName, char *pDirName, const char *pDefault); +qboolean COM_SetupDirectories(void); +void COM_CheckPrintMap(dheader_t *header, const char *mapname, qboolean bShowOutdated); +void COM_ListMaps(char *pszSubString); +void COM_Log(char *pszFile, char *fmt, ...); +unsigned char *COM_LoadFileForMe(char *filename, int *pLength); +int COM_CompareFileTime(char *filename1, char *filename2, int *iCompare); +void COM_GetGameDir(char *szGameDir); +int COM_EntsForPlayerSlots(int nPlayers); +void COM_NormalizeAngles(vec_t *angles); +void COM_Munge(unsigned char *data, int len, int seq); +void COM_UnMunge(unsigned char *data, int len, int seq); +void COM_Munge2(unsigned char *data, int len, int seq); +void COM_UnMunge2(unsigned char *data, int len, int seq); +void COM_Munge3(unsigned char *data, int len, int seq); +NOXREF void COM_UnMunge3(unsigned char *data, int len, int seq); +unsigned int COM_GetApproxWavePlayLength(const char *filepath); diff --git a/rehlds/engine/consistency.h b/rehlds/engine/consistency.h new file mode 100644 index 0000000..9e0b6f8 --- /dev/null +++ b/rehlds/engine/consistency.h @@ -0,0 +1,48 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef CONSISTENCY_H +#define CONSISTENCY_H +#ifdef _WIN32 +#pragma once +#endif + + +/* <7508> ../engine/consistency.h:9 */ +typedef struct consistency_s +{ + char * filename; + int issound; + int orig_index; + int value; + int check_type; + float mins[3]; + float maxs[3]; +} consistency_t; + +#endif // CONSISTENCY_H \ No newline at end of file diff --git a/rehlds/engine/crc.cpp b/rehlds/engine/crc.cpp new file mode 100644 index 0000000..25207b6 --- /dev/null +++ b/rehlds/engine/crc.cpp @@ -0,0 +1,584 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +static const uint32_t pulCRCTable[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + +/* <193b9> ../engine/crc.c:86 */ +void CRC32_Init(CRC32_t *pulCRC) +{ + *pulCRC = -1; +} + +/* <193d9> ../engine/crc.c:91 */ +CRC32_t CRC32_Final(CRC32_t pulCRC) +{ + return ~pulCRC; +} + +/* <19453> ../engine/crc.c:96 */ +void CRC32_ProcessByte(CRC32_t *pulCRC, unsigned char ch) +{ + CRC32_t ulCrc = *pulCRC; + ulCrc = pulCRCTable[(ulCrc & 0xFF) ^ ch] ^ ((ulCrc ^ ch) >> 8); + *pulCRC = ulCrc; +} + +/* <19496> ../engine/crc.c:106 */ +void CRC32_ProcessBuffer(CRC32_t *pulCRC, void *pBuffer, int nBuffer) +{ + CRC32_t ulCrc = *pulCRC; + uint8_t* pb = (uint8_t*)pBuffer; + + for (int i = 0; i < nBuffer; i++) + { + ulCrc = pulCRCTable[(ulCrc & 0xFF) ^ pb[i]] ^ (ulCrc >> 8); + } + + *pulCRC = ulCrc; +} + +/* <19527> ../engine/crc.c:247 */ +byte COM_BlockSequenceCRCByte(byte *base, int length, int sequence) +{ + byte *p; + char chkb[64]; + CRC32_t crc; + + if (sequence < 0) + Sys_Error("sequence < 0, in COM_BlockSequenceCRCByte\n"); + p = (byte *)pulCRCTable + sequence % 0x3FC; + if (length > 60) + length = 60; + + Q_memcpy(chkb, base, length); + + chkb[length] = p[0]; + chkb[length + 1] = p[1]; + chkb[length + 2] = p[2]; + chkb[length + 3] = p[3]; + + CRC32_Init(&crc); + CRC32_ProcessBuffer(&crc, chkb, length + 4); + return CRC32_Final(crc); +} + +/* <195e1> ../engine/crc.c:292 */ +NOXREF BOOL CRC_File(CRC32_t *crcvalue, char *pszFileName) +{ + FileHandle_t fp; + byte chunk[1024]; + int nBytesRead; + int nSize; + + fp = FS_Open(pszFileName, "rb"); + + if (!fp) + return 0; + + nSize = FS_Size(fp); + if (nSize == -1) + return 0; + + while (nSize > 0) + { + if (nSize > 1024) + nBytesRead = FS_Read(chunk, 1024, 1, fp); + else + nBytesRead = FS_Read(chunk, nSize, 1, fp); + + if (nBytesRead > 0) + { + nSize -= nBytesRead; + CRC32_ProcessBuffer(crcvalue, chunk, nBytesRead); + } + + if (FS_EndOfFile(fp)) + break; + + if (!FS_IsOk(fp)) + { + FS_Close(fp); + return 0; + } + } + FS_Close(fp); + return 1; +} + +/* <1966e> ../engine/crc.c:354 */ +int CRC_MapFile(CRC32_t *crcvalue, char *pszFileName) +{ + FileHandle_t fp; + byte chunk[1024]; + int i; + int l; + int nBytesRead; + dheader_t header; + int nSize; + lump_t *curLump; + int32 startOfs; + int nLumpID; + + nLumpID = 0; + if (Q_stricmp(com_gamedir, "bshift") == 0) + nLumpID = 1; + + fp = FS_Open(pszFileName, "rb"); + + if (!fp) + return 0; + + nSize = FS_Size(fp); + if (nSize == -1) + return 0; + + startOfs = FS_Tell(fp); + if (FS_Read(&header, sizeof(dheader_t), 1, fp) != sizeof(dheader_t)) + { + Con_Printf("Could not read BSP header for map [%s].\n", pszFileName); + FS_Close(fp); + return 0; + } + i = LittleLong(header.version); + if (i != BSPVERSION) + { + Con_Printf("Map [%s] has incorrect BSP version (%i should be %i).\n", pszFileName, i, BSPVERSION); + FS_Close(fp); + return 0; + } + for (l = 0; l < HEADER_LUMPS; l++) + { + if (l == nLumpID) + continue; + + curLump = &(header.lumps[l]); + nSize = curLump->filelen; + FS_Seek(fp, startOfs + curLump->fileofs, FILESYSTEM_SEEK_HEAD); + + while(nSize > 0) + { + if (nSize > 1024) + nBytesRead = FS_Read(chunk, 1024, 1, fp); + else + nBytesRead = FS_Read(chunk, nSize, 1, fp); + + if (nBytesRead > 0) + { + nSize -= nBytesRead; + CRC32_ProcessBuffer(crcvalue, chunk, nBytesRead); + } + if (!FS_IsOk(fp)) + { + FS_Close(fp); + return 0; + } + } + } + FS_Close(fp); + return 1; +} + + +static unsigned char PADDING[64] = +{ + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G and H are basic MD5 functions: selection, majority, parity */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + { \ + (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + { \ + (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + { \ + (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + { \ + (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + + +/* <1974c> ../engine/crc.c:455 */ +void MD5Init(MD5Context_t *ctx) +{ + ctx->bits[0] = ctx->bits[1] = 0; + + // Load magic initialization constants. + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; +} + +/* <19841> ../engine/crc.c:473 */ +void MD5Update(MD5Context_t *ctx, const unsigned char *buf, unsigned int len) +{ + uint32_t in[16]; + int mdi; + unsigned int i, ii; + + // Compute number of bytes mod 64 + mdi = (int)((ctx->bits[0] >> 3) & 0x3F); + + // Update number of bits + if ((ctx->bits[0] + ((uint32_t)len << 3)) < ctx->bits[0]) + { + ctx->bits[1]++; + } + + ctx->bits[0] += ((uint32_t)len << 3); + ctx->bits[1] += ((uint32_t)len >> 29); + + while (len--) + { + // Add new character to buffer, increment mdi + ctx->in[mdi++] = *buf++; + + // Transform if necessary + if (mdi == 0x40) + { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((uint32_t)ctx->in[ii + 3]) << 24) | + (((uint32_t)ctx->in[ii + 2]) << 16) | + (((uint32_t)ctx->in[ii + 1]) << 8) | + ((uint32_t)ctx->in[ii]); + MD5Transform(ctx->buf, in); + mdi = 0; + } + } +} + +/* <197ea> ../engine/crc.c:528 */ +void MD5Final(unsigned char digest[16], MD5Context_t *ctx) +{ + uint32_t in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + // save number of bits + in[14] = ctx->bits[0]; + in[15] = ctx->bits[1]; + + // Compute number of bytes mod 64 + mdi = (int)((ctx->bits[0] >> 3) & 0x3F); + + // Pad out to 56 mod 64 + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update(ctx, PADDING, padLen); + + // Append length in bits and transform + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((uint32_t)ctx->in[ii + 3]) << 24) | + (((uint32_t)ctx->in[ii + 2]) << 16) | + (((uint32_t)ctx->in[ii + 1]) << 8) | + ((uint32_t)ctx->in[ii]); + MD5Transform(ctx->buf, in); + + // Store buffer in digest + for (i = 0, ii = 0; i < 4; i++, ii += 4) + { + digest[ii] = (unsigned char)(ctx->buf[i] & 0xFF); + digest[ii + 1] = (unsigned char)((ctx->buf[i] >> 8) & 0xFF); + digest[ii + 2] = (unsigned char)((ctx->buf[i] >> 16) & 0xFF); + digest[ii + 3] = (unsigned char)((ctx->buf[i] >> 24) & 0xFF); + } +} + +/* <19769> ../engine/crc.c:592 */ +void MD5Transform(unsigned int buf[4], const unsigned int in[16]) +{ + uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + // Round 1 +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF(a, b, c, d, in[0], S11, 3614090360); /* 1 */ + FF(d, a, b, c, in[1], S12, 3905402710); /* 2 */ + FF(c, d, a, b, in[2], S13, 606105819); /* 3 */ + FF(b, c, d, a, in[3], S14, 3250441966); /* 4 */ + FF(a, b, c, d, in[4], S11, 4118548399); /* 5 */ + FF(d, a, b, c, in[5], S12, 1200080426); /* 6 */ + FF(c, d, a, b, in[6], S13, 2821735955); /* 7 */ + FF(b, c, d, a, in[7], S14, 4249261313); /* 8 */ + FF(a, b, c, d, in[8], S11, 1770035416); /* 9 */ + FF(d, a, b, c, in[9], S12, 2336552879); /* 10 */ + FF(c, d, a, b, in[10], S13, 4294925233); /* 11 */ + FF(b, c, d, a, in[11], S14, 2304563134); /* 12 */ + FF(a, b, c, d, in[12], S11, 1804603682); /* 13 */ + FF(d, a, b, c, in[13], S12, 4254626195); /* 14 */ + FF(c, d, a, b, in[14], S13, 2792965006); /* 15 */ + FF(b, c, d, a, in[15], S14, 1236535329); /* 16 */ + + // Round 2 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG(a, b, c, d, in[1], S21, 4129170786); /* 17 */ + GG(d, a, b, c, in[6], S22, 3225465664); /* 18 */ + GG(c, d, a, b, in[11], S23, 643717713); /* 19 */ + GG(b, c, d, a, in[0], S24, 3921069994); /* 20 */ + GG(a, b, c, d, in[5], S21, 3593408605); /* 21 */ + GG(d, a, b, c, in[10], S22, 38016083); /* 22 */ + GG(c, d, a, b, in[15], S23, 3634488961); /* 23 */ + GG(b, c, d, a, in[4], S24, 3889429448); /* 24 */ + GG(a, b, c, d, in[9], S21, 568446438); /* 25 */ + GG(d, a, b, c, in[14], S22, 3275163606); /* 26 */ + GG(c, d, a, b, in[3], S23, 4107603335); /* 27 */ + GG(b, c, d, a, in[8], S24, 1163531501); /* 28 */ + GG(a, b, c, d, in[13], S21, 2850285829); /* 29 */ + GG(d, a, b, c, in[2], S22, 4243563512); /* 30 */ + GG(c, d, a, b, in[7], S23, 1735328473); /* 31 */ + GG(b, c, d, a, in[12], S24, 2368359562); /* 32 */ + + // Round 3 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH(a, b, c, d, in[5], S31, 4294588738); /* 33 */ + HH(d, a, b, c, in[8], S32, 2272392833); /* 34 */ + HH(c, d, a, b, in[11], S33, 1839030562); /* 35 */ + HH(b, c, d, a, in[14], S34, 4259657740); /* 36 */ + HH(a, b, c, d, in[1], S31, 2763975236); /* 37 */ + HH(d, a, b, c, in[4], S32, 1272893353); /* 38 */ + HH(c, d, a, b, in[7], S33, 4139469664); /* 39 */ + HH(b, c, d, a, in[10], S34, 3200236656); /* 40 */ + HH(a, b, c, d, in[13], S31, 681279174); /* 41 */ + HH(d, a, b, c, in[0], S32, 3936430074); /* 42 */ + HH(c, d, a, b, in[3], S33, 3572445317); /* 43 */ + HH(b, c, d, a, in[6], S34, 76029189); /* 44 */ + HH(a, b, c, d, in[9], S31, 3654602809); /* 45 */ + HH(d, a, b, c, in[12], S32, 3873151461); /* 46 */ + HH(c, d, a, b, in[15], S33, 530742520); /* 47 */ + HH(b, c, d, a, in[2], S34, 3299628645); /* 48 */ + + // Round 4 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II(a, b, c, d, in[0], S41, 4096336452); /* 49 */ + II(d, a, b, c, in[7], S42, 1126891415); /* 50 */ + II(c, d, a, b, in[14], S43, 2878612391); /* 51 */ + II(b, c, d, a, in[5], S44, 4237533241); /* 52 */ + II(a, b, c, d, in[12], S41, 1700485571); /* 53 */ + II(d, a, b, c, in[3], S42, 2399980690); /* 54 */ + II(c, d, a, b, in[10], S43, 4293915773); /* 55 */ + II(b, c, d, a, in[1], S44, 2240044497); /* 56 */ + II(a, b, c, d, in[8], S41, 1873313359); /* 57 */ + II(d, a, b, c, in[15], S42, 4264355552); /* 58 */ + II(c, d, a, b, in[6], S43, 2734768916); /* 59 */ + II(b, c, d, a, in[13], S44, 1309151649); /* 60 */ + II(a, b, c, d, in[4], S41, 4149444226); /* 61 */ + II(d, a, b, c, in[11], S42, 3174756917); /* 62 */ + II(c, d, a, b, in[2], S43, 718787259); /* 63 */ + II(b, c, d, a, in[9], S44, 3951481745); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* <198b8> ../engine/crc.c:686 */ +BOOL MD5_Hash_File(unsigned char digest[16], char *pszFileName, BOOL bUsefopen, BOOL bSeed, unsigned int seed[4]) +{ + FileHandle_t fp = (FileHandle_t)FS_OpenPathID(pszFileName, "rb", "GAMECONFIG"); + if (!fp) + fp = FS_Open(pszFileName, "rb"); + + if (!fp) + return 0; + + int nSize = FS_Size(fp); + if (nSize <= 0) + { + FS_Close(fp); + return 0; + + } + + MD5Context_t ctx; + Q_memset(&ctx, 0, sizeof(ctx)); + MD5Init(&ctx); + if (bSeed) + MD5Update(&ctx, (unsigned char*)seed, 16); + + while (1) + { + byte chunk[1024]; + int nBytesRead = FS_Read(chunk, (nSize <= sizeof(chunk)) ? nSize : sizeof(chunk), 1, fp); + if (nBytesRead > 0) + { + nSize -= nBytesRead; + MD5Update(&ctx, chunk, nBytesRead); + } + + if (FS_EndOfFile(fp)) + { + FS_Close(fp); + MD5Final(digest, &ctx); + return 1; + } + + if (!FS_IsOk(fp)) + break; + + if (nSize <= 0) + { + FS_Close(fp); + MD5Final(digest, &ctx); + return 1; + } + } + + FS_Close(fp); + return 0; +} + +/* <1998b> ../engine/crc.c:762 */ +char *MD5_Print(unsigned char hash[16]) +{ + static char szReturn[64]; + char szChunk[10]; + int i; + + Q_memset(szReturn, 0, sizeof(szReturn)); + + for (i = 0; i < 16; i++) + { + Q_snprintf(szChunk, sizeof(szChunk), "%02x", hash[i]); + Q_strncat(szReturn, szChunk, sizeof(szReturn) - Q_strlen(szReturn) - 1); + } + + return szReturn; +} diff --git a/rehlds/engine/custom_int.h b/rehlds/engine/custom_int.h new file mode 100644 index 0000000..44fa5d3 --- /dev/null +++ b/rehlds/engine/custom_int.h @@ -0,0 +1,21 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Customization.h +#pragma once +#include "custom.h" + +void COM_ClearCustomizationList( struct customization_s *pHead, qboolean bCleanDecals); +qboolean COM_CreateCustomization( struct customization_s *pListHead, struct resource_s *pResource, int playernumber, int flags, struct customization_s **pCustomization, int *nLumps ); +int COM_SizeofResourceList ( struct resource_s *pList, struct resourceinfo_s *ri ); diff --git a/rehlds/engine/cvar.cpp b/rehlds/engine/cvar.cpp new file mode 100644 index 0000000..2efe02b --- /dev/null +++ b/rehlds/engine/cvar.cpp @@ -0,0 +1,735 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + + +/* + All cvar names are case insensitive! Values not. +*/ + +cvar_t *cvar_vars; +char cvar_null_string[] = ""; + + +/* <1853e> ../engine/cvar.c:26 */ +void Cvar_Init(void) +{ +#ifndef SWDS + // TODO: add client code, possibly none. +#endif +} + +/* <18552> ../engine/cvar.c:30 */ +void Cvar_Shutdown(void) +{ + // TODO: Check memory releasing + cvar_vars = NULL; +} + +/* <18566> ../engine/cvar.c:40 */ +cvar_t *Cvar_FindVar(const char *var_name) +{ + cvar_t *var; + +#ifndef SWDS + g_engdstAddrs->pfnGetCvarPointer(&var_name); +#endif + + for (var = cvar_vars; var; var = var->next) + { + if (!Q_stricmp(var_name, var->name)) + break; + } + return var; +} + +/* <185b6> ../engine/cvar.c:58 */ +NOXREF cvar_t *Cvar_FindPrevVar(const char *var_name) +{ + NOXREFCHECK; + + cvar_t *var; + + for (var = cvar_vars; var && var->next; var = var->next) + { + if (!Q_stricmp(var_name, var->next->name)) + return var; + } + return NULL; +} + +/* <18606> ../engine/cvar.c:78 */ +float Cvar_VariableValue(const char *var_name) +{ + cvar_t *var = Cvar_FindVar(var_name); + + if (var) + { + return (float)Q_atof(var->string); + } + + return 0.0f; +} + +/* <18666> ../engine/cvar.c:94 */ +NOXREF int Cvar_VariableInt(const char *var_name) +{ + NOXREFCHECK; + + cvar_t *var = Cvar_FindVar(var_name); + + if (var) + { + return Q_atoi(var->string); + } + + return 0; +} + +/* <186c6> ../engine/cvar.c:110 */ +char *Cvar_VariableString(const char *var_name) +{ + cvar_t *var = Cvar_FindVar(var_name); + + if (var) + { + return var->string; + } + + return cvar_null_string; +} + +/* <1872a> ../engine/cvar.c:126 */ +NOXREF char *Cvar_CompleteVariable(const char *search, int forward) +{ + NOXREFCHECK; + + // TODO: We have a cvar name length limit here: prepare for unforeseen consequences! + static char lastpartial[256]; + char partial[256]; + cvar_t *cvar; + int len; + char *pPartial; + + Q_strncpy(partial, search, 255); + partial[255] = 0; + len = Q_strlen(partial); + + // Trim tail spaces + for (pPartial = partial + len - 1; pPartial >= partial && *pPartial == ' '; pPartial--, len--) + { + *pPartial = 0; + } + + if (!len) + { + return NULL; + } + + if (!Q_stricmp(partial, lastpartial)) + { + // Same partial, find this then next/prev cvar, if any. + // TODO: But where it match for entered by user partial? Because we store full name + cvar = Cvar_FindVar(partial); + if (cvar) + { + cvar = forward == 1 ? cvar->next : Cvar_FindPrevVar(cvar->name); + if (cvar) + { + Q_strncpy(lastpartial, cvar->name, 255); + lastpartial[255] = 0; + return cvar->name; + } + } + } + + // Find first matching cvar + for (cvar = cvar_vars; cvar != NULL; cvar = cvar->next) + { + if (!Q_strnicmp(partial, cvar->name, len)) + { + // Store matched cvar name + Q_strncpy(lastpartial, cvar->name, 255); + lastpartial[255] = 0; + return cvar->name; + } + } + + return NULL; +} + +/* <18805> ../engine/cvar.c:198 */ +void Cvar_DirectSet(struct cvar_s *var, const char *value) +{ + if (!var || !value) + { + return; + } + + const char *pszValue = value; + char szNew[MAX_CVAR_VALUE]; + szNew[0] = 0; + + if (var->flags & FCVAR_PRINTABLEONLY) + { + if (Q_UnicodeValidate(value)) + { + Q_strncpy(szNew, value, ARRAYSIZE(szNew) - 1); + szNew[ARRAYSIZE(szNew) - 1] = 0; + } + else + { + // Copy only printable chars + // TODO: Why not UTF-8 too? + const char *pS = pszValue; + char *pD = szNew; + + while (*pS) + { + if (*pS < 32 || *pS > 126) + { + pS++; + continue; + } + *pD++ = *pS++; + } + *pD = 0; + } + + if (!Q_UnicodeValidate(szNew)) + { + // Call the artillery + Q_UnicodeRepair(szNew); + } + + if (szNew[0] == 0) + { + Q_strcpy(szNew, "empty"); + } + + pszValue = szNew; + } + + if (var->flags & FCVAR_NOEXTRAWHITEPACE) + { + if (pszValue != szNew) + { + Q_strncpy(szNew, value, ARRAYSIZE(szNew) - 1); + szNew[ARRAYSIZE(szNew) - 1] = 0; + } + + Q_StripUnprintableAndSpace(szNew); + + pszValue = szNew; + } + + qboolean changed = Q_strcmp(var->string, pszValue); + + if (var->flags & FCVAR_USERINFO) + { + if (g_pcls.state == ca_dedicated) + { + char *info = Info_Serverinfo(); + Info_SetValueForKey(info, var->name, pszValue, MAX_INFO_STRING); + SV_BroadcastCommand("fullserverinfo \"%s\"\n", info); + } +#ifndef SWDS + else + { + Info_SetValueForKey(g_pcls.userinfo, var->name, pszValue, MAX_INFO_STRING); + + if (changed && g_pcls.state >= ca_connected) + { + MSG_WriteByte(&g_pcls.netchan.message, clc_stringcmd); + SZ_Print(&g_pcls.netchan.message, va("setinfo \"%s\" \"%s\"\n", var->name, pszValue)); + } + } +#endif + } + + if (changed && var->flags & FCVAR_SERVER) + { + if (!(var->flags & FCVAR_UNLOGGED)) + { + if (var->flags & FCVAR_PROTECTED) + { + Log_Printf("Server cvar \"%s\" = \"%s\"\n", var->name, "***PROTECTED***"); + SV_BroadcastPrintf("\"%s\" changed to \"%s\"\n", var->name, "***PROTECTED***"); + } + else + { + Log_Printf("Server cvar \"%s\" = \"%s\"\n", var->name, pszValue); + SV_BroadcastPrintf("\"%s\" changed to \"%s\"\n", var->name, pszValue); + } + } + + if (!(var->flags & FCVAR_PROTECTED)) + { + Steam_SetCVar(var->name, pszValue); + } + else if (pszValue[0] && Q_stricmp(pszValue, "none")) + { + Steam_SetCVar(var->name, "1"); + } + else + { + Steam_SetCVar(var->name, "0"); + } + } + + Z_Free(var->string); + var->string = (char *)Z_Malloc(Q_strlen(pszValue) + 1); + Q_strcpy(var->string, pszValue); + var->value = (float)Q_atof(var->string); +} + +/* <188e9> ../engine/cvar.c:347 */ +void Cvar_Set(const char *var_name, const char *value) +{ + cvar_t *var = Cvar_FindVar(var_name); + + if (!var) + { + Con_DPrintf(__FUNCTION__ ": variable \"%s\" not found\n", var_name); + return; + } + + Cvar_DirectSet(var, value); +} + +/* <1893e> ../engine/cvar.c:365 */ +void Cvar_SetValue(const char *var_name, float value) +{ + char val[32]; + +#ifndef SWDS + g_engdstAddrs->Cvar_SetValue(&var_name, &value); +#endif + + if (fabs(value - (double)(signed int)value) >= 0.000001) + { + Q_snprintf(val, ARRAYSIZE(val) - 1, "%f", value); + } + else + { + Q_snprintf(val, ARRAYSIZE(val) - 1, "%d", (signed int)value); + } + val[ARRAYSIZE(val) - 1] = 0; + + Cvar_Set(var_name, val); +} + +/* <189df> ../engine/cvar.c:391 */ +void Cvar_RegisterVariable(cvar_t *variable) +{ + char *oldstr; + cvar_t *v, *c; + cvar_t dummyvar; + + if (Cvar_FindVar(variable->name)) + { + Con_Printf("Can't register variable \"%s\", already defined\n", variable->name); + return; + } + + if (Cmd_Exists(variable->name)) + { + Con_Printf(__FUNCTION__ ": \"%s\" is a command\n", variable->name); + return; + } + + oldstr = variable->string; + + // Alloc string, so it will not dissapear on side modules unloading and to maintain the same name during run + variable->string = (char *)Z_Malloc(Q_strlen(variable->string) + 1); + Q_strcpy(variable->string, oldstr); + variable->value = (float)Q_atof(oldstr); + + dummyvar.name = " "; + dummyvar.next = cvar_vars; + + v = cvar_vars; + c = &dummyvar; + + // Insert with alphabetic order + while (v) + { + if (Q_stricmp(v->name, variable->name) > 0) + { + break; + } + + c = v; + v = v->next; + } + + c->next = variable; + variable->next = v; + cvar_vars = dummyvar.next; +} + +/* <18a7e> ../engine/cvar.c:452 */ +NOXREF void Cvar_RemoveHudCvars(void) +{ + NOXREFCHECK; + + cvar_t *pVar; + cvar_t **pList; + + pVar = cvar_vars; + pList = &cvar_vars; + + while (pVar) + { + if (pVar->flags & FCVAR_CLIENTDLL) + { + *pList = pVar->next; + Z_Free(pVar->string); + Z_Free(pVar); + } + else + { + pList = &pVar->next; + } + + pVar = *pList; + } +} + +/* <18ac9> ../engine/cvar.c:499 */ +// Returns first token if there is more than one, else returns NULL. +const char *Cvar_IsMultipleTokens(const char *varname) +{ + static char firstToken[516]; + int tokens; + char *name; + + firstToken[0] = 0; + tokens = 0; + name = (char *)varname; + + name = COM_Parse(name); + + if (com_token[0] == 0) + { + return NULL; // original function returns firstToken in this situation, which is "", not NULL, but it should be ok this way + } + if (name == NULL) + { + return NULL; // only one token + } + + // Store first token + Q_strncpy(firstToken, com_token, ARRAYSIZE(firstToken) - 1); + firstToken[ARRAYSIZE(firstToken) - 1] = 0; + + // Parse for another token + name = COM_Parse(name); + + if (com_token[0] == 0) + { + return NULL; // only one token + } + + return firstToken; // multiple tokens, return first one +} + +/* <18b6e> ../engine/cvar.c:542 */ +qboolean Cvar_Command(void) +{ + cvar_t *v; + const char *arg0 = Cmd_Argv(0); + const char *firstToken = Cvar_IsMultipleTokens(arg0); + + if (firstToken) + { + v = Cvar_FindVar(firstToken); + if (v) + { + Con_Printf("\"%s\" is \"%s\"\n", v->name, v->string); + return TRUE; + } + } + else + { + v = Cvar_FindVar(arg0); + if (v) + { + if (Cmd_Argc() == 1) + { + Con_Printf("\"%s\" is \"%s\"\n", v->name, v->string); + } + else + { + if (v->flags & FCVAR_SPONLY && g_pcls.state >= ca_connecting && g_pcl.maxclients > 1) + { + Con_Printf("Can't set %s in multiplayer\n", v->name); + } + else + { + Cvar_Set(v->name, Cmd_Argv(1)); + } + } + + return TRUE; + } + } + + return FALSE; +} + +/* <18ca4> ../engine/cvar.c:601 */ +NOXREF void Cvar_WriteVariables(FileHandle_t f) +{ + NOXREFCHECK; + + cvar_t *var; + + for (var = cvar_vars; var; var = var->next) + { + if (var->flags & FCVAR_ARCHIVE) + { + FS_FPrintf(f, "%s \"%s\"\n", var->name, var->string); + } + } +} + +/* <18cdc> ../engine/cvar.c:627 */ +void Cmd_CvarListPrintCvar(cvar_t *var, FileHandle_t f) +{ + char szOutstr[256]; + + // TODO: Do correct output of string valued cvars + if (var->value == (float)(int)var->value) + { + Q_snprintf(szOutstr, ARRAYSIZE(szOutstr) - 1, "%-15s : %8i", var->name, (int)var->value); + } + else + { + Q_snprintf(szOutstr, ARRAYSIZE(szOutstr) - 1, "%-15s : %8.3f", var->name, var->value); + } + szOutstr[ARRAYSIZE(szOutstr) - 1] = 0; + + if (var->flags & FCVAR_ARCHIVE) + { + Q_strcat(szOutstr, ", a"); + } + if (var->flags & FCVAR_SERVER) + { + Q_strcat(szOutstr, ", sv"); + } + if (var->flags & FCVAR_USERINFO) + { + Q_strcat(szOutstr, ", i"); + } + + Q_strcat(szOutstr, "\n"); + + Con_Printf("%s", szOutstr); + + if (f) + { + FS_FPrintf(f, "%s", szOutstr); + } +} + +/* <18d23> ../engine/cvar.c:671 */ +void Cmd_CvarList_f(void) +{ + cvar_t *var; + int iCvars; + int iArgs; + const char *partial, *arg1; + int ipLen; + qboolean bAOnly; + qboolean bSOnly; + char szTemp[MAX_PATH]; + FileHandle_t f; + FileHandle_t fp; + qboolean bLogging; + + iCvars = 0; + partial = NULL; + bAOnly = FALSE; + bSOnly = FALSE; + f = NULL; + fp = NULL; + bLogging = FALSE; + + iArgs = Cmd_Argc(); + if (iArgs > 1) + { + arg1 = Cmd_Argv(1); + + if (!Q_stricmp(arg1, "?")) + { + Con_Printf("CvarList : List all cvars\nCvarList [Partial] : List cvars starting with 'Partial'\nCvarList log [Partial] : Logs cvars to file \"cvarlist.txt\" in the gamedir.\n"); + return; + } + + if (!Q_stricmp(arg1, "log")) + { + // Open log + int i; + for (i = 0; i < 100; i++) + { + Q_snprintf(szTemp, ARRAYSIZE(szTemp) - 1, "cvarlist%02d.txt", i); + szTemp[ARRAYSIZE(szTemp) - 1] = 0; + + fp = FS_Open(szTemp, "r"); + if (!fp) + { + break; + } + FS_Close(fp); + } + + if (i >= 100) + { + Con_Printf("Can't cvarlist! Too many existing cvarlist output files in the gamedir!\n"); + return; + } + + f = FS_Open(szTemp, "wt"); + if (!f) + { + Con_Printf("Couldn't open \"%s\" for writing!\n", szTemp); + return; + } + bLogging = TRUE; + + // Get next argument into partial, if present + if (iArgs > 2) + { + partial = Cmd_Argv(2); + ipLen = Q_strlen(partial); + } + } + else if (!Q_stricmp(arg1, "-a")) + { + bAOnly = TRUE; + } + else if (!Q_stricmp(arg1, "-s")) + { + bSOnly = TRUE; + } + else + { + partial = arg1; + ipLen = Q_strlen(partial); + } + } + + // Print cvars + Con_Printf("CVar List\n--------------\n"); + + for (var = cvar_vars; var; var = var->next) + { + if (bAOnly && !(var->flags & FCVAR_ARCHIVE)) + { + continue; + } + if (bSOnly && !(var->flags & FCVAR_SERVER)) + { + continue; + } + if (partial && Q_strnicmp(var->name, partial, ipLen)) + { + continue; + } + + Cmd_CvarListPrintCvar(var, f); + iCvars++; + } + + if (partial && *partial) + { + Con_Printf("--------------\n%3i CVars for [%s]\nCvarList ? for syntax\n", iCvars, partial); + } + else + { + Con_Printf("--------------\n%3i Total CVars\nCvarList ? for syntax\n", iCvars); + } + + // Close log + if (bLogging) + { + FS_Close(f); + Con_Printf("cvarlist logged to %s\n", szTemp); + } +} + +/* <18e0f> ../engine/cvar.c:806 */ +NOXREF int Cvar_CountServerVariables(void) +{ + NOXREFCHECK; + + int i; + cvar_t *var; + + for (i = 0, var = cvar_vars; var; var = var->next) + { + if (var->flags & FCVAR_SERVER) + { + ++i; + } + } + return i; +} + +/* <18e4a> ../engine/cvar.c:829 */ +void Cvar_UnlinkExternals(void) +{ + cvar_t *pVar; + cvar_t **pList; + + pVar = cvar_vars; + pList = &cvar_vars; + + while (pVar) + { + if (pVar->flags & FCVAR_EXTDLL) + { + *pList = pVar->next; + } + else + { + pList = &pVar->next; + } + + pVar = *pList; + } +} + +/* <18e8a> ../engine/cvar.c:853 */ +void Cvar_CmdInit(void) +{ + Cmd_AddCommand("cvarlist", Cmd_CvarList_f); +} diff --git a/rehlds/engine/cvar.h b/rehlds/engine/cvar.h new file mode 100644 index 0000000..4ffbce5 --- /dev/null +++ b/rehlds/engine/cvar.h @@ -0,0 +1,71 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef CVAR_H +#define CVAR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "cvardef.h" +#include "FileSystem.h" + + +#define MAX_CVAR_VALUE 1024 + +#ifdef HOOK_ENGINE +#define cvar_vars (*pcvar_vars) +#endif // HOOK_ENGINE + +extern cvar_t *cvar_vars; + + +void Cvar_Init(void); +void Cvar_Shutdown(void); +cvar_t *Cvar_FindVar(const char *var_name); +NOXREF cvar_t *Cvar_FindPrevVar(const char *var_name); +float Cvar_VariableValue(const char *var_name); +NOXREF int Cvar_VariableInt(const char *var_name); +char *Cvar_VariableString(const char *var_name); +NOXREF char *Cvar_CompleteVariable(const char *search, int forward); +void Cvar_DirectSet(struct cvar_s *var, const char *value); +void Cvar_Set(const char *var_name, const char *value); +void Cvar_SetValue(const char *var_name, float value); +void Cvar_RegisterVariable(cvar_t *variable); +NOXREF void Cvar_RemoveHudCvars(void); +const char *Cvar_IsMultipleTokens(const char *varname); +qboolean Cvar_Command(void); +NOXREF void Cvar_WriteVariables(FileHandle_t f); +void Cmd_CvarListPrintCvar(cvar_t *var, FileHandle_t f); +void Cmd_CvarList_f(void); +NOXREF int Cvar_CountServerVariables(void); +void Cvar_UnlinkExternals(void); +void Cvar_CmdInit(void); + +#endif // CVAR_H diff --git a/rehlds/engine/decal.h b/rehlds/engine/decal.h new file mode 100644 index 0000000..733ce88 --- /dev/null +++ b/rehlds/engine/decal.h @@ -0,0 +1,113 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef DECAL_H +#define DECAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "model.h" +#include "wad.h" + +#define MAX_DECALS 512 + +/* +* extradata size to has difference between swds.dll and hw.dll +* offset to how difference size between them (24 ~ 32) | (64 ~ 72) +*/ +#ifdef SWDS +#define OFFSET_DATAEXTRA_SIZE 0 +#else +#define OFFSET_DATAEXTRA_SIZE 8 +#endif + +/* <1fb9e> ../engine/decal.h:33 */ +typedef struct decalname_s +{ + char name[16]; + unsigned char ucFlags; +} decalname_t; + +/* <1fc17> ../engine/decals.c:449 */ +typedef struct lumplist_s +{ + lumpinfo_t *lump; + qboolean breplaced; + lumplist_s *next; +} lumplist_t; + +#ifdef HOOK_ENGINE +#define decal_wad (*pdecal_wad) +#define menu_wad (*pmenu_wad) +#define szCustName (*pszCustName) +#define decal_names (*pdecal_names) +#define m_bDrawInitialized (*pm_bDrawInitialized) +#define gfCustomBuild (*pgfCustomBuild) +#endif // HOOK_ENGINE + +extern cachewad_t *decal_wad; +extern cachewad_t *menu_wad; +extern char szCustName[10]; +extern char decal_names[MAX_DECALS][16]; +extern qboolean m_bDrawInitialized; +extern qboolean gfCustomBuild; + +void Draw_Shutdown(void); +void Draw_DecalShutdown(void); +void Draw_AllocateCacheSpace(cachewad_t *wad, int cacheMax, int tempWad); +void Draw_CacheWadInitFromFile(FileHandle_t hFile, int len, char *name, int cacheMax, cachewad_t *wad); +void Draw_CacheWadInit(char *name, int cacheMax, cachewad_t *wad); +qboolean Draw_CustomCacheWadInit(int cacheMax, cachewad_t *wad, void *raw, int nFileSize); +void Draw_MiptexTexture(cachewad_t * wad, unsigned char * data); +void Draw_CacheWadHandler(cachewad_t *wad, PFNCACHE fn, int extraDataSize); +void Draw_FreeWad(cachewad_t *pWad); +NOXREF void Draw_DecalSetName(int decal, char *name); +NOXREF int Draw_DecalIndex(int id); +int Draw_DecalCount(void); +int Draw_DecalSize(int number); +const char *Draw_DecalName(int number); +NOXREF texture_t *Draw_DecalTexture(int index); +int Draw_CacheByIndex(cachewad_t *wad, int nIndex, int playernum); +NOXREF int Draw_DecalIndexFromName(char *name); +void Decal_ReplaceOrAppendLump(lumplist_t **ppList, lumpinfo_t *lump, qboolean bsecondlump); +int Decal_CountLumps(lumplist_t *plist); +int Decal_SizeLumps(lumplist_t *plist); +void Decal_MergeInDecals(cachewad_t *pwad, const char *pathID); +void Decal_Init(void); +qboolean CustomDecal_Validate(void *raw, int nFileSize); +qboolean CustomDecal_Init(struct cachewad_s *wad, void *raw, int nFileSize, int playernum); +NOXREF void *Draw_CacheGet(cachewad_t *wad, int index); +void *Draw_CustomCacheGet(cachewad_t *wad, void *raw, int rawsize, int index); +NOXREF qboolean Draw_CacheReload(cachewad_t *wad, int i, lumpinfo_t *pLump, cachepic_t *pic, char *clean, char *path); +qboolean Draw_ValidateCustomLogo(cachewad_t *wad, unsigned char *data, lumpinfo_t *lump); +qboolean Draw_CacheLoadFromCustom(char *clean, cachewad_t *wad, void *raw, int rawsize, cachepic_t *pic); +NOXREF int Draw_CacheIndex(cachewad_t *wad, char *path); +NOXREF int Draw_CacheFindIndex(cachewad_t *wad, char *path); +#endif // DECAL_H diff --git a/rehlds/engine/decals.cpp b/rehlds/engine/decals.cpp new file mode 100644 index 0000000..7f83f74 --- /dev/null +++ b/rehlds/engine/decals.cpp @@ -0,0 +1,846 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +cachewad_t *decal_wad; +cachewad_t *menu_wad; // NOXREF + +char szCustName[10]; +char decal_names[MAX_DECALS][16]; + +qboolean m_bDrawInitialized; +qboolean gfCustomBuild; + +/* <20209> ../engine/decals.c:37 */ +void Draw_Shutdown(void) +{ + if (m_bDrawInitialized) + { + m_bDrawInitialized = FALSE; + Draw_FreeWad(menu_wad); + if (menu_wad) + Mem_Free(menu_wad); + menu_wad = NULL; + } +} + +/* <201ee> ../engine/decals.c:59 */ +void Draw_DecalShutdown(void) +{ + Draw_FreeWad(decal_wad); + if (decal_wad) + Mem_Free(decal_wad); + decal_wad = NULL; +} + +/* <1ff6d> ../engine/decals.c:69 */ +void Draw_AllocateCacheSpace(cachewad_t *wad, int cacheMax, int tempWad) +{ + int len = sizeof(cachepic_t) * cacheMax; + wad->cache = (cachepic_t *)Mem_Malloc(len); + Q_memset(wad->cache, 0, len); +#ifndef SWDS + wad->tempWad = tempWad; +#endif +} + +/* <1ffa4> ../engine/decals.c:80 */ +void Draw_CacheWadInitFromFile(FileHandle_t hFile, int len, char *name, int cacheMax, cachewad_t *wad) +{ + lumpinfo_t *lump_p; + wadinfo_t header; + + FS_Read(&header, sizeof(wadinfo_t), 1, hFile); + if (Q_strncmp(header.identification, "WAD3", 4)) + Sys_Error("Wad file %s doesn't have WAD3 id\n", name); + + wad->lumps = (lumpinfo_s *)Mem_Malloc(len - header.infotableofs); + + FS_Seek(hFile, header.infotableofs, FILESYSTEM_SEEK_HEAD); + FS_Read(wad->lumps, len - header.infotableofs, 1, hFile); + + lump_p = wad->lumps; + for (int i = 0; i < header.numlumps; i++, lump_p++) + W_CleanupName(lump_p->name, lump_p->name); + + wad->lumpCount = header.numlumps; + wad->cacheMax = cacheMax; + wad->cacheCount = 0; + wad->name = Mem_Strdup(name); + Draw_AllocateCacheSpace(wad, cacheMax, 0); + Draw_CacheWadHandler(wad, NULL, 0); +} + +/* <20067> ../engine/decals.c:113 */ +void Draw_CacheWadInit(char *name, int cacheMax, cachewad_t *wad) +{ + int len; + FileHandle_t hFile = FS_Open(name, "rb"); + if (!hFile) + Sys_Error("Draw_LoadWad: Couldn't open %s\n", name); + len = FS_Size(hFile); + Draw_CacheWadInitFromFile(hFile, len, name, cacheMax, wad); + FS_Close(hFile); +} + +/* <1fd66> ../engine/decals.c:127 */ +qboolean Draw_CustomCacheWadInit(int cacheMax, cachewad_t *wad, void *raw, int nFileSize) +{ + lumpinfo_t *lump_p; + wadinfo_t header; + header = *(wadinfo_t *)raw; + if (Q_strncmp(header.identification, "WAD3", 4)) + { + Con_Printf("Custom file doesn't have WAD3 id\n"); + return FALSE; + } + if (header.numlumps != 1) + { + Con_Printf("Custom file has wrong number of lumps %i\n", header.numlumps); + return FALSE; + } + if (header.infotableofs < 1) + { + Con_Printf("Custom file has bogus infotableofs %i\n", header.infotableofs); + return FALSE; + } + if (header.infotableofs + sizeof(lumpinfo_t) != nFileSize) + { + Con_Printf("Custom file has bogus infotableofs ( %i > %i )\n", header.infotableofs + sizeof(lumpinfo_t), nFileSize); + return FALSE; + } + lump_p = (lumpinfo_t *)Mem_Malloc(sizeof(lumpinfo_t)); + wad->lumps = lump_p; + Q_memcpy(lump_p, (char *)raw + header.infotableofs, sizeof(lumpinfo_t)); + W_CleanupName(lump_p->name, lump_p->name); + if (lump_p->size != lump_p->disksize) + { + Con_Printf("Custom file has mismatched lump size ( %i vs. %i )\n", lump_p->size, lump_p->disksize); + return FALSE; + } + if (lump_p->size < 1) + { + Con_Printf("Custom file has bogus lump size %i\n", lump_p->size); + return FALSE; + } + if (lump_p->filepos < sizeof(wadinfo_t)) + { + Con_Printf("Custom file has bogus lump offset %i\n", lump_p->filepos); + return FALSE; + } + if (lump_p->size + lump_p->filepos > header.infotableofs) + { + Con_Printf("Custom file has bogus lump %i\n", 0); + return FALSE; + } + wad->cacheMax = cacheMax; + wad->lumpCount = 1; + wad->cacheCount = 0; + wad->name = Mem_Strdup("tempdecal.wad"); + Draw_AllocateCacheSpace(wad, cacheMax, 0); + Draw_CacheWadHandler(wad, NULL, 0); + return TRUE; +} + +/* <1d0f8> ../engine/draw.c:154 */ +void Draw_MiptexTexture(cachewad_t *wad, unsigned char *data) +{ + texture_t *tex; + miptex_t *mip; + miptex_t tmp; + int i; + int pix; + int paloffset; + int palette; + u_short nSize; + byte *pal; + + if (wad->cacheExtra != 24 + OFFSET_DATAEXTRA_SIZE) + Sys_Error("Draw_MiptexTexture: Bad cached wad %s\n", wad->name); + + tex = (texture_t *)data; + mip = (miptex_t *)(data + wad->cacheExtra); + tmp = *mip; + + tex->width = LittleLong(tmp.width); + tex->height = LittleLong(tmp.height); + tex->anim_max = 0; + tex->anim_min = 0; + tex->anim_total = 0; + tex->alternate_anims = 0; + tex->anim_next = 0; + + for (i = 0; i < MIPLEVELS; i++) + tex->offsets[i] = wad->cacheExtra + LittleLong(tmp.offsets[i]); + + pix = tex->width * tex->height; + palette = (pix>>2) + (pix>>4) + (pix>>6) + pix; + paloffset = tex->offsets[0] + palette + 2; + nSize = *(u_short *)&data[wad->cacheExtra + 40 + palette]; + pal = (byte *)tex + paloffset; + tex->paloffset = paloffset; + + if (gfCustomBuild) + { + Q_strncpy(tex->name, szCustName, 15); + tex->name[15] = 0; + } +#ifdef SWDS + if (pal[765] || pal[766] || pal[767] != -1) + tex->name[0] = '}'; + else + tex->name[0] = '{'; + +#else // SWDS + for (i = 0; i < nSize; i++) + { + pal[3 * i] = texgammatable[pal[3 * i] & 0xFF]; + pal[3 * i + 1] = texgammatable[pal[3 * i + 1] & 0xFF]; + pal[3 * i + 2] = texgammatable[pal[3 * i + 2] & 0xFF]; + } + if (pal[765] || pal[766] || pal[767] != -1) + { + tex->name[0] = '}'; + if (gfCustomBuild) + GL_UnloadTexture(tex); + paloffset = GL_LoadTexture2(data, GLT_DECAL, tex->width, tex->height, v8, TRUE, 3, pal, gl_filter_max); + else + { + tex->name[0] = '{'; + paloffset = GL_LoadTexture2(data->name, GLT_DECAL, data->width, data->height, v8, TRUE, 1, pal, gl_filter_max); + } + tex->gl_texturenum = paloffset; +#endif // SWDS +} + +/* <20165> ../engine/decals.c:218 */ +void Draw_CacheWadHandler(cachewad_t *wad, PFNCACHE fn, int extraDataSize) +{ + wad->pfnCacheBuild = fn; + wad->cacheExtra = extraDataSize; +} + +/* <20192> ../engine/decals.c:230 */ +void Draw_FreeWad(cachewad_t *pWad) +{ + int i; + cachepic_t *pic; + + if (!pWad) + return; + + if (pWad->lumps) + Mem_Free(pWad->lumps); + + pWad->lumps = NULL; + Mem_Free(pWad->name); + if (pWad->numpaths) + { + for (i = 0; i < pWad->numpaths; i++) + { + Mem_Free(pWad->basedirs[i]); + pWad->basedirs[i] = NULL; + } + Mem_Free(pWad->basedirs); + pWad->basedirs = NULL; + } + if (pWad->lumppathindices) + { + Mem_Free(pWad->lumppathindices); + pWad->lumppathindices = NULL; + } + if (pWad->cache) + { + #ifndef SWDS + if (pWad->tempWad) + { + Mem_Free(pWad->cache); + pWad->cache = NULL; + return; + } + #endif // SWDS + for (i = 0, pic = pWad->cache; i < pWad->cacheCount; i++, pic++) + { + if (Cache_Check(&pic->cache)) + Cache_Free(&pic->cache); + } + Mem_Free(pWad->cache); + pWad->cache = NULL; + } +} + +/* <2021e> ../engine/decals.c:292 */ +NOXREF void Draw_DecalSetName(int decal, char *name) +{ + //Used Host_Frame -> CL_ReadPackets -> CL_ProcessFile -> CL_PrecacheResources -> Draw_DecalSetName + if (decal >= MAX_DECALS) + return; + + int len = sizeof(decal_names[0]) - 1; + Q_strncpy(decal_names[decal], name, len); + decal_names[decal][len] = 0; +} + +/* <20299> ../engine/decals.c:305 */ +NOXREF int Draw_DecalIndex(int id) +{ + //Used hw -> CL_Restore + char tmp[32]; + char *pName; + if (!decal_names[id]) + Sys_Error("Used decal #%d without a name\n", id); + + pName = decal_names[id]; + if (!Host_IsServerActive() && violence_hblood.value == 0.0f && !Q_strncmp(pName, "{blood", 6)) + { + Q_snprintf(tmp, sizeof(tmp), "{yblood%s", pName + 6); + } + return Draw_CacheIndex(decal_wad, tmp); +} + +/* <1fd08> ../engine/decals.c:324 */ +int Draw_DecalCount(void) +{ + if (decal_wad) + return decal_wad->lumpCount; + return 0; +} + +/* <2033e> ../engine/decals.c:336 */ +int Draw_DecalSize(int number) +{ + if (decal_wad) + { + if (decal_wad->lumpCount > number) + return decal_wad->lumps[number].size; + } + return 0; +} + +/* <1fd17> ../engine/decals.c:347 */ +const char *Draw_DecalName(int number) +{ + if (decal_wad) + { + if (decal_wad->lumpCount > number) + return decal_wad->lumps[number].name; + } + return NULL; +} + +/* <20d78> ../engine/decals.c:358 */ +NOXREF texture_t *Draw_DecalTexture(int index) +{ + texture_t *retval; + customization_t *pCust; + + if (index >= 0) + retval = (texture_t *)Draw_CacheGet(decal_wad, index); + else + { + pCust = g_pcl.players[~index].customdata.pNext; + if (!pCust || !pCust->bInUse || !pCust->pInfo || !pCust->pBuffer) + Sys_Error("Failed to load custom decal for player #%i:%s using default decal 0.\n",~index,g_pcl.players[~index].name); + + retval = (texture_t *)Draw_CustomCacheGet((cachewad_t *)pCust->pInfo, pCust->pBuffer, pCust->resource.nDownloadSize, pCust->nUserData1); + if (!retval) + retval = (texture_t *)Draw_CacheGet(decal_wad, 0); + } + return retval; +} + +/* <1fdda> ../engine/decals.c:405 */ +int Draw_CacheByIndex(cachewad_t *wad, int nIndex, int playernum) +{ + int i; + cachepic_t *pic; + char szTestName[32]; + Q_snprintf(szTestName, sizeof(szTestName), "%03i%02i", playernum, nIndex); + for (i = 0, pic = wad->cache; i < wad->cacheCount; i++, pic++) + { + if (!Q_strcmp(szTestName, pic->name)) + break; + } + if (i == wad->cacheCount) + { + if (i == wad->cacheMax) + Sys_Error("Cache wad (%s) out of %d entries", wad->name, i); + wad->cacheCount++; + Q_snprintf(pic->name, sizeof(pic->name), "%s", szTestName); + } + return i; +} + +/* <203d0> ../engine/decals.c:428 */ +NOXREF int Draw_DecalIndexFromName(char *name) +{ + char tmpName[16]; + Q_strncpy(tmpName, name, sizeof(tmpName) - 1); + tmpName[sizeof(tmpName) - 1] = 0; + + if (tmpName[0] == '}') + tmpName[0] = '{'; + + for (int i = 0; i < MAX_DECALS; i++) + { + if (*decal_names[i] && !Q_strcmp(tmpName, decal_names[i])) + return i; + } + return 0; +} + +/* <2041b> ../engine/decals.c:459 */ +void Decal_ReplaceOrAppendLump(lumplist_t **ppList, lumpinfo_t *lump, qboolean bsecondlump) +{ + lumplist_t *p; + for (p = *ppList; p != NULL; p = p->next) + { + if (!Q_stricmp(lump->name, p->lump->name)) + { + Mem_Free(p->lump); + p->lump = (lumpinfo_t *)Mem_Malloc(sizeof(lumpinfo_t)); + Q_memcpy(p->lump, lump, sizeof(lumpinfo_t)); + p->breplaced = bsecondlump; + return; + } + } + + p = (lumplist_t *)Mem_Malloc(sizeof(lumplist_t)); + Q_memset(p, 0, sizeof(lumplist_t)); + p->lump = (lumpinfo_t *)Mem_Malloc(sizeof(lumpinfo_t)); + Q_memcpy(p->lump, lump, sizeof(lumpinfo_t)); + p->breplaced = bsecondlump; + p->next = *ppList; + *ppList = p; +} + +/* <1fcb4> ../engine/decals.c:493 */ +int Decal_CountLumps(lumplist_t *plist) +{ + int c = 0; + lumplist_t *p = plist; + while (p != NULL) + { + p = p->next; + c++; + } + return c; +} + +/* <1fce8> ../engine/decals.c:507 */ +int Decal_SizeLumps(lumplist_t *plist) +{ + return (sizeof(lumpinfo_t) * Decal_CountLumps(plist)); +} + +/* <2050f> ../engine/decals.c:512 */ +void Decal_MergeInDecals(cachewad_t *pwad, const char *pathID) +{ + int i; + int lumpcount; + lumpinfo_t *lump; + lumplist_t *lumplist; + lumplist_t *plump; + lumplist_t *pnext; + cachewad_t *final; + + if (!pwad) + Sys_Error("Decal_MergeInDecals called with NULL wad\n"); + + lumplist = NULL; + if (!decal_wad) + { + pwad->numpaths = 1; + decal_wad = pwad; + + pwad->basedirs = (char **)Mem_Malloc(sizeof(char *)); + *decal_wad->basedirs = Mem_Strdup(pathID); + decal_wad->lumppathindices = (int *)Mem_Malloc(sizeof(int *) * decal_wad->cacheMax); + Q_memset(decal_wad->lumppathindices, 0, sizeof(int *) * decal_wad->cacheMax); + return; + } + + final = (cachewad_t *)Mem_Malloc(sizeof(cachewad_t)); + Q_memset(final, 0, sizeof(cachewad_t)); + + for (i = 0, lump = decal_wad->lumps; i < decal_wad->lumpCount; i++, lump++) + Decal_ReplaceOrAppendLump(&lumplist, lump, FALSE); + for (i = 0, lump = pwad->lumps; i < pwad->lumpCount; i++, lump++) + Decal_ReplaceOrAppendLump(&lumplist, lump, TRUE); + + final->lumpCount = Decal_CountLumps(lumplist); + final->cacheCount = 0; + final->cacheMax = decal_wad->cacheMax; + final->name = Mem_Strdup(decal_wad->name); + Draw_AllocateCacheSpace(final, final->cacheMax, 0); + final->pfnCacheBuild = decal_wad->pfnCacheBuild; + final->cacheExtra = decal_wad->cacheExtra; + final->lumppathindices = (int *)Mem_Malloc(sizeof(int *) * final->cacheMax); + Q_memset(final->lumppathindices, 0, sizeof(int *) * final->cacheMax); + + final->numpaths = 2; + final->basedirs = (char **)Mem_Malloc(sizeof(char *) * 2); + final->basedirs[0] = Mem_Strdup(*decal_wad->basedirs); + final->basedirs[1] = Mem_Strdup(pathID); + final->lumps = (lumpinfo_t *)Mem_Malloc(Decal_SizeLumps(lumplist)); + + lumpcount = 0; + plump = lumplist; + lump = final->lumps; + while (plump != NULL) + { + pnext = plump->next; + Q_memcpy(lump, plump->lump, sizeof(lumpinfo_t)); + Mem_Free(plump->lump); + plump->lump = NULL; + + final->lumppathindices[lumpcount++] = (plump->breplaced != 0); + Mem_Free(plump); + plump = pnext; + lump++; + } + + Draw_FreeWad(decal_wad); + if (decal_wad) + Mem_Free(decal_wad); + decal_wad = final; + Draw_FreeWad(pwad); + Mem_Free(pwad); +} + +/* <20779> ../engine/decals.c:622 */ +void Decal_Init(void) +{ + int i; + int filesize; + FileHandle_t hfile; + cachewad_t *decal_wad_temp; + char pszPathID[2][15] = { "DEFAULTGAME", "GAME" }; + + Draw_DecalShutdown(); + for (i = 0; i < 2; i++) + { + hfile = FS_OpenPathID("decals.wad", "rb", pszPathID[i]); + if (i == 0 && !hfile) + Sys_Error("Couldn't find '%s' in \"%s\" search path\n", "decals.wad", pszPathID[i]); + + filesize = FS_Size(hfile); + decal_wad_temp = (cachewad_t *)Mem_Malloc(sizeof(cachewad_t)); + Q_memset(decal_wad_temp, 0, sizeof(cachewad_t)); + + Draw_CacheWadInitFromFile(hfile, filesize, "decals.wad", MAX_DECALS, decal_wad_temp); + Draw_CacheWadHandler(decal_wad_temp, Draw_MiptexTexture, 24 + OFFSET_DATAEXTRA_SIZE); + Decal_MergeInDecals(decal_wad_temp, pszPathID[i]); + FS_Close(hfile); + } + + sv_decalnamecount = Draw_DecalCount(); + if (sv_decalnamecount > MAX_DECALS) + Sys_Error("Too many decals: %d / %d\n", sv_decalnamecount, MAX_DECALS); + + for (i = 0; i < sv_decalnamecount; i++) + { + Q_memset(&sv_decalnames[i], 0, sizeof(decalname_t)); + Q_strncpy(sv_decalnames[i].name, Draw_DecalName(i), 15); + sv_decalnames[i].name[15] = 0; + } +} + +/* <20c56> ../engine/decals.c:673 */ +qboolean CustomDecal_Validate(void *raw, int nFileSize) +{ + qboolean bret = FALSE; + cachewad_t *fakewad = NULL; + fakewad = (cachewad_t *)Mem_ZeroMalloc(sizeof(cachewad_t)); + if (fakewad) + { + bret = CustomDecal_Init(fakewad, raw, nFileSize, -2); + if (bret) + bret = (Draw_CustomCacheGet(fakewad, raw, nFileSize, 0) != NULL); + + Draw_FreeWad(fakewad); + Mem_Free(fakewad); + } + return bret; +} + +/* <1fe34> ../engine/decals.c:694 */ +qboolean CustomDecal_Init(struct cachewad_s *wad, void *raw, int nFileSize, int playernum) +{ + qboolean bret = Draw_CustomCacheWadInit(16, wad, raw, nFileSize); + if (bret) + { + Draw_CacheWadHandler(wad, Draw_MiptexTexture, 24 + OFFSET_DATAEXTRA_SIZE); + for (int i = 0; i < wad->lumpCount; i++) + Draw_CacheByIndex(wad, i, playernum); + } + return bret; +} + +/* <20964> ../engine/decals.c:717 */ +NOXREF void *Draw_CacheGet(cachewad_t *wad, int index) +{ + int i; + void *dat; + char *path; + char name[16]; + char clean[16]; + cachepic_t *pic; + lumpinfo_t *pLump; + + if (index >= wad->cacheCount) + Sys_Error("Cache wad indexed before load %s: %d", wad->name, index); + + pic = wad->cache; + dat = Cache_Check(&pic[index].cache); + path = pic[index].name; + +#ifdef SWDS + if (dat == NULL) +#else + if (wad->tempWad || dat == NULL) +#endif // SWDS + { + COM_FileBase(path, name); + W_CleanupName(name, clean); + for (i = 0, pLump = wad->lumps; i < wad->lumpCount; i++, pLump++) + { + if (!Q_strcmp(clean, pLump->name)) + break; + } + if (i >= wad->lumpCount) + return NULL; + + if (Draw_CacheReload(wad, i, pLump, pic, clean, path)) + { + if (pic->cache.data == NULL) + Sys_Error("Draw_CacheGet: failed to load %s", path); + dat = pic->cache.data; + } + } + return dat; +} + +/* <20ba5> ../engine/decals.c:778 */ +void *Draw_CustomCacheGet(cachewad_t *wad, void *raw, int rawsize, int index) +{ + void *pdata; + cachepic_t *pic; + char name[16]; + char clean[16]; + + if (wad->cacheCount <= index) + Sys_Error("Cache wad indexed before load %s: %d", wad->name, index); + + pic = &wad->cache[index]; + pdata = Cache_Check(&pic->cache); + if (!pdata) + { + COM_FileBase(pic->name, name); + W_CleanupName(name, clean); + + if (Draw_CacheLoadFromCustom(clean, wad, raw, rawsize, pic)) + { + if (!pic->cache.data) + Sys_Error("Draw_CacheGet: failed to load %s", pic->name); + pdata = pic->cache.data; + } + } + return pdata; +} + +/* <208ab> ../engine/decals.c:822 */ +NOXREF qboolean Draw_CacheReload(cachewad_t *wad, int i, lumpinfo_t *pLump, cachepic_t *pic, char *clean, char *path) +{ + int len; + byte *buf; + FileHandle_t hFile; + //const char *pathID;//unused? + + if (wad->numpaths < 1) + hFile = FS_Open(wad->name, "rb"); + else + hFile = FS_OpenPathID(wad->name, "rb", wad->basedirs[wad->lumppathindices[i]]); + if (!hFile) + return FALSE; + len = FS_Size(hFile); +#ifndef SWDS + if (wad->tempWad) + { + buf = (byte *)Hunk_TempAlloc(wad->cacheExtra + pLump->size + 1); + pic->cache.data = buf; + } + else +#endif // SWDS + buf = (byte *)Cache_Alloc(&pic->cache, wad->cacheExtra + pLump->size + 1, clean); + if (!buf) + Sys_Error("Draw_CacheGet: not enough space for %s in %s", path, wad->name); + buf[pLump->size + wad->cacheExtra] = 0; + + FS_Seek(hFile, pLump->filepos, FILESYSTEM_SEEK_HEAD); + FS_Read((char *)&buf[wad->cacheExtra], pLump->size, 1, hFile); + FS_Close(hFile); + + if (wad->pfnCacheBuild) + wad->pfnCacheBuild(wad, buf); + + return TRUE; +} + +/* <20a15> ../engine/decals.c:871 */ +qboolean Draw_ValidateCustomLogo(cachewad_t *wad, unsigned char *data, lumpinfo_t *lump) +{ + texture_t tex; + miptex_t *mip; + miptex_t tmp; + int pix; + int pixoffset; + int paloffset; + int palettesize; + int nSize; + + if (wad->cacheExtra != 24 + OFFSET_DATAEXTRA_SIZE) + { + Con_Printf(__FUNCTION__ ": Bad cached wad %s\n", wad->name); + return FALSE; + } + + tex = *(texture_t *)data; + mip = (miptex_t *)(data + wad->cacheExtra); + tmp = *mip; + + tex.width = LittleLong(tmp.width); + tex.height = LittleLong(tmp.height); + tex.anim_max = 0; + tex.anim_min = 0; + tex.anim_total = 0; + tex.alternate_anims = NULL; + tex.anim_next = NULL; + + for (int i = 0; i < MIPLEVELS; i++) + tex.offsets[i] = wad->cacheExtra + LittleLong(tmp.offsets[i]); + + pix = tex.width * tex.height; + pixoffset = pix + (pix>>2) + (pix>>4) + (pix>>6); + paloffset = (pix>>2) + tmp.offsets[0] + pix; + palettesize = (pix>>4) + paloffset; + nSize = *(u_short *)&data[pixoffset + 64 + OFFSET_DATAEXTRA_SIZE]; + + if (!tex.width || tex.width > 256 || tex.height > 256 + || (tmp.offsets[0] + pix != tmp.offsets[1]) + || paloffset != tmp.offsets[2] || palettesize != tmp.offsets[3]) + { + Con_Printf(__FUNCTION__ ": Bad cached wad %s\n", wad->name); + return FALSE; + } + if (nSize > 256) + { + Con_Printf(__FUNCTION__ ": Bad cached wad palette size %i on %s\n", nSize, wad->name); + return FALSE; + } + nSize = pixoffset + LittleLong(tmp.offsets[0]) + 3 * nSize + 2; + if (nSize > lump->disksize) + { + Con_Printf(__FUNCTION__ ": Bad cached wad %s\n", wad->name); + return FALSE; + } + return TRUE; +} + +/* <20aec> ../engine/decals.c:942 */ +qboolean Draw_CacheLoadFromCustom(char *clean, cachewad_t *wad, void *raw, int rawsize, cachepic_t *pic) +{ + int idx; + byte *buf; + lumpinfo_t *pLump; + + idx = 0; + if (Q_strlen(clean) > 4) + { + idx = Q_atoi(clean + 3); + if (idx < 0 || idx >= wad->lumpCount) + return FALSE; + + } + pLump = &wad->lumps[idx]; + buf = (byte *)Cache_Alloc(&pic->cache, wad->cacheExtra + pLump->size + 1, clean); + if (!buf) + Sys_Error("Draw_CacheGet: not enough space for %s in %s", clean, wad->name); + + buf[wad->cacheExtra + pLump->size] = 0; + Q_memcpy((char *)buf + wad->cacheExtra, (char *)raw + pLump->filepos, pLump->size); + + if (Draw_ValidateCustomLogo(wad, buf, pLump)) + { + gfCustomBuild = TRUE; + Q_strcpy(szCustName, "T"); + Q_memcpy(&szCustName[1], clean, 5); + szCustName[6] = 0; + + if (wad->pfnCacheBuild) + wad->pfnCacheBuild(wad, buf); + gfCustomBuild = FALSE; + return TRUE; + } + return FALSE; +} + +/* <20257> ../engine/decals.c:999 */ +NOXREF int Draw_CacheIndex(cachewad_t *wad, char *path) +{ + int i; + cachepic_t *pic; + for (i = 0, pic = wad->cache; i < wad->cacheCount; i++, pic++) + { + if (!Q_strcmp(path, pic->name)) + break; + } + if (i == wad->cacheCount) + { + if (wad->cacheMax == wad->cacheCount) + Sys_Error("Cache wad (%s) out of %d entries"); + + wad->cacheCount++; + Q_strncpy(wad->name, path, 63); + wad->name[63] = 0; + } + return i; +} + +/* <20e1e> ../engine/decals.c:1025 */ +NOXREF int Draw_CacheFindIndex(cachewad_t *wad, char *path) +{ + cachepic_t *pic = wad->cache; + for (int i = 0; i < wad->cacheCount; i++, pic++) + { + if (!Q_strcmp(path, pic->name)) + return i; + } + return -1; +} diff --git a/rehlds/engine/delta.cpp b/rehlds/engine/delta.cpp new file mode 100644 index 0000000..6b29b65 --- /dev/null +++ b/rehlds/engine/delta.cpp @@ -0,0 +1,1538 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +#ifndef Defines_and_Variables_region + +#define DT_BYTE BIT(0) // A byte +#define DT_SHORT BIT(1) // 2 byte field +#define DT_FLOAT BIT(2) // A floating point field +#define DT_INTEGER BIT(3) // 4 byte integer +#define DT_ANGLE BIT(4) // A floating point angle +#define DT_TIMEWINDOW_8 BIT(5) // A floating point timestamp relative to server time +#define DT_TIMEWINDOW_BIG BIT(6) // A floating point timestamp relative to server time (with more precision and custom multiplier) +#define DT_STRING BIT(7) // A null terminated string, sent as 8 byte chars +#define DT_SIGNED BIT(31) // sign modificator + +#define FDT_MARK BIT(0) // Delta mark for sending + + +/* <23bb1> ../engine/delta.c:47 */ +typedef struct delta_link_s +{ + delta_link_t *next; + delta_description_t *delta; +} delta_link_t; + +/* <23be5> ../engine/delta.c:53 */ +typedef struct delta_definition_s +{ + char *fieldName; + int fieldOffset; +} delta_definition_t; + +/* <23c19> ../engine/delta.c:59 */ +typedef struct delta_definition_list_s +{ + delta_definition_list_t *next; + char *ptypename; + int numelements; + delta_definition_t *pdefinition; +} delta_definition_list_t; + +/* <23c69> ../engine/delta.c:67 */ +typedef struct delta_registry_s +{ + delta_registry_t *next; + char *name; + delta_t *pdesc; +} delta_registry_t; + + +delta_definition_list_t *g_defs; +delta_encoder_t *g_encoders; +delta_registry_t *g_deltaregistry; + +#endif // Defines_and_Variables_region + +#ifndef Delta_definitions_region + +#define DELTA_D_DEF(member) #member, offsetof(delta_description_s, member) +#define DELTA_DEF(structname, member) { #member, offsetof(structname, member) } + +static delta_definition_t g_DeltaDataDefinition[] = +{ + DELTA_DEF(delta_description_s, fieldType), + DELTA_DEF(delta_description_s, fieldName), + DELTA_DEF(delta_description_s, fieldOffset), + DELTA_DEF(delta_description_s, fieldSize), + DELTA_DEF(delta_description_s, significant_bits), + DELTA_DEF(delta_description_s, premultiply), + DELTA_DEF(delta_description_s, postmultiply), + DELTA_DEF(delta_description_s, flags), +}; + +static delta_description_t g_MetaDescription[] = +{ + { DT_INTEGER, DELTA_D_DEF(fieldType), 1, 32, 1.0, 1.0, 0, 0, 0 }, + { DT_STRING, DELTA_D_DEF(fieldName), 1, 1, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(fieldOffset), 1, 16, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(fieldSize), 1, 8, 1.0, 1.0, 0, 0, 0 }, + { DT_INTEGER, DELTA_D_DEF(significant_bits), 1, 8, 1.0, 1.0, 0, 0, 0 }, + { DT_FLOAT, DELTA_D_DEF(premultiply), 1, 32, 4000.0, 1.0, 0, 0, 0 }, + { DT_FLOAT, DELTA_D_DEF(postmultiply), 1, 32, 4000.0, 1.0, 0, 0, 0 }, +}; + +delta_t g_MetaDelta[] = +{ + { 0, ARRAYSIZE(g_MetaDescription), "", NULL, g_MetaDescription }, +}; + +static delta_definition_t g_EventDataDefinition[] = +{ + DELTA_DEF(event_args_s, entindex), + DELTA_DEF(event_args_s, origin[0]), + DELTA_DEF(event_args_s, origin[1]), + DELTA_DEF(event_args_s, origin[2]), + DELTA_DEF(event_args_s, angles[0]), + DELTA_DEF(event_args_s, angles[1]), + DELTA_DEF(event_args_s, angles[2]), + DELTA_DEF(event_args_s, fparam1), + DELTA_DEF(event_args_s, fparam2), + DELTA_DEF(event_args_s, iparam1), + DELTA_DEF(event_args_s, iparam2), + DELTA_DEF(event_args_s, bparam1), + DELTA_DEF(event_args_s, bparam2), + DELTA_DEF(event_args_s, ducking), +}; +static delta_definition_t g_EntityDataDefinition[] = +{ + DELTA_DEF(entity_state_s, startpos[0]), + DELTA_DEF(entity_state_s, startpos[1]), + DELTA_DEF(entity_state_s, startpos[2]), + DELTA_DEF(entity_state_s, endpos[0]), + DELTA_DEF(entity_state_s, endpos[1]), + DELTA_DEF(entity_state_s, endpos[2]), + DELTA_DEF(entity_state_s, impacttime), + DELTA_DEF(entity_state_s, starttime), + DELTA_DEF(entity_state_s, origin[0]), + DELTA_DEF(entity_state_s, origin[1]), + DELTA_DEF(entity_state_s, origin[2]), + DELTA_DEF(entity_state_s, angles[0]), + DELTA_DEF(entity_state_s, angles[1]), + DELTA_DEF(entity_state_s, angles[2]), + DELTA_DEF(entity_state_s, modelindex), + DELTA_DEF(entity_state_s, frame), + DELTA_DEF(entity_state_s, movetype), + DELTA_DEF(entity_state_s, colormap), + DELTA_DEF(entity_state_s, skin), + DELTA_DEF(entity_state_s, solid), + DELTA_DEF(entity_state_s, scale), + DELTA_DEF(entity_state_s, effects), + DELTA_DEF(entity_state_s, sequence), + DELTA_DEF(entity_state_s, animtime), + DELTA_DEF(entity_state_s, framerate), + DELTA_DEF(entity_state_s, controller[0]), + DELTA_DEF(entity_state_s, controller[1]), + DELTA_DEF(entity_state_s, controller[2]), + DELTA_DEF(entity_state_s, controller[3]), + DELTA_DEF(entity_state_s, blending[0]), + DELTA_DEF(entity_state_s, blending[1]), + DELTA_DEF(entity_state_s, body), + DELTA_DEF(entity_state_s, owner), + DELTA_DEF(entity_state_s, rendermode), + DELTA_DEF(entity_state_s, renderamt), + DELTA_DEF(entity_state_s, renderfx), + DELTA_DEF(entity_state_s, rendercolor.r), + DELTA_DEF(entity_state_s, rendercolor.g), + DELTA_DEF(entity_state_s, rendercolor.b), + DELTA_DEF(entity_state_s, weaponmodel), + DELTA_DEF(entity_state_s, gaitsequence), + DELTA_DEF(entity_state_s, mins[0]), + DELTA_DEF(entity_state_s, mins[1]), + DELTA_DEF(entity_state_s, mins[2]), + DELTA_DEF(entity_state_s, maxs[0]), + DELTA_DEF(entity_state_s, maxs[1]), + DELTA_DEF(entity_state_s, maxs[2]), + DELTA_DEF(entity_state_s, aiment), + DELTA_DEF(entity_state_s, basevelocity[0]), + DELTA_DEF(entity_state_s, basevelocity[1]), + DELTA_DEF(entity_state_s, basevelocity[2]), + DELTA_DEF(entity_state_s, friction), + DELTA_DEF(entity_state_s, gravity), + DELTA_DEF(entity_state_s, spectator), + DELTA_DEF(entity_state_s, velocity[0]), + DELTA_DEF(entity_state_s, velocity[1]), + DELTA_DEF(entity_state_s, velocity[2]), + DELTA_DEF(entity_state_s, team), + DELTA_DEF(entity_state_s, playerclass), + DELTA_DEF(entity_state_s, health), + DELTA_DEF(entity_state_s, usehull), + DELTA_DEF(entity_state_s, oldbuttons), + DELTA_DEF(entity_state_s, onground), + DELTA_DEF(entity_state_s, iStepLeft), + DELTA_DEF(entity_state_s, flFallVelocity), + DELTA_DEF(entity_state_s, weaponanim), + DELTA_DEF(entity_state_s, eflags), + DELTA_DEF(entity_state_s, iuser1), + DELTA_DEF(entity_state_s, iuser2), + DELTA_DEF(entity_state_s, iuser3), + DELTA_DEF(entity_state_s, iuser4), + DELTA_DEF(entity_state_s, fuser1), + DELTA_DEF(entity_state_s, fuser2), + DELTA_DEF(entity_state_s, fuser3), + DELTA_DEF(entity_state_s, fuser4), + DELTA_DEF(entity_state_s, vuser1[0]), + DELTA_DEF(entity_state_s, vuser1[1]), + DELTA_DEF(entity_state_s, vuser1[2]), + DELTA_DEF(entity_state_s, vuser2[0]), + DELTA_DEF(entity_state_s, vuser2[1]), + DELTA_DEF(entity_state_s, vuser2[2]), + DELTA_DEF(entity_state_s, vuser3[0]), + DELTA_DEF(entity_state_s, vuser3[1]), + DELTA_DEF(entity_state_s, vuser3[2]), + DELTA_DEF(entity_state_s, vuser4[0]), + DELTA_DEF(entity_state_s, vuser4[1]), + DELTA_DEF(entity_state_s, vuser4[2]), +}; +static delta_definition_t g_UsercmdDataDefinition[] = +{ + DELTA_DEF(usercmd_s, lerp_msec), + DELTA_DEF(usercmd_s, msec), + DELTA_DEF(usercmd_s, lightlevel), + DELTA_DEF(usercmd_s, viewangles[0]), + DELTA_DEF(usercmd_s, viewangles[1]), + DELTA_DEF(usercmd_s, viewangles[2]), + DELTA_DEF(usercmd_s, buttons), + DELTA_DEF(usercmd_s, forwardmove), + DELTA_DEF(usercmd_s, sidemove), + DELTA_DEF(usercmd_s, upmove), + DELTA_DEF(usercmd_s, impulse), + DELTA_DEF(usercmd_s, weaponselect), + DELTA_DEF(usercmd_s, impact_index), + DELTA_DEF(usercmd_s, impact_position[0]), + DELTA_DEF(usercmd_s, impact_position[1]), + DELTA_DEF(usercmd_s, impact_position[2]), +}; +static delta_definition_t g_WeaponDataDefinition[] = +{ + DELTA_DEF(weapon_data_s, m_iId), + DELTA_DEF(weapon_data_s, m_iClip), + DELTA_DEF(weapon_data_s, m_flNextPrimaryAttack), + DELTA_DEF(weapon_data_s, m_flNextSecondaryAttack), + DELTA_DEF(weapon_data_s, m_flTimeWeaponIdle), + DELTA_DEF(weapon_data_s, m_fInReload), + DELTA_DEF(weapon_data_s, m_fInSpecialReload), + DELTA_DEF(weapon_data_s, m_flNextReload), + DELTA_DEF(weapon_data_s, m_flPumpTime), + DELTA_DEF(weapon_data_s, m_fReloadTime), + DELTA_DEF(weapon_data_s, m_fAimedDamage), + DELTA_DEF(weapon_data_s, m_fNextAimBonus), + DELTA_DEF(weapon_data_s, m_fInZoom), + DELTA_DEF(weapon_data_s, m_iWeaponState), + DELTA_DEF(weapon_data_s, iuser1), + DELTA_DEF(weapon_data_s, iuser2), + DELTA_DEF(weapon_data_s, iuser3), + DELTA_DEF(weapon_data_s, iuser4), + DELTA_DEF(weapon_data_s, fuser1), + DELTA_DEF(weapon_data_s, fuser2), + DELTA_DEF(weapon_data_s, fuser3), + DELTA_DEF(weapon_data_s, fuser4), +}; +static delta_definition_t g_ClientDataDefinition[] = +{ + DELTA_DEF(clientdata_s, origin[0]), + DELTA_DEF(clientdata_s, origin[1]), + DELTA_DEF(clientdata_s, origin[2]), + DELTA_DEF(clientdata_s, velocity[0]), + DELTA_DEF(clientdata_s, velocity[1]), + DELTA_DEF(clientdata_s, velocity[2]), + DELTA_DEF(clientdata_s, viewmodel), + DELTA_DEF(clientdata_s, punchangle[0]), + DELTA_DEF(clientdata_s, punchangle[1]), + DELTA_DEF(clientdata_s, punchangle[2]), + DELTA_DEF(clientdata_s, flags), + DELTA_DEF(clientdata_s, waterlevel), + DELTA_DEF(clientdata_s, watertype), + DELTA_DEF(clientdata_s, view_ofs[0]), + DELTA_DEF(clientdata_s, view_ofs[1]), + DELTA_DEF(clientdata_s, view_ofs[2]), + DELTA_DEF(clientdata_s, health), + DELTA_DEF(clientdata_s, bInDuck), + DELTA_DEF(clientdata_s, weapons), + DELTA_DEF(clientdata_s, flTimeStepSound), + DELTA_DEF(clientdata_s, flDuckTime), + DELTA_DEF(clientdata_s, flSwimTime), + DELTA_DEF(clientdata_s, waterjumptime), + DELTA_DEF(clientdata_s, maxspeed), + DELTA_DEF(clientdata_s, m_iId), + DELTA_DEF(clientdata_s, ammo_nails), + DELTA_DEF(clientdata_s, ammo_shells), + DELTA_DEF(clientdata_s, ammo_cells), + DELTA_DEF(clientdata_s, ammo_rockets), + DELTA_DEF(clientdata_s, m_flNextAttack), + DELTA_DEF(clientdata_s, physinfo), + DELTA_DEF(clientdata_s, fov), + DELTA_DEF(clientdata_s, weaponanim), + DELTA_DEF(clientdata_s, tfstate), + DELTA_DEF(clientdata_s, pushmsec), + DELTA_DEF(clientdata_s, deadflag), + DELTA_DEF(clientdata_s, iuser1), + DELTA_DEF(clientdata_s, iuser2), + DELTA_DEF(clientdata_s, iuser3), + DELTA_DEF(clientdata_s, iuser4), + DELTA_DEF(clientdata_s, fuser1), + DELTA_DEF(clientdata_s, fuser2), + DELTA_DEF(clientdata_s, fuser3), + DELTA_DEF(clientdata_s, fuser4), + DELTA_DEF(clientdata_s, vuser1[0]), + DELTA_DEF(clientdata_s, vuser1[1]), + DELTA_DEF(clientdata_s, vuser1[2]), + DELTA_DEF(clientdata_s, vuser2[0]), + DELTA_DEF(clientdata_s, vuser2[1]), + DELTA_DEF(clientdata_s, vuser2[2]), + DELTA_DEF(clientdata_s, vuser3[0]), + DELTA_DEF(clientdata_s, vuser3[1]), + DELTA_DEF(clientdata_s, vuser3[2]), + DELTA_DEF(clientdata_s, vuser4[0]), + DELTA_DEF(clientdata_s, vuser4[1]), + DELTA_DEF(clientdata_s, vuser4[2]), +}; + +#endif + + +/* <23f5d> ../engine/delta.c:346 */ +delta_description_t *DELTA_FindField(delta_t *pFields, const char *pszField) +{ + int fieldCount = pFields->fieldCount; + delta_description_t *pitem = pFields->pdd; + + for (int i = 0; i < fieldCount; i++, pitem++) + { + if (!Q_stricmp(pitem->fieldName, pszField)) + { + return pitem; + } + } + + Con_Printf(__FUNCTION__ ": Warning, couldn't find %s\n", pszField); + return NULL; +} + +/* <23fd7> ../engine/delta.c:370 */ +int DELTA_FindFieldIndex(struct delta_s *pFields, const char *fieldname) +{ + int fieldCount = pFields->fieldCount; + delta_description_t *pitem = pFields->pdd; + + for (int i = 0; i < fieldCount; i++, pitem++) + { + if (!Q_stricmp(pitem->fieldName, fieldname)) + { + return i; + } + } + + Con_Printf(__FUNCTION__ ": Warning, couldn't find %s\n", fieldname); + return NULL; +} + +/* <24032> ../engine/delta.c:393 */ +void DELTA_SetField(struct delta_s *pFields, const char *fieldname) +{ + delta_description_t *pTest = DELTA_FindField(pFields, fieldname); + + if (pTest) + { + pTest->flags |= FDT_MARK; + } +} + +/* <240b2> ../engine/delta.c:411 */ +void DELTA_UnsetField(struct delta_s *pFields, const char *fieldname) +{ + delta_description_t *pTest = DELTA_FindField(pFields, fieldname); + + if (pTest) + { + pTest->flags &= ~FDT_MARK; + } +} + +/* <24132> ../engine/delta.c:429 */ +void DELTA_SetFieldByIndex(struct delta_s *pFields, int fieldNumber) +{ + pFields->pdd[fieldNumber].flags |= FDT_MARK; +} + +/* <2416a> ../engine/delta.c:441 */ +void DELTA_UnsetFieldByIndex(struct delta_s *pFields, int fieldNumber) +{ + pFields->pdd[fieldNumber].flags &= ~FDT_MARK; +} + +/* <23cc4> ../engine/delta.c:453 */ +void DELTA_ClearFlags(delta_t *pFields) +{ + int i; + delta_description_t *pitem; + for (i = 0, pitem = pFields->pdd; i < pFields->fieldCount; i++, pitem++) + { + pitem->flags = 0; + } +} + +/* <241d2> ../engine/delta.c:473 */ +int DELTA_TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + char *st1, *st2; + delta_description_t *pTest; + int fieldType; + int fieldCount = pFields->fieldCount; + int length; + int different; + int neededBits = 0; + int highestBit = -1; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + different = FALSE; + + fieldType = pTest->fieldType & ~DT_SIGNED; + switch (fieldType) + { + case DT_BYTE: + different = from[pTest->fieldOffset] != to[pTest->fieldOffset]; + break; + case DT_SHORT: + different = *(uint16_t *)&from[pTest->fieldOffset] != *(uint16_t *)&to[pTest->fieldOffset]; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + different = *(uint32_t *)&from[pTest->fieldOffset] != *(uint32_t *)&to[pTest->fieldOffset]; + break; + case DT_TIMEWINDOW_8: + different = (int32_t)(*(float *)&from[pTest->fieldOffset] * 100.0) != (int32_t)(*(float *)&to[pTest->fieldOffset] * 100.0); + break; + case DT_TIMEWINDOW_BIG: + different = (int32_t)(*(float *)&from[pTest->fieldOffset] * 1000.0) != (int32_t)(*(float *)&to[pTest->fieldOffset] * 1000.0); + break; + case DT_STRING: + st1 = (char*)&from[pTest->fieldOffset]; + st2 = (char*)&to[pTest->fieldOffset]; + if (!(!*st1 && !*st2 || *st1 && *st2 && !Q_stricmp(st1, st2))) // Not sure why it is case insensitive, but it looks so + { + length = Q_strlen(st2); + } + break; + default: + Con_Printf(__FUNCTION__ ": Bad field type %i\n", fieldType); + break; + } + + if (different) + { + highestBit = i; + neededBits += fieldType == DT_STRING ? length + 8 : pTest->significant_bits; + } + } + + if (neededBits != -1) + { + neededBits += highestBit / 8 * 8 + 8; + } + + return neededBits; +} + +/* <24309> ../engine/delta.c:602 */ +int DELTA_CountSendFields(delta_t *pFields) +{ + int i, c; + int fieldCount = pFields->fieldCount; + delta_description_t *pitem; + for (i = 0, c = 0, pitem = pFields->pdd; i < fieldCount; i++, pitem++) + { + if (pitem->flags & FDT_MARK) + { + c++; + pitem->stats.sendcount++; + } + } + return c; +} + +/* <24382> ../engine/delta.c:629 */ +void DELTA_MarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + char *st1, *st2; + delta_description_t *pTest; + int fieldType; + int fieldCount = pFields->fieldCount; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + fieldType = pTest->fieldType & ~DT_SIGNED; + switch (fieldType) + { + case DT_BYTE: + if (from[pTest->fieldOffset] != to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_SHORT: + if (*(uint16_t *)&from[pTest->fieldOffset] != *(uint16_t *)&to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + if (*(uint32_t *)&from[pTest->fieldOffset] != *(uint32_t *)&to[pTest->fieldOffset]) + pTest->flags |= FDT_MARK; + break; + case DT_TIMEWINDOW_8: + if ((int32_t)(*(float *)&from[pTest->fieldOffset] * 100.0) != (int32_t)(*(float *)&to[pTest->fieldOffset] * 100.0)) + pTest->flags |= FDT_MARK; + break; + case DT_TIMEWINDOW_BIG: + if ((int32_t)(*(float *)&from[pTest->fieldOffset] * 1000.0) != (int32_t)(*(float *)&to[pTest->fieldOffset] * 1000.0)) + pTest->flags |= FDT_MARK; + break; + case DT_STRING: + st1 = (char*)&from[pTest->fieldOffset]; + st2 = (char*)&to[pTest->fieldOffset]; + if (!(!*st1 && !*st2 || *st1 && *st2 && !Q_stricmp(st1, st2))) // Not sure why it is case insensitive, but it looks so + pTest->flags |= FDT_MARK; + break; + default: + Con_Printf(__FUNCTION__ ": Bad field type %i\n", fieldType); + break; + } + } + if (pFields->conditionalencode) + pFields->conditionalencode(pFields, from, to); +} + +/* <2448d> ../engine/delta.c:738 */ +void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount) +{ + delta_description_t *pTest; + int i; + int lastbit = -1; + int bitnumber; + int fieldCount = pFields->fieldCount; + + Q_memset(bits, 0, 8); + + lastbit = -1; + bitnumber = -1; + for (i = fieldCount - 1, pTest = &pFields->pdd[i]; i >= 0; i--, pTest--) + { + if (pTest->flags & FDT_MARK) + { + if (lastbit == -1) + bitnumber = i; + bits[i > 31 ? 1 : 0] |= 1 << (i & 0x1F); + lastbit = bitnumber; + } + } + *bytecount = (lastbit >> 3) + 1; +} + +/* <2456d> ../engine/delta.c:782 */ +void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int i; + delta_description_t *pTest; + int fieldSign; + int fieldType; + + float f2; + int fieldCount = pFields->fieldCount; + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + if (!(pTest->flags & FDT_MARK)) + continue; + + fieldSign = pTest->fieldType & DT_SIGNED; + fieldType = pTest->fieldType & ~DT_SIGNED; + switch (fieldType) + { + case DT_BYTE: + if (fieldSign) + { + int8_t si8 = *(int8_t *)&to[pTest->fieldOffset]; + si8 = (int8_t)((double)si8 * pTest->premultiply); + MSG_WriteSBits(si8, pTest->significant_bits); + } + else + { + uint8_t i8 = *(uint8_t *)&to[pTest->fieldOffset]; + i8 = (uint8_t)((double)i8 * pTest->premultiply); + MSG_WriteBits(i8, pTest->significant_bits); + } + break; + case DT_SHORT: + if (fieldSign) + { + int16_t si16 = *(int16_t *)&to[pTest->fieldOffset]; + si16 = (int16_t)((double)si16 * pTest->premultiply); + MSG_WriteSBits(si16, pTest->significant_bits); + } + else + { + uint16_t i16 = *(uint16_t *)&to[pTest->fieldOffset]; + i16 = (uint16_t)((double)i16 * pTest->premultiply); + MSG_WriteBits(i16, pTest->significant_bits); + } + break; + case DT_FLOAT: + { + double val = (double)(*(float *)&to[pTest->fieldOffset]) * pTest->premultiply; + if (fieldSign) + { + MSG_WriteSBits((int32_t)val, pTest->significant_bits); + } + else + { + MSG_WriteBits((uint32_t)val, pTest->significant_bits); + } + break; + } + case DT_INTEGER: + { + if (fieldSign) + { + int32_t signedInt = *(int32_t *)&to[pTest->fieldOffset]; + if (pTest->premultiply < 0.9999 || pTest->premultiply > 1.0001) + { + signedInt = (int32_t)((double)signedInt * pTest->premultiply); + } + MSG_WriteSBits(signedInt, pTest->significant_bits); + } + else + { + uint32_t unsignedInt = *(uint32_t *)&to[pTest->fieldOffset]; + if (pTest->premultiply < 0.9999 || pTest->premultiply > 1.0001) + { + unsignedInt = (uint32_t)((double)unsignedInt * pTest->premultiply); + } + MSG_WriteBits(unsignedInt, pTest->significant_bits); + } + break; + } + case DT_ANGLE: + f2 = *(float *)&to[pTest->fieldOffset]; + MSG_WriteBitAngle(f2, pTest->significant_bits); + break; + case DT_TIMEWINDOW_8: + { + f2 = *(float *)&to[pTest->fieldOffset]; + int32_t twVal = (int)(g_psv.time * 100.0) - (int)(f2 * 100.0); + MSG_WriteSBits(twVal, 8); + break; + } + case DT_TIMEWINDOW_BIG: + { + f2 = *(float *)&to[pTest->fieldOffset]; + int32_t twVal = (int)(g_psv.time * pTest->premultiply) - (int)(f2 * pTest->premultiply); + MSG_WriteSBits((int32_t)twVal, pTest->significant_bits); + break; + } + case DT_STRING: + MSG_WriteBitString((const char *)&to[pTest->fieldOffset]); + break; + default: + Con_Printf(__FUNCTION__ ": unknown send field type\n"); + break; + } + } +} + +/* <2467e> ../engine/delta.c:924 */ +int DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + int sendfields; + DELTA_ClearFlags(pFields); + DELTA_MarkSendFields(from, to, pFields); + sendfields = DELTA_CountSendFields(pFields); + return sendfields; +} + +/* <247f5> ../engine/delta.c:949 */ +int DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void)) +{ + int sendfields; + DELTA_ClearFlags(pFields); + DELTA_MarkSendFields(from, to, pFields); + sendfields = DELTA_CountSendFields(pFields); + _DELTA_WriteDelta(from, to, force, pFields, callback, sendfields); + return sendfields; +} + +/* <24760> ../engine/delta.c:963 */ +int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void), int sendfields) +{ + int i; + int bytecount; + int bits[2]; // this is a limit with 64 fields max in delta + + if (sendfields || force) + { + DELTA_SetSendFlagBits(pFields, bits, &bytecount); + + if (callback) + callback(); + + MSG_WriteBits(bytecount, 3); + for (i = 0; i < bytecount; i++) + { + MSG_WriteBits(((byte*)bits)[i], 8); + } + + DELTA_WriteMarkedFields(from, to, pFields); + } + + return 1; +} + +/* <24aa0> ../engine/delta.c:1010 */ +int DELTA_ParseDelta(unsigned char *from, unsigned char *to, delta_t *pFields) +{ + delta_description_t *pTest; + int i; + int bits[2]; // this is a limit with 64 fields max in delta + int nbytes; + int bitfieldnumber; + int fieldCount = pFields->fieldCount; + int fieldType; + int fieldSign; + + double d2; + float t; + int addt; + char *st2; + char c; + int startbit; + + startbit = MSG_CurrentBit(); + Q_memset(bits, 0, 8); + + nbytes = MSG_ReadBits(3); + for (i = 0; i < nbytes; i++) + { + ((byte*)bits)[i] = MSG_ReadBits(8); + } + + for (i = 0, pTest = pFields->pdd; i < fieldCount; i++, pTest++) + { + fieldType = pTest->fieldType & ~DT_SIGNED; + + bitfieldnumber = 1 << (i & 0x1F); + if (!(bitfieldnumber & bits[i > 31])) + { + // Field was not sent to us, just transfer info from the "from" + switch (fieldType) + { + case DT_BYTE: + to[pTest->fieldOffset] = from[pTest->fieldOffset]; + break; + case DT_SHORT: + *(uint16_t *)&to[pTest->fieldOffset] = *(uint16_t *)&from[pTest->fieldOffset]; + break; + case DT_FLOAT: + case DT_INTEGER: + case DT_ANGLE: + case DT_TIMEWINDOW_8: + case DT_TIMEWINDOW_BIG: + *(uint32_t *)&to[pTest->fieldOffset] = *(uint32_t *)&from[pTest->fieldOffset]; + break; + case DT_STRING: + Q_strcpy((char *)&to[pTest->fieldOffset], (char *)&from[pTest->fieldOffset]); + break; + default: + Con_Printf(__FUNCTION__ ": unparseable field type %i\n", fieldType); + } + continue; + } + + pTest->stats.receivedcount++; + + fieldSign = pTest->fieldType & DT_SIGNED; + switch (fieldType) + { + case DT_BYTE: + if (fieldSign) + { + d2 = (double)MSG_ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) + { + d2 = d2 / pTest->premultiply; + } + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) + { + d2 = d2 * pTest->postmultiply; + } + *(int8_t *)&to[pTest->fieldOffset] = (int8_t)d2; + } + else + { + d2 = (double)MSG_ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) + { + d2 = d2 / pTest->premultiply; + } + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) + { + d2 = d2 * pTest->postmultiply; + } + *(uint8_t *)&to[pTest->fieldOffset] = (uint8_t)d2; + } + break; + case DT_SHORT: + if (fieldSign) + { + d2 = (double)MSG_ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) + { + d2 = d2 / pTest->premultiply; + } + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) + { + d2 = d2 * pTest->postmultiply; + } + *(int16_t *)&to[pTest->fieldOffset] = (int16_t)d2; + } + else + { + d2 = (double)MSG_ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) + { + d2 = d2 / pTest->premultiply; + } + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) + { + d2 = d2 * pTest->postmultiply; + } + *(uint16_t *)&to[pTest->fieldOffset] = (uint16_t)d2; + } + break; + case DT_FLOAT: + if (fieldSign) + { + d2 = (double)MSG_ReadSBits(pTest->significant_bits); + } + else + { + d2 = (double)MSG_ReadBits(pTest->significant_bits); + } + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) + { + d2 = d2 / pTest->premultiply; + } + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) + { + d2 = d2 * pTest->postmultiply; + } + *(float *)&to[pTest->fieldOffset] = (float)d2; + break; + case DT_INTEGER: + if (fieldSign) + { + d2 = (double)MSG_ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) + { + d2 = d2 / pTest->premultiply; + } + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) + { + d2 = d2 * pTest->postmultiply; + } + *(int32_t *)&to[pTest->fieldOffset] = (int32_t)d2; + } + else + { + d2 = (double)MSG_ReadBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) + { + d2 = d2 / pTest->premultiply; + } + if (pTest->postmultiply <= 0.9999 || pTest->postmultiply >= 1.0001) + { + d2 = d2 * pTest->postmultiply; + } + *(uint32_t *)&to[pTest->fieldOffset] = (uint32_t)d2; + } + break; + case DT_ANGLE: + *(float *)&to[pTest->fieldOffset] = MSG_ReadBitAngle(pTest->significant_bits); + break; + case DT_TIMEWINDOW_8: + addt = MSG_ReadSBits(8); + t = (float)((g_pcl.mtime[0] * 100.0 - addt) / 100.0); + *(float *)&to[pTest->fieldOffset] = t; + break; + case DT_TIMEWINDOW_BIG: + addt = MSG_ReadSBits(pTest->significant_bits); + if (pTest->premultiply <= 0.9999 || pTest->premultiply >= 1.0001) + { + t = (float)((g_pcl.mtime[0] * pTest->premultiply - addt) / pTest->premultiply); + } + else + { + t = (float)(g_pcl.mtime[0] - addt); + } + *(float *)&to[pTest->fieldOffset] = t; + break; + case DT_STRING: + st2 = (char *)&to[pTest->fieldOffset]; + do + { + c = MSG_ReadBits(8); + *st2++ = c; + } while (c); + break; + default: + Con_Printf(__FUNCTION__ ": unparseable field type %i\n", fieldType); + break; + } + } + + return MSG_CurrentBit() - startbit; +} + +/* <24c50> ../engine/delta.c:1276 */ +void DELTA_AddEncoder(char *name, void(*conditionalencode)(struct delta_s *, const unsigned char *, const unsigned char *)) +{ + delta_encoder_t *p = (delta_encoder_t *)Mem_ZeroMalloc(sizeof(delta_encoder_t)); + p->name = Mem_Strdup(name); + p->conditionalencode = conditionalencode; + p->next = g_encoders; + g_encoders = p; +} + +/* <24c9d> ../engine/delta.c:1293 */ +void DELTA_ClearEncoders(void) +{ + delta_encoder_t *n, *p = g_encoders; + while (p) + { + n = p->next; + Mem_Free(p->name); + Mem_Free(p); + p = n; + } + g_encoders = 0; +} + +/* <24ce9> ../engine/delta.c:1315 */ +encoder_t DELTA_LookupEncoder(char *name) +{ + delta_encoder_t *p = g_encoders; + while (p) + { + if (!Q_stricmp(name, p->name)) + { + return p->conditionalencode; + } + p = p->next; + } + return NULL; +} + +/* <23d3e> ../engine/delta.c:1338 */ +int DELTA_CountLinks(delta_link_t *plinks) +{ + delta_link_t *p = plinks; + + int c; + for (c = 0; p != NULL; c++) + { + p = p->next; + } + + return c; +} + +/* <23cf6> ../engine/delta.c:1360 */ +void DELTA_ReverseLinks(delta_link_t **plinks) +{ + delta_link_t *n, *p = *plinks; + delta_link_t *newlist = NULL; + + while (p) + { + n = p->next; + p->next = newlist; + newlist = p; + p = n; + } + + *plinks = newlist; +} + +/* <24d8d> ../engine/delta.c:1383 */ +void DELTA_ClearLinks(delta_link_t **plinks) +{ + delta_link_t *n, *p = *plinks; + while (p) + { + n = p->next; + Mem_Free(p); + p = n; + } + *plinks = 0; +} + +/* <24ded> ../engine/delta.c:1405 */ +delta_t *DELTA_BuildFromLinks(delta_link_t **pplinks) +{ + delta_description_t *pdesc, *pcur; + delta_t *pdelta; + delta_link_t *p; + int count; + + pdelta = (delta_t *)Mem_ZeroMalloc(sizeof(delta_t)); + + DELTA_ReverseLinks(pplinks); + + count = DELTA_CountLinks(*pplinks); + pdesc = (delta_description_t *)Mem_ZeroMalloc(sizeof(delta_description_t) * count); + + for (p = *pplinks, pcur = pdesc; p != NULL; p = p->next, pcur++) + { + Q_memcpy(pcur, p->delta, sizeof(delta_description_t)); + Mem_Free(p->delta); + p->delta = 0; + } + + DELTA_ClearLinks(pplinks); + + pdelta->dynamic = 1; + pdelta->fieldCount = count; + pdelta->pdd = pdesc; + + return pdelta; +} + +/* <23dfa> ../engine/delta.c:1445 */ +int DELTA_FindOffset(int count, delta_definition_t *pdef, char *fieldname) +{ + for (int i = 0; i < count; i++) + { + if (!Q_stricmp(fieldname, pdef[i].fieldName)) + { + return pdef[i].fieldOffset; + } + } + + Sys_Error(__FUNCTION__ ": Couldn't find offset for %s!!!\n", fieldname); +} + +/* <24f58> ../engine/delta.c:1469 */ +qboolean DELTA_ParseType(delta_description_t *pdelta, char **pstream) +{ + // Read the stream till we hit the end + while (*pstream = COM_Parse(*pstream), com_token[0] != 0) + { + if (!Q_stricmp(com_token, ",")) + return TRUE; // end of type description + + if (!Q_stricmp(com_token, "|")) + continue; // skip | token + + // Determine field type + if (!Q_stricmp(com_token, "DT_SIGNED")) + pdelta->fieldType |= DT_SIGNED; + else if (!Q_stricmp(com_token, "DT_BYTE")) + pdelta->fieldType |= DT_BYTE; + else if (!Q_stricmp(com_token, "DT_SHORT")) + pdelta->fieldType |= DT_SHORT; + else if (!Q_stricmp(com_token, "DT_FLOAT")) + pdelta->fieldType |= DT_FLOAT; + else if (!Q_stricmp(com_token, "DT_INTEGER")) + pdelta->fieldType |= DT_INTEGER; + else if (!Q_stricmp(com_token, "DT_ANGLE")) + pdelta->fieldType |= DT_ANGLE; + else if (!Q_stricmp(com_token, "DT_TIMEWINDOW_8")) + pdelta->fieldType |= DT_TIMEWINDOW_8; + else if (!Q_stricmp(com_token, "DT_TIMEWINDOW_BIG")) + pdelta->fieldType |= DT_TIMEWINDOW_BIG; + else if (!Q_stricmp(com_token, "DT_STRING")) + pdelta->fieldType |= DT_STRING; + else + Sys_Error(__FUNCTION__ ": Unknown type or type flag %s\n", com_token); + } + + // We are hit the end of the stream + Sys_Error(__FUNCTION__ ": Expecting fieldtype info\n"); // Was Con_Printf here + return FALSE; +} + +/* <24f95> ../engine/delta.c:1545 */ +qboolean DELTA_ParseField(int count, delta_definition_t *pdefinition, delta_link_t *pField, char **pstream) +{ + int readpost; + + readpost = 0; + if (Q_stricmp(com_token, "DEFINE_DELTA")) + { + if (Q_stricmp(com_token, "DEFINE_DELTA_POST")) + { + Sys_Error(__FUNCTION__ ": Expecting DEFINE_*, got %s\n", com_token); + } + readpost = 1; + } + + *pstream = COM_Parse(*pstream); + if (Q_stricmp(com_token, "(")) + { + Sys_Error(__FUNCTION__ ": Expecting (, got %s\n", com_token); + } + + *pstream = COM_Parse(*pstream); + if (com_token[0] == 0) + { + Sys_Error(__FUNCTION__ ": Expecting fieldname\n"); + } + + Q_strncpy(pField->delta->fieldName, com_token, 31); + pField->delta->fieldName[31] = 0; + pField->delta->fieldOffset = DELTA_FindOffset(count, pdefinition, com_token); + + *pstream = COM_Parse(*pstream); + if (!DELTA_ParseType(pField->delta, pstream)) + { + return FALSE; + } + + *pstream = COM_Parse(*pstream); + pField->delta->fieldSize = 1; + pField->delta->significant_bits = Q_atoi(com_token); + *pstream = COM_Parse(*pstream); + *pstream = COM_Parse(*pstream); + pField->delta->premultiply = (float)Q_atof(com_token); + + if (readpost) + { + *pstream = COM_Parse(*pstream); + *pstream = COM_Parse(*pstream); + pField->delta->postmultiply = (float)Q_atof(com_token); + } + else + { + pField->delta->postmultiply = 1.0; + } + + *pstream = COM_Parse(*pstream); + if (Q_stricmp(com_token, ")")) + { + Sys_Error(__FUNCTION__ ": Expecting ), got %s\n", com_token); // Was Con_Printf here + return FALSE; + } + + *pstream = COM_Parse(*pstream); + if (Q_stricmp(com_token, ",")) + { + COM_UngetToken(); + } + + return TRUE; +} + +/* <25051> ../engine/delta.c:1657 */ +void DELTA_FreeDescription(delta_t **ppdesc) +{ + delta_t *p; + + if (ppdesc) + { + p = *ppdesc; + if (p) + { + if (p->dynamic) + Mem_Free(p->pdd); + Mem_Free(p); + *ppdesc = 0; + } + } +} + +/* <23d92> ../engine/delta.c:1679 */ +void DELTA_AddDefinition(char *name, delta_definition_t *pdef, int numelements) +{ + delta_definition_list_t *p = g_defs; + while (p) + { + if (!Q_stricmp(name, p->ptypename)) + { + break; + } + p = p->next; + } + + if (p == NULL) + { + p = (delta_definition_list_t *)Mem_ZeroMalloc(sizeof(delta_definition_list_t)); + p->ptypename = Mem_Strdup(name); + p->next = g_defs; + g_defs = p; + } + + p->pdefinition = pdef; + p->numelements = numelements; +} + +/* <25100> ../engine/delta.c:1713 */ +void DELTA_ClearDefinitions(void) +{ + delta_definition_list_t *n, *p = g_defs; + while (p) + { + n = p->next; + Mem_Free(p->ptypename); + Mem_Free(p); + p = n; + } + g_defs = 0; +} + +/* <23e3c> ../engine/delta.c:1735 */ +delta_definition_t *DELTA_FindDefinition(char *name, int *count) +{ + delta_definition_list_t *p = g_defs; + + *count = 0; + + while (p) + { + if (!Q_stricmp(name, p->ptypename)) + { + *count = p->numelements; + return p->pdefinition; + } + p = p->next; + } + + return NULL; +} + +/* <2517b> ../engine/delta.c:1765 */ +void DELTA_SkipDescription(char **pstream) +{ + *pstream = COM_Parse(*pstream); + do + { + *pstream = COM_Parse(*pstream); + if (com_token[0] == 0) + { + Sys_Error(__FUNCTION__ ": Error during description skip"); + } + } while (Q_stricmp(com_token, "}")); +} + +/* <251b5> ../engine/delta.c:1792 */ +qboolean DELTA_ParseOneField(char **ppstream, delta_link_t **pplist, int count, delta_definition_t *pdefinition) +{ + delta_link_t *newlink; + delta_link_t link; + + while (true) + { + if (!Q_stricmp(com_token, "}")) + { + COM_UngetToken(); + break; + } + + *ppstream = COM_Parse(*ppstream); + if (com_token[0] == 0) + { + break; + } + + Q_memset(&link, 0, 8u); + link.delta = (delta_description_t *)Mem_ZeroMalloc(sizeof(delta_description_t)); + if (!DELTA_ParseField(count, pdefinition, &link, ppstream)) + { + return FALSE; + } + + newlink = (delta_link_t *)Mem_ZeroMalloc(sizeof(delta_link_t)); + newlink->delta = link.delta; + newlink->next = *pplist; + *pplist = newlink; + } + return TRUE; +} + +/* <2523f> ../engine/delta.c:1842 */ +qboolean DELTA_ParseDescription(char *name, delta_t **ppdesc, char *pstream) +{ + delta_link_t *links; + delta_definition_t *pdefinition; + char encoder[32]; + char source[32]; + int count; + + + links = NULL; + count = 0; + encoder[0] = 0; + + if (!ppdesc) + { + Sys_Error(__FUNCTION__ " with no delta_description_t\n"); + } + *ppdesc = 0; + + if (!pstream) + { + Sys_Error(__FUNCTION__ " with no data stream\n"); + } + + while (true) + { + // Parse delta name + pstream = COM_Parse(pstream); + if (com_token[0] == 0) + { + break; + } + if (Q_stricmp(com_token, name)) + { + DELTA_SkipDescription(&pstream); + } + else + { + pdefinition = DELTA_FindDefinition(com_token, &count); + if (!pdefinition) + { + Sys_Error(__FUNCTION__ ": Unknown data type: %s\n", com_token); + } + + // Parse source of conditional encoder + pstream = COM_Parse(pstream); + if (com_token[0] == 0) + { + Sys_Error(__FUNCTION__ ": Unknown encoder : %s\nValid values:\nnone\ngamedll funcname\nclientdll funcname\n", com_token); + } + if (Q_stricmp(com_token, "none")) + { + Q_strncpy(source, com_token, sizeof(source)-1); + source[sizeof(source)-1] = 0; + + // Parse custom encoder function name + pstream = COM_Parse(pstream); + if (com_token[0] == 0) + { + Sys_Error(__FUNCTION__ ": Expecting encoder\n"); + } + + Q_strncpy(encoder, com_token, sizeof(encoder)-1); + encoder[sizeof(encoder)-1] = 0; + } + + // Parse fields + while (true) + { + pstream = COM_Parse(pstream); + if (com_token[0] == 0) + { + break; + } + if (!Q_stricmp(com_token, "}")) + { + break; + } + if (Q_stricmp(com_token, "{")) + { + Sys_Error(__FUNCTION__ ": Expecting {, got %s\n", com_token); // Was Con_Printf here + return FALSE; + } + if (!DELTA_ParseOneField(&pstream, &links, count, pdefinition)) + { + return FALSE; + } + } + } + } + + *ppdesc = DELTA_BuildFromLinks(&links); + + if (encoder[0] != 0) + { + Q_strncpy((*ppdesc)->conditionalencodename, encoder, sizeof((*ppdesc)->conditionalencodename) - 1); + (*ppdesc)->conditionalencodename[sizeof((*ppdesc)->conditionalencodename) - 1] = 0; + (*ppdesc)->conditionalencode = 0; + } + + return TRUE; +} + +/* <25338> ../engine/delta.c:1959 */ +qboolean DELTA_Load(char *name, delta_t **ppdesc, char *pszFile) +{ + char *pbuf; + qboolean bret; + + pbuf = (char *)COM_LoadFile(pszFile, 5, 0); + if (!pbuf) + { + Sys_Error(__FUNCTION__ ": Couldn't load file %s\n", pszFile); + } + + bret = DELTA_ParseDescription(name, ppdesc, pbuf); + + Mem_Free(pbuf); + + return bret; +} + +/* <253a4> ../engine/delta.c:1990 */ +void DELTA_RegisterDescription(char *name) +{ + delta_registry_t *p = (delta_registry_t *)Mem_ZeroMalloc(sizeof(delta_registry_t)); + p->next = g_deltaregistry; + g_deltaregistry = p; + p->name = Mem_Strdup(name); + p->pdesc = 0; +} + +/* <253dc> ../engine/delta.c:2008 */ +void DELTA_ClearRegistrations(void) +{ + delta_registry_t *n, *p = g_deltaregistry; + while (p) + { + n = p->next; + Mem_Free(p->name); + if (p->pdesc) + DELTA_FreeDescription(&p->pdesc); + Mem_Free(p); + p = n; + } + g_deltaregistry = 0; +} + +/* <25442> ../engine/delta.c:2036 */ +delta_t **DELTA_LookupRegistration(const char *name) +{ + delta_registry_t *p = g_deltaregistry; + while (p) + { + if (!Q_stricmp(p->name, name)) + { + return &p->pdesc; + } + p = p->next; + } + return NULL; +} + +/* <23dd6> ../engine/delta.c:2060 */ +void DELTA_ClearStats(delta_t *p) +{ + int i; + + if (p) + { + for (i = p->fieldCount - 1; i >= 0; i--) + { + p->pdd[i].stats.sendcount = 0; + p->pdd[i].stats.receivedcount = 0; + } + } +} + +/* <23e72> ../engine/delta.c:2081 */ +void DELTA_ClearStats_f(void) +{ + delta_registry_t *p; + + Con_Printf("Clearing delta stats\n"); + for (p = g_deltaregistry; p; p = p->next) + { + DELTA_ClearStats(p->pdesc); + } +} + +/* <23ece> ../engine/delta.c:2100 */ +void DELTA_PrintStats(const char *name, delta_t *p) +{ + if (p) + { + Con_Printf("Stats for '%s'\n", name); + if (p->fieldCount > 0) + { + delta_description_t *dt = p->pdd; + for (int i = 0; i < p->fieldCount; i++, dt++) + { + Con_Printf(" %02i % 10s: s % 5i r % 5i\n", i + 1, dt->fieldName, dt->stats.sendcount, dt->stats.receivedcount); + } + } + Con_Printf("\n"); + } +} + +/* <23efe> ../engine/delta.c:2124 */ +void DELTA_DumpStats_f(void) +{ + Con_Printf("Delta Stats\n"); + for (delta_registry_t *dr = g_deltaregistry; dr; dr = dr->next) + DELTA_PrintStats(dr->name, dr->pdesc); +} + +/* <254d4> ../engine/delta.c:2143 */ +void DELTA_Init(void) +{ + Cmd_AddCommand("delta_stats", DELTA_DumpStats_f); + Cmd_AddCommand("delta_clear", DELTA_ClearStats_f); + + DELTA_AddDefinition("clientdata_t", g_ClientDataDefinition, ARRAYSIZE(g_ClientDataDefinition)); + DELTA_AddDefinition("weapon_data_t", g_WeaponDataDefinition, ARRAYSIZE(g_WeaponDataDefinition)); + DELTA_AddDefinition("usercmd_t", g_UsercmdDataDefinition, ARRAYSIZE(g_UsercmdDataDefinition)); + DELTA_AddDefinition("entity_state_t", g_EntityDataDefinition, ARRAYSIZE(g_EntityDataDefinition)); + DELTA_AddDefinition("entity_state_player_t", g_EntityDataDefinition, ARRAYSIZE(g_EntityDataDefinition)); + DELTA_AddDefinition("custom_entity_state_t", g_EntityDataDefinition, ARRAYSIZE(g_EntityDataDefinition)); + DELTA_AddDefinition("event_t", g_EventDataDefinition, ARRAYSIZE(g_EventDataDefinition)); +} + +/* <25847> ../engine/delta.c:2164 */ +void DELTA_Shutdown(void) +{ + DELTA_ClearEncoders(); + DELTA_ClearDefinitions(); + DELTA_ClearRegistrations(); +} diff --git a/rehlds/engine/delta.h b/rehlds/engine/delta.h new file mode 100644 index 0000000..26282be --- /dev/null +++ b/rehlds/engine/delta.h @@ -0,0 +1,149 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef DELTA_H +#define DELTA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + + +typedef struct delta_s delta_t; + +/* ../engine/delta.h:76 */ +typedef void(*encoder_t)(delta_t *, const unsigned char *, const unsigned char *); + +/* <9f6a5> ../engine/delta.h:34 */ +typedef struct delta_stats_s +{ + int sendcount; + int receivedcount; +} delta_stats_t; + +/* ../engine/delta.h:45 */ +typedef struct delta_description_s +{ + int fieldType; + char fieldName[32]; + int fieldOffset; + short int fieldSize; + int significant_bits; + float premultiply; + float postmultiply; + short int flags; + delta_stats_t stats; +} delta_description_t; + +/* ../engine/delta.h:78 */ +typedef struct delta_s +{ + int dynamic; + int fieldCount; + char conditionalencodename[32]; + encoder_t conditionalencode; + delta_description_t *pdd; +} delta_t; + +/* <23b2a> ../engine/delta.h:104 */ +typedef struct delta_encoder_s delta_encoder_t; + +/* <23b35> ../engine/delta.h:106 */ +struct delta_encoder_s +{ + delta_encoder_t *next; + char *name; + encoder_t conditionalencode; +}; + +typedef struct delta_link_s delta_link_t; +typedef struct delta_definition_s delta_definition_t; +typedef struct delta_definition_list_s delta_definition_list_t; +typedef struct delta_registry_s delta_registry_t; +typedef struct delta_info_s delta_info_t; + + +#ifdef HOOK_ENGINE +#define g_defs (*pg_defs) +#define g_encoders (*pg_encoders) +#define g_deltaregistry (*pg_deltaregistry) +#endif // HOOK_ENGINE + + +extern delta_definition_list_t *g_defs; +extern delta_encoder_t *g_encoders; +extern delta_registry_t *g_deltaregistry; +extern delta_t g_MetaDelta[]; + + +delta_description_t *DELTA_FindField(delta_t *pFields, const char *pszField); +int DELTA_FindFieldIndex(struct delta_s *pFields, const char *fieldname); +void DELTA_SetField(struct delta_s *pFields, const char *fieldname); +void DELTA_UnsetField(struct delta_s *pFields, const char *fieldname); +void DELTA_SetFieldByIndex(struct delta_s *pFields, int fieldNumber); +void DELTA_UnsetFieldByIndex(struct delta_s *pFields, int fieldNumber); +void DELTA_ClearFlags(delta_t *pFields); +int DELTA_TestDelta(unsigned char *from, unsigned char *to, delta_t *pFields); +int DELTA_CountSendFields(delta_t *pFields); +void DELTA_MarkSendFields(unsigned char *from, unsigned char *to, delta_t *pFields); +void DELTA_SetSendFlagBits(delta_t *pFields, int *bits, int *bytecount); +void DELTA_WriteMarkedFields(unsigned char *from, unsigned char *to, delta_t *pFields); +int DELTA_CheckDelta(unsigned char *from, unsigned char *to, delta_t *pFields); +int DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void)); +int _DELTA_WriteDelta(unsigned char *from, unsigned char *to, qboolean force, delta_t *pFields, void(*callback)(void), int sendfields); +int DELTA_ParseDelta(unsigned char *from, unsigned char *to, delta_t *pFields); +void DELTA_AddEncoder(char *name, void(*conditionalencode)(struct delta_s *, const unsigned char *, const unsigned char *)); +void DELTA_ClearEncoders(void); +encoder_t DELTA_LookupEncoder(char *name); +int DELTA_CountLinks(delta_link_t *plinks); +void DELTA_ReverseLinks(delta_link_t **plinks); +void DELTA_ClearLinks(delta_link_t **plinks); +delta_t *DELTA_BuildFromLinks(delta_link_t **pplinks); +int DELTA_FindOffset(int count, delta_definition_t *pdef, char *fieldname); +qboolean DELTA_ParseType(delta_description_t *pdelta, char **pstream); +qboolean DELTA_ParseField(int count, delta_definition_t *pdefinition, delta_link_t *pField, char **pstream); +void DELTA_FreeDescription(delta_t **ppdesc); +void DELTA_AddDefinition(char *name, delta_definition_t *pdef, int numelements); +void DELTA_ClearDefinitions(void); +delta_definition_t *DELTA_FindDefinition(char *name, int *count); +void DELTA_SkipDescription(char **pstream); +qboolean DELTA_ParseOneField(char **ppstream, delta_link_t **pplist, int count, delta_definition_t *pdefinition); +qboolean DELTA_ParseDescription(char *name, delta_t **ppdesc, char *pstream); +qboolean DELTA_Load(char *name, delta_t **ppdesc, char *pszFile); +void DELTA_RegisterDescription(char *name); +void DELTA_ClearRegistrations(void); +delta_t **DELTA_LookupRegistration(const char *name); +void DELTA_ClearStats(delta_t *p); +void DELTA_ClearStats_f(void); +void DELTA_PrintStats(const char *name, delta_t *p); +void DELTA_DumpStats_f(void); +void DELTA_Init(void); +void DELTA_Shutdown(void); + +#endif // DELTA_H diff --git a/rehlds/engine/delta_packet.h b/rehlds/engine/delta_packet.h new file mode 100644 index 0000000..a37b755 --- /dev/null +++ b/rehlds/engine/delta_packet.h @@ -0,0 +1,46 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef DELTA_PACKET_H +#define DELTA_PACKET_H +#ifdef _WIN32 +#pragma once +#endif + +#include "entity_state.h" + + +/* <138fb> ../engine/delta_packet.h:39 */ +typedef struct packet_entities_s +{ + int num_entities; + unsigned char flags[32]; + entity_state_t *entities; +} packet_entities_t; + +#endif // DELTA_PACKET_H diff --git a/rehlds/engine/ed_strpool.cpp b/rehlds/engine/ed_strpool.cpp new file mode 100644 index 0000000..4994ad3 --- /dev/null +++ b/rehlds/engine/ed_strpool.cpp @@ -0,0 +1,89 @@ +#include "precompiled.h" + +class CStringPoolMap : public CStaticMap { +protected: + virtual uint32_t hash(const char* const &val) { + unsigned int len = strlen(val); + return crc32((const uint8_t*)val, len); + } + + virtual bool equals(const char* const &val1, const char* const &val2) { + return !strcmp(val1, val2); + } + +public: + CStringPoolMap() { + } +}; + +CStringPoolMap g_EdStringPool; +sizebuf_t g_EdStringPool_Hunk; + +void Ed_StrPool_Init() { + memset(&g_EdStringPool_Hunk, 0, sizeof(g_EdStringPool_Hunk)); + + g_EdStringPool_Hunk.maxsize = 128 * 1024; + g_EdStringPool_Hunk.data = (byte*) Hunk_AllocName(g_EdStringPool_Hunk.maxsize, "Ed_StrPool"); + g_EdStringPool_Hunk.cursize = 0; + g_EdStringPool_Hunk.buffername = "Ed_StrPool"; + g_EdStringPool_Hunk.flags = SIZEBUF_ALLOW_OVERFLOW; +} + +void Ed_StrPool_Reset() { + g_EdStringPool_Hunk.cursize = 0; + g_EdStringPool_Hunk.flags = SIZEBUF_ALLOW_OVERFLOW; + g_EdStringPool.clear(); +} + +char* Ed_StrPool_Alloc(const char* origStr) { + char str[2048]; + unsigned int len = strlen(origStr) + 1; + + if (len >= ARRAYSIZE(str)) { + Sys_Error(__FUNCTION__ ": Too long string allocated: %s", origStr); + } + + strcpy(str, origStr); + char* new_p = str; + for (unsigned int i = 0; i < len; i++, new_p++) + { + if (str[i] == '\\' && str[i + 1] == 'n') + { + // Replace "\\n" with "\n" + *new_p = '\n'; + i++; + } + else + { + *new_p = str[i]; + } + } + + *new_p = 0; + len = strlen(str) + 1; + + auto node = g_EdStringPool.get(str); + if (node) { + return node->val; + } + + char* val = NULL; + + //try to alloc string from shared hunk + if (!(g_EdStringPool_Hunk.flags & SIZEBUF_OVERFLOWED)) { + val = (char*)g_EdStringPool_Hunk.data + g_EdStringPool_Hunk.cursize; + MSG_WriteString(&g_EdStringPool_Hunk, str); + if (g_EdStringPool_Hunk.flags & SIZEBUF_OVERFLOWED) { + val = NULL; + } + } + + if (!val) { + val = (char*) Hunk_Alloc(len); + memcpy(val, str, len); + } + + g_EdStringPool.put(val, val); + + return val; +} diff --git a/rehlds/engine/ed_strpool.h b/rehlds/engine/ed_strpool.h new file mode 100644 index 0000000..969f834 --- /dev/null +++ b/rehlds/engine/ed_strpool.h @@ -0,0 +1,8 @@ +#pragma once + +#include "osconfig.h" +#include "static_map.h" + +extern char* Ed_StrPool_Alloc(const char* str); +extern void Ed_StrPool_Reset(); +extern void Ed_StrPool_Init(); diff --git a/rehlds/engine/event.h b/rehlds/engine/event.h new file mode 100644 index 0000000..0711061 --- /dev/null +++ b/rehlds/engine/event.h @@ -0,0 +1,45 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef EVENT_H +#define EVENT_H +#ifdef _WIN32 +#pragma once +#endif + + +/* <75ae> ../engine/event.h:6 */ +typedef struct event_s +{ + unsigned short index; + const char *filename; + int filesize; + const char *pszScript; +} event_t; + +#endif // EVENT_H diff --git a/rehlds/engine/filesystem.cpp b/rehlds/engine/filesystem.cpp new file mode 100644 index 0000000..660f654 --- /dev/null +++ b/rehlds/engine/filesystem.cpp @@ -0,0 +1,516 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifdef _WIN32 + #define FILESYSTEM_DLL_NAME "filesystem_stdio.dll" +#else + #define FILESYSTEM_DLL_NAME "filesystem_stdio.so" +#endif + +CUtlVector g_fallbackLocalizationFiles; +char s_pBaseDir[512]; +bool bLowViolenceBuild; + +CSysModule *g_pFileSystemModule; +CreateInterfaceFn g_FileSystemFactory; + +/* <28515> ../engine/filesystem.cpp:66 */ +const char *GetBaseDirectory(void) +{ + return s_pBaseDir; +} + +/* <2891f> ../engine/filesystem.cpp:71 */ +NOXREF void *GetFileSystemFactory(void) +{ + NOXREFCHECK; + + return (void *)g_FileSystemFactory; +} + +/* <28522> ../engine/filesystem.cpp:81 */ +bool FileSystem_LoadDLL(CreateInterfaceFn filesystemFactory) +{ + if (!filesystemFactory) + { + g_pFileSystemModule = Sys_LoadModule(FILESYSTEM_DLL_NAME); + + if (g_pFileSystemModule) + { + filesystemFactory = Sys_GetFactory(g_pFileSystemModule); + } + } + + if (filesystemFactory) + { + g_FileSystemFactory = filesystemFactory; + + g_pFileSystem = (IFileSystem *)filesystemFactory(FILESYSTEM_INTERFACE_VERSION, 0); + return g_pFileSystem != NULL; + } + + return false; +} + +/* <2854b> ../engine/filesystem.cpp:119 */ +void FileSystem_UnloadDLL(void) +{ + if (g_pFileSystemModule) + { + Sys_UnloadModule((CSysModule *)g_pFileSystemModule); + g_pFileSystemModule = NULL; + g_FileSystemFactory = NULL; + g_pFileSystem = NULL; + } +} + +/* <284fb> ../engine/filesystem.cpp:129 */ +bool BEnabledHDAddon(void) +{ + if (COM_CheckParm("-nohdmodels")) + { + return false; + } + + return (registry->ReadInt("hdmodels", 1) > 0); +} + +/* <28508> ../engine/filesystem.cpp:138 */ +bool BEnableAddonsFolder(void) +{ + if (COM_CheckParm("-addons")) + { + return false; + } + + return (registry->ReadInt("addons_folder", 0) > 0); +} + +/* <28984> ../engine/filesystem.cpp:148 */ +void Host_SetHDModels_f(void) +{ + if (g_pcls.state && Cmd_Argc() == 2) + { + bool bEnabled = (registry->ReadInt("hdmodels", 1) > 0); + + registry->WriteInt("hdmodels", !Q_stricmp(Cmd_Argv(1), "1") ? 1 : 0); + + if (bEnabled != BEnabledHDAddon()) + { + COM_SetupDirectories(); + } + } +} + +/* <289d1> ../engine/filesystem.cpp:176 */ +void Host_SetAddonsFolder_f(void) +{ + if (g_pcls.state && Cmd_Argc() == 2) + { + bool bEnabled = (registry->ReadInt("addons_folder", 0) > 0); + + registry->WriteInt("addons_folder", !Q_stricmp(Cmd_Argv(1), "1") ? 1 : 0); + + if (bEnabled != BEnableAddonsFolder()) + { + COM_SetupDirectories(); + } + } +} + +/* <28a1e> ../engine/filesystem.cpp:204 */ +void Host_SetVideoLevel_f(void) +{ + if (g_pcls.state && Cmd_Argc() == 2) + { + registry->WriteInt("vid_level", !Q_stricmp(Cmd_Argv(1), "1") ? 1 : 0); + } +} + +/* <28a32> ../engine/filesystem.cpp:224 */ +int Host_GetVideoLevel(void) +{ + return registry->ReadInt("vid_level", 0); +} + +/* <28a68> ../engine/filesystem.cpp:235 */ +void CheckLiblistForFallbackDir(const char *pGameDir, bool bLanguage, const char *pLanguage, bool bLowViolenceBuild_) +{ + char szTemp[512]; + FileHandle_t hFile; + + Q_snprintf(szTemp, sizeof(szTemp) - 1, "%s/liblist.gam", pGameDir); + COM_FixSlashes(szTemp); + g_pFileSystem->GetLocalCopy(szTemp); + + if (Q_stricmp(com_gamedir, pGameDir)) + { + Q_snprintf(szTemp, 511, "../%s/liblist.gam", pGameDir); + COM_FixSlashes(szTemp); + hFile = FS_Open(szTemp, "rt"); + } + else + hFile = FS_Open("liblist.gam", "rt"); + + if (!hFile) + return; + + if (FS_EndOfFile(hFile)) + { + FS_Close(hFile); + return; + } + + char szFallback[128]; + char szLine[512]; + + char *end; + char *start; + int bytesToCopy; + + while (1) + { + szLine[0] = 0; + FS_ReadLine(szLine, sizeof(szLine) - 1, hFile); + szLine[511] = 0; + if (!Q_strnicmp(szLine, "fallback_dir", Q_strlen("fallback_dir"))) + { + start = strchr(szLine, '"'); + if (!start) + { + FS_Close(hFile); + return; + } + + end = strchr(start + 1, '"'); + if (!end) + { + FS_Close(hFile); + return; + } + + bytesToCopy = (int)(end - start) - 1; + if (bytesToCopy > sizeof(szFallback) - 2) + { + FS_Close(hFile); + return; + } + + if (bytesToCopy > 0) + break; + } + if (FS_EndOfFile(hFile)) + { + FS_Close(hFile); + return; + } + } + + Q_strncpy(szFallback, start + 1, bytesToCopy); + szFallback[bytesToCopy] = 0; + + if (!Q_stricmp(pGameDir, szFallback) ) + { + FS_Close(hFile); + return; + } + if (bLowViolenceBuild) + { + Q_snprintf(szTemp, 511, "%s/%s_lv", GetBaseDirectory(), szFallback); + szTemp[511] = 0; + COM_FixSlashes(szTemp); + g_pFileSystem->AddSearchPathNoWrite(szTemp, "GAME_FALLBACK"); + } + if (BEnableAddonsFolder()) + { + Q_snprintf(szTemp, 511, "%s/%s_addon", GetBaseDirectory(), szFallback); + szTemp[511] = 0; + COM_FixSlashes(szTemp); + g_pFileSystem->AddSearchPathNoWrite(szTemp, "GAME_FALLBACK"); + } + + if (bLanguage && pLanguage) + { + char baseDir[4096]; + char *tempPtr; + + Q_snprintf(szTemp, 511, "%s/%s_%s", GetBaseDirectory(), szFallback, pLanguage); + szTemp[511] = 0; + COM_FixSlashes(szTemp); + g_pFileSystem->AddSearchPath(szTemp, "GAME_FALLBACK"); + + if (!COM_CheckParm("-steam")) + { + Q_strncpy(baseDir, GetBaseDirectory(), sizeof(baseDir) - 1); + baseDir[sizeof(baseDir) - 1] = 0; + + tempPtr = Q_strstr(baseDir, "\\game"); + if (tempPtr) + { + *tempPtr = 0; + + Q_snprintf(szTemp, 511, "%s\\localization\\%s_%s", baseDir, szFallback, pLanguage); + szTemp[511] = 0; + + COM_FixSlashes(szTemp); + g_pFileSystem->AddSearchPath(szTemp, "GAME_FALLBACK"); + } + } + } + + if (BEnabledHDAddon()) + { + Q_snprintf(szTemp, 511, "%s/%s_hd", GetBaseDirectory(), szFallback); + szTemp[511] = 0; + COM_FixSlashes(szTemp); + g_pFileSystem->AddSearchPathNoWrite(szTemp, "GAME_FALLBACK"); + } + + Q_snprintf(szTemp, 511, "%s/%s", GetBaseDirectory(), szFallback); + szTemp[511] = 0; + COM_FixSlashes(szTemp); + g_pFileSystem->AddSearchPath(szTemp, "GAME_FALLBACK"); + + if (Q_stricmp(szFallback, "valve")) + { + const int BufLen = 128; + char *szFileName = new char[BufLen]; + + Q_snprintf(szFileName, BufLen - 1, "Resource/%s_%%language%%.txt", szFallback); + szFileName[BufLen - 1] = 0; + + g_fallbackLocalizationFiles.AddToTail(szFileName); + CheckLiblistForFallbackDir(szFallback, bLanguage, pLanguage, bLowViolenceBuild); + } + FS_Close(hFile); +} + +/* <28deb> ../engine/filesystem.cpp:393 */ +int FileSystem_SetGameDirectory(const char *pDefaultDir, const char *pGameDir) +{ + char temp[512]; + char language[256]; + const char *pchLang; + + g_pFileSystem->RemoveAllSearchPaths(); + language[0] = 0; + + if (!bLowViolenceBuild) + { + if (CRehldsPlatformHolder::get()->SteamApps() && GetGameAppID() == 70) + { + bLowViolenceBuild = CRehldsPlatformHolder::get()->SteamApps()->BIsLowViolence(); + } + } + + pchLang = CRehldsPlatformHolder::get()->SteamApps() ? CRehldsPlatformHolder::get()->SteamApps()->GetCurrentGameLanguage() : NULL; + strncpy(language, pchLang ? pchLang : "english", sizeof(language)); + if (!g_bIsDedicatedServer && !IsGameSubscribed(pGameDir)) + return 0; + + CRehldsPlatformHolder::get()->SteamAPI_SetBreakpadAppID(GetGameAppID()); + + bool bEnableHDPack = BEnabledHDAddon(); + bool bLanguage = (strlen(language) != 0 && Q_stricmp(language, "english")) ? true : false; + + if (!pGameDir) + pGameDir = pDefaultDir; + + if (pGameDir) + { + if (bLowViolenceBuild) + { + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_lv", GetBaseDirectory(), pGameDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "GAME"); + } + if (BEnableAddonsFolder()) + { + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_addon", GetBaseDirectory(), pGameDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "GAME"); + } + if (bLanguage) + { + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_%s", GetBaseDirectory(), pGameDir, language); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "GAME"); + + if (!COM_CheckParm("-steam")) + { + char baseDir[MAX_PATH]; + Q_strncpy(baseDir, GetBaseDirectory(), sizeof(baseDir) - 1); + baseDir[sizeof(baseDir) - 1] = 0; + char* tempPtr = Q_strstr(baseDir, "\\game"); + if (tempPtr) + { + *tempPtr = 0; + Q_snprintf(temp, 511, "%s\\localization\\%s_%s", baseDir, pGameDir, language); + temp[511] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "GAME"); + } + } + } + if (bEnableHDPack) + { + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_hd", GetBaseDirectory(), pGameDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "GAME"); + } + + Q_snprintf(temp, 511, "%s/%s", GetBaseDirectory(), pGameDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPath(temp, "GAME"); + g_pFileSystem->AddSearchPath(temp, "GAMECONFIG"); + + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_downloads", GetBaseDirectory(), pGameDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPath(temp, "GAMEDOWNLOAD"); + + CheckLiblistForFallbackDir(pGameDir, bLanguage, language, bLowViolenceBuild); + } + if (bLanguage) + { + if (bLowViolenceBuild) + { + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_lv", GetBaseDirectory(), pDefaultDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "DEFAULTGAME"); + } + + if (BEnableAddonsFolder()) + { + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_addon", GetBaseDirectory(), pDefaultDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "DEFAULTGAME"); + } + + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_%s", GetBaseDirectory(), pDefaultDir, language); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "DEFAULTGAME"); + if (!COM_CheckParm("-steam")) + { + char baseDir[MAX_PATH]; + + Q_strncpy(baseDir, GetBaseDirectory(), sizeof(baseDir) - 1); + baseDir[sizeof(baseDir) - 1] = 0; + char* tempPtr = Q_strstr(baseDir, "\\game"); + if (tempPtr) + { + *tempPtr = 0; + Q_snprintf(temp, sizeof(temp) - 1, "%s\\localization\\%s_%s", baseDir, pDefaultDir, language); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "DEFAULTGAME"); + } + } + } + if (bEnableHDPack) + { + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s_hd", GetBaseDirectory(), pDefaultDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "DEFAULTGAME"); + } + + Q_snprintf(temp, sizeof(temp) - 1, "%s", GetBaseDirectory()); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPath(temp, "BASE"); + + Q_snprintf(temp, sizeof(temp) - 1, "%s/%s", GetBaseDirectory(), pDefaultDir); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPathNoWrite(temp, "DEFAULTGAME"); + + Q_snprintf(temp, sizeof(temp) - 1, "%s/platform", GetBaseDirectory()); + temp[sizeof(temp) - 1] = 0; + COM_FixSlashes(temp); + g_pFileSystem->AddSearchPath(temp, "PLATFORM"); + + return 1; + +} + +/* <28f6a> ../engine/filesystem.cpp:596 */ +int FileSystem_AddFallbackGameDir(const char *pGameDir) +{ + char language[128]; + + const char * pchLang = CRehldsPlatformHolder::get()->SteamApps() ? CRehldsPlatformHolder::get()->SteamApps()->GetCurrentGameLanguage() : NULL; + strncpy(language, pchLang ? pchLang : "english", sizeof(language)); + + if (strlen(language) != 0 && Q_stricmp(language, "english")) + { + char temp[MAX_PATH]; + sprintf(temp, "%s/%s_%s", GetBaseDirectory(), pGameDir, language); + g_pFileSystem->AddSearchPath(temp, "GAME"); + } + g_pFileSystem->AddSearchPath(pGameDir, "GAME"); + return 1; +} + +/* <28fd7> ../engine/filesystem.cpp:626 */ +int FileSystem_Init(char *basedir, void *voidfilesystemFactory) +{ + Q_strcpy(s_pBaseDir, basedir); + host_parms.basedir = s_pBaseDir; + + if (FileSystem_LoadDLL((CreateInterfaceFn)voidfilesystemFactory)) + { + return COM_SetupDirectories() != 0; + } + + return 0; +} + +/* <29057> ../engine/filesystem.cpp:645 */ +void FileSystem_Shutdown(void) +{ + FS_RemoveAllSearchPaths(); + FileSystem_UnloadDLL(); +} + +/* <29085> (null):39776 */ +NOBODY void _GLOBAL__sub_I_g_FileSystemFactory(void); +//{ +// __static_initialization_and_destruction_0(int __initialize_p, +// int __priority); /* size=6582895, low_pc=0 */ // 649 +//} diff --git a/rehlds/engine/filesystem_.h b/rehlds/engine/filesystem_.h new file mode 100644 index 0000000..105a20b --- /dev/null +++ b/rehlds/engine/filesystem_.h @@ -0,0 +1,72 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef FILESYSTEM__H +#define FILESYSTEM__H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "iregistry.h" +#include "utlvector.h" + +#ifdef HOOK_ENGINE +#define g_fallbackLocalizationFiles (*pg_fallbackLocalizationFiles) +#define s_pBaseDir (*ps_pBaseDir) +#define bLowViolenceBuild (*pbLowViolenceBuild) + +#define g_pFileSystemModule (*pg_pFileSystemModule) +#define g_FileSystemFactory (*pg_FileSystemFactory) +#endif // HOOK_ENGINE + +extern CUtlVector g_fallbackLocalizationFiles; +extern char s_pBaseDir[512]; +extern bool bLowViolenceBuild; + +extern CSysModule *g_pFileSystemModule; +extern CreateInterfaceFn g_FileSystemFactory; + +const char *GetBaseDirectory(void); +NOXREF void *GetFileSystemFactory(void); +bool FileSystem_LoadDLL(CreateInterfaceFn filesystemFactory); +void FileSystem_UnloadDLL(void); +bool BEnabledHDAddon(void); +bool BEnableAddonsFolder(void); +void Host_SetHDModels_f(void); +void Host_SetAddonsFolder_f(void); +void Host_SetVideoLevel_f(void); +int Host_GetVideoLevel(void); +void CheckLiblistForFallbackDir(const char *pGameDir, bool bLanguage, const char *pLanguage, bool bLowViolenceBuild_); +int FileSystem_SetGameDirectory(const char *pDefaultDir, const char *pGameDir); +int FileSystem_AddFallbackGameDir(const char *pGameDir); +int FileSystem_Init(char *basedir, void *voidfilesystemFactory); +void FileSystem_Shutdown(void); +NOBODY void _GLOBAL__sub_I_g_FileSystemFactory(void); + +#endif // FILESYSTEM__H diff --git a/rehlds/engine/filesystem_internal.cpp b/rehlds/engine/filesystem_internal.cpp new file mode 100644 index 0000000..68ccabf --- /dev/null +++ b/rehlds/engine/filesystem_internal.cpp @@ -0,0 +1,373 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +IFileSystem *g_pFileSystem; + + +/* <2605f> ../engine/filesystem_internal.cpp:18 */ +NOXREF void FS_RemoveAllSearchPaths(void) +{ + //NOXREFCHECK; // We call it + + g_pFileSystem->RemoveAllSearchPaths(); +} + +/* <26073> ../engine/filesystem_internal.cpp:24 */ +void FS_AddSearchPath(const char *pPath, const char *pathID) +{ + g_pFileSystem->AddSearchPath(pPath, pathID); +} + +/* <260a8> ../engine/filesystem_internal.cpp:30 */ +NOXREF int FS_RemoveSearchPath(const char *pPath) +{ + NOXREFCHECK; + + return g_pFileSystem->RemoveSearchPath(pPath); +} + +/* <260d3> ../engine/filesystem_internal.cpp:36 */ +void FS_RemoveFile(const char *pRelativePath, const char *pathID) +{ + g_pFileSystem->RemoveFile(pRelativePath, pathID); +} + +/* <26108> ../engine/filesystem_internal.cpp:42 */ +void FS_CreateDirHierarchy(const char *path, const char *pathID) +{ + g_pFileSystem->CreateDirHierarchy(path, pathID); +} + +/* <2613d> ../engine/filesystem_internal.cpp:48 */ +int FS_FileExists(const char *pFileName) +{ + return g_pFileSystem->FileExists(pFileName); +} + +/* <26168> ../engine/filesystem_internal.cpp:54 */ +NOXREF int FS_IsDirectory(const char *pFileName) +{ + NOXREFCHECK; + + return g_pFileSystem->IsDirectory(pFileName); +} + +/* <26193> ../engine/filesystem_internal.cpp:60 */ +FileHandle_t FS_Open(const char *pFileName, const char *pOptions) +{ + return g_pFileSystem->Open(pFileName, pOptions, 0); +} + +/* <261cc> ../engine/filesystem_internal.cpp:66 */ +FileHandle_t FS_OpenPathID(const char *pFileName, const char *pOptions, const char *pathID) +{ + return g_pFileSystem->Open(pFileName, pOptions, pathID); +} + +/* <26213> ../engine/filesystem_internal.cpp:72 */ +void FS_Close(FileHandle_t file) +{ + g_pFileSystem->Close(file); +} + +/* <2623a> ../engine/filesystem_internal.cpp:78 */ +void FS_Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType) +{ + g_pFileSystem->Seek(file, pos, seekType); +} + +/* <2627d> ../engine/filesystem_internal.cpp:84 */ +unsigned int FS_Tell(FileHandle_t file) +{ + return g_pFileSystem->Tell(file); +} + +/* <262a8> ../engine/filesystem_internal.cpp:90 */ +unsigned int FS_Size(FileHandle_t file) +{ + return g_pFileSystem->Size(file); +} + +/* <262d3> ../engine/filesystem_internal.cpp:96 */ +unsigned int FS_FileSize(const char *pFileName) +{ + return g_pFileSystem->Size(pFileName); +} + +/* <262fe> ../engine/filesystem_internal.cpp:101 */ +int32_t FS_GetFileTime(const char *pFileName) +{ + return g_pFileSystem->GetFileTime(pFileName); +} + +/* <26329> ../engine/filesystem_internal.cpp:107 */ +NOXREF void FS_FileTimeToString(char *pStrip, int maxCharsIncludingTerminator, int32_t fileTime) +{ + NOXREFCHECK; + + g_pFileSystem->FileTimeToString(pStrip, maxCharsIncludingTerminator, fileTime); +} + +/* <2636c> ../engine/filesystem_internal.cpp:113 */ +int FS_IsOk(FileHandle_t file) +{ + return g_pFileSystem->IsOk(file); +} + +/* <26397> ../engine/filesystem_internal.cpp:119 */ +void FS_Flush(FileHandle_t file) +{ + g_pFileSystem->Flush(file); +} + +/* <263be> ../engine/filesystem_internal.cpp:125 */ +int FS_EndOfFile(FileHandle_t file) +{ + return g_pFileSystem->EndOfFile(file); +} + +/* <25fa9> ../engine/filesystem_internal.cpp:131 */ +int FS_Read(void *pOutput, int size, int count, FileHandle_t file) +{ + return g_pFileSystem->Read(pOutput, size, file); +} + +/* <2641e> ../engine/filesystem_internal.cpp:138 */ +int FS_Write(const void *pInput, int size, int count, FileHandle_t file) +{ + return g_pFileSystem->Write(pInput, size, file); +} + +/* <26479> ../engine/filesystem_internal.cpp:145 */ +char *FS_ReadLine(char *pOutput, int maxChars, FileHandle_t file) +{ + return g_pFileSystem->ReadLine(pOutput, maxChars, file); +} + +/* <264c0> ../engine/filesystem_internal.cpp:151 */ +int FS_FPrintf(FileHandle_t file, char *pFormat, ...) +{ + char data[8192]; + va_list va; + + va_start(va, pFormat); + vsprintf(data, pFormat, va); + va_end(va); + + return g_pFileSystem->FPrintf(file, "%s", data); +} + +/* <26534> ../engine/filesystem_internal.cpp:164 */ +const char *FS_FindFirst(const char *pWildCard, FileFindHandle_t *pHandle, const char *pathID) +{ + return g_pFileSystem->FindFirst(pWildCard, pHandle, pathID); +} + +/* <26581> ../engine/filesystem_internal.cpp:170 */ +const char *FS_FindNext(FileFindHandle_t handle) +{ + return g_pFileSystem->FindNext(handle); +} + +/* <265ac> ../engine/filesystem_internal.cpp:176 */ +NOXREF int FS_FindIsDirectory(FileFindHandle_t handle) +{ + NOXREFCHECK; + + return g_pFileSystem->FindIsDirectory(handle); +} + +/* <265d7> ../engine/filesystem_internal.cpp:182 */ +void FS_FindClose(FileFindHandle_t handle) +{ + return g_pFileSystem->FindClose(handle); +} + +/* <26046> ../engine/filesystem_internal.cpp:188 */ +void FS_GetLocalCopy(const char *pFileName) +{ + g_pFileSystem->GetLocalCopy(pFileName); +} + +/* <25fe7> ../engine/filesystem_internal.cpp:194 */ +const char *FS_GetLocalPath(const char *pFileName, char *pLocalPath, int localPathBufferSize) +{ + return g_pFileSystem->GetLocalPath(pFileName, pLocalPath, localPathBufferSize); +} + +/* <2664a> ../engine/filesystem_internal.cpp:200 */ +NOXREF char *FS_ParseFile(char *pFileBytes, char *pToken, int *pWasQuoted) +{ + NOXREFCHECK; + + bool wasquoted; + char *result = g_pFileSystem->ParseFile(pFileBytes, pToken, &wasquoted); + + if (pWasQuoted) + { + *pWasQuoted = wasquoted; + } + + return result; +} + +/* <266ba> ../engine/filesystem_internal.cpp:214 */ +NOXREF int FS_FullPathToRelativePath(const char *pFullpath, char *pRelative) +{ + NOXREFCHECK; + + return g_pFileSystem->FullPathToRelativePath(pFullpath, pRelative); +} + +/* <266f3> ../engine/filesystem_internal.cpp:220 */ +NOXREF int FS_GetCurrentDirectory(char *pDirectory, int maxlen) +{ + NOXREFCHECK; + + return g_pFileSystem->GetCurrentDirectory(pDirectory, maxlen); +} + +/* <2672c> ../engine/filesystem_internal.cpp:226 */ +NOXREF void FS_PrintOpenedFiles(void) +{ + NOXREFCHECK; + + g_pFileSystem->PrintOpenedFiles(); +} + +/* <26740> ../engine/filesystem_internal.cpp:232 */ +NOXREF void FS_SetWarningFunc(void (*pfnWarning)(const char *, ...)) +{ + NOXREFCHECK; + + g_pFileSystem->SetWarningFunc(pfnWarning); +} + +/* <26779> ../engine/filesystem_internal.cpp:238 */ +NOXREF void FS_SetWarningLevel(FileWarningLevel_t level) +{ + NOXREFCHECK; + + g_pFileSystem->SetWarningLevel(level); +} + +/* <267a0> ../engine/filesystem_internal.cpp:245 */ +NOXREF unsigned char FS_GetCharacter(FileHandle_t f) +{ + NOXREFCHECK; + + uint8_t retval; + g_pFileSystem->Read(&retval, 1, f); + return retval; +} + +/* <2680e> ../engine/filesystem_internal.cpp:252 */ +void FS_LogLevelLoadStarted(const char *name) +{ + g_pFileSystem->LogLevelLoadStarted(name); +} + +/* <26835> ../engine/filesystem_internal.cpp:257 */ +void FS_LogLevelLoadFinished(const char *name) +{ + g_pFileSystem->LogLevelLoadFinished(name); +} + +/* <2685e> ../engine/filesystem_internal.cpp:262 */ +int FS_SetVBuf(FileHandle_t stream, char *buffer, int mode, size_t size) +{ + return g_pFileSystem->SetVBuf(stream, buffer, mode, size); +} + +/* <268b8> ../engine/filesystem_internal.cpp:267 */ +void FS_GetInterfaceVersion(char *p, int maxlen) +{ + g_pFileSystem->GetInterfaceVersion(p, maxlen); +} + +/* <268ee> ../engine/filesystem_internal.cpp:272 */ +void *FS_GetReadBuffer(FileHandle_t file, int *outBufSize) +{ + return g_pFileSystem->GetReadBuffer(file, outBufSize, 1); +} + +/* <2692a> ../engine/filesystem_internal.cpp:277 */ +void FS_ReleaseReadBuffer(FileHandle_t file, void *buffer) +{ + g_pFileSystem->ReleaseReadBuffer(file, buffer); +} + +/* <26962> ../engine/filesystem_internal.cpp:282 */ +void FS_Unlink(const char *filename) +{ + char localPath[512]; + FS_GetLocalPath(filename, localPath, 512); + _unlink(localPath); +} + +/* <269e8> ../engine/filesystem_internal.cpp:292 */ +void FS_Rename(const char *originalName, const char *newName) +{ + char *cut; + char localPath[512]; + char newPath[512]; + + if (FS_GetLocalPath(originalName, localPath, 512)) + { + strcpy(newPath, localPath); + cut = strstr(newPath, originalName); + + if (cut) + { + *cut = 0; + strcat(newPath, newName); + rename(localPath, newPath); + } + } +} + +/* <26abf> ../engine/filesystem_internal.cpp:320 */ +void *FS_LoadLibrary(const char *dllName) +{ + void *result = NULL; + + if (dllName) + { + FS_GetLocalCopy(dllName); +#ifdef _WIN32 + result = LoadLibraryA(dllName); +#else + result = dlopen(dllName, 2); +#endif + } + + return result; +} + diff --git a/rehlds/engine/filesystem_internal.h b/rehlds/engine/filesystem_internal.h new file mode 100644 index 0000000..8f5335c --- /dev/null +++ b/rehlds/engine/filesystem_internal.h @@ -0,0 +1,93 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef _FILESYSTEM_INTERNAL_H +#define _FILESYSTEM_INTERNAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "FileSystem.h" + + +#ifdef HOOK_ENGINE +#define g_pFileSystem (*pg_pFileSystem) +#endif // HOOK_ENGINE + +extern IFileSystem *g_pFileSystem; + + +NOXREF void FS_RemoveAllSearchPaths(void); +void FS_AddSearchPath(const char *pPath, const char *pathID); +NOXREF int FS_RemoveSearchPath(const char *pPath); +void FS_RemoveFile(const char *pRelativePath, const char *pathID); +void FS_CreateDirHierarchy(const char *path, const char *pathID); +int FS_FileExists(const char *pFileName); +NOXREF int FS_IsDirectory(const char *pFileName); +FileHandle_t FS_Open(const char *pFileName, const char *pOptions); +FileHandle_t FS_OpenPathID(const char *pFileName, const char *pOptions, const char *pathID); +void FS_Close(FileHandle_t file); +void FS_Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType); +unsigned int FS_Tell(FileHandle_t file); +unsigned int FS_Size(FileHandle_t file); +unsigned int FS_FileSize(const char *pFileName); +int32_t FS_GetFileTime(const char *pFileName); +NOXREF void FS_FileTimeToString(char *pStrip, int maxCharsIncludingTerminator, int32_t fileTime); +int FS_IsOk(FileHandle_t file); +void FS_Flush(FileHandle_t file); +int FS_EndOfFile(FileHandle_t file); +int FS_Read(void *pOutput, int size, int count, FileHandle_t file); +int FS_Write(const void *pInput, int size, int count, FileHandle_t file); +char *FS_ReadLine(char *pOutput, int maxChars, FileHandle_t file); +int FS_FPrintf(FileHandle_t file, char *pFormat, ...); +const char *FS_FindFirst(const char *pWildCard, FileFindHandle_t *pHandle, const char *pathID); +const char *FS_FindNext(FileFindHandle_t handle); +NOXREF int FS_FindIsDirectory(FileFindHandle_t handle); +void FS_FindClose(FileFindHandle_t handle); +void FS_GetLocalCopy(const char *pFileName); +const char *FS_GetLocalPath(const char *pFileName, char *pLocalPath, int localPathBufferSize); +NOXREF char *FS_ParseFile(char *pFileBytes, char *pToken, int *pWasQuoted); +NOXREF int FS_FullPathToRelativePath(const char *pFullpath, char *pRelative); +NOXREF int FS_GetCurrentDirectory(char *pDirectory, int maxlen); +NOXREF void FS_PrintOpenedFiles(void); +NOXREF void FS_SetWarningFunc(void (*pfnWarning)(const char *, ...)); +NOXREF void FS_SetWarningLevel(FileWarningLevel_t level); +NOXREF unsigned char FS_GetCharacter(FileHandle_t f); +void FS_LogLevelLoadStarted(const char *name); +void FS_LogLevelLoadFinished(const char *name); +int FS_SetVBuf(FileHandle_t stream, char *buffer, int mode, size_t size); +void FS_GetInterfaceVersion(char *p, int maxlen); +void *FS_GetReadBuffer(FileHandle_t file, int *outBufSize); +void FS_ReleaseReadBuffer(FileHandle_t file, void *buffer); +void FS_Unlink(const char *filename); +void FS_Rename(const char *originalName, const char *newName); +void *FS_LoadLibrary(const char *dllName); + +#endif // _FILESYSTEM_INTERNAL_H + diff --git a/rehlds/engine/filter.h b/rehlds/engine/filter.h new file mode 100644 index 0000000..091ff2c --- /dev/null +++ b/rehlds/engine/filter.h @@ -0,0 +1,58 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef FILTER_H +#define FILTER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "userid.h" + + +/* ../engine/filter.h:12 */ +typedef struct ipfilter_s +{ + unsigned int mask; + union { + uint32_t u32; + uint8_t octets[4]; + } compare; + float banEndTime; + float banTime; +} ipfilter_t; + +/* ../engine/filter.h:20 */ +typedef struct userfilter_s +{ + USERID_t userid; + float banEndTime; + float banTime; +} userfilter_t; + +#endif // FILTER_H diff --git a/rehlds/engine/hashpak.cpp b/rehlds/engine/hashpak.cpp new file mode 100644 index 0000000..8d13a2b --- /dev/null +++ b/rehlds/engine/hashpak.cpp @@ -0,0 +1,1382 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +hash_pack_queue_t *gp_hpak_queue = NULL; +hash_pack_directory_t hash_pack_dir = { 0, NULL }; +hash_pack_header_t hash_pack_header = { { 0, 0, 0, 0 }, 0, 0 }; + +#else //HOOK_ENGINE + +hash_pack_queue_t *gp_hpak_queue; +hash_pack_directory_t hash_pack_dir; +hash_pack_header_t hash_pack_header; + +#endif //HOOK_ENGINE + +/* <2a7cb> ../engine/hashpak.c:65 */ +qboolean HPAK_GetDataPointer(char *pakname, struct resource_s *pResource, unsigned char **pbuffer, int *bufsize) +{ + qboolean retval = FALSE; + FileHandle_t fp; + hash_pack_header_t header; + hash_pack_directory_t directory; + hash_pack_entry_t *entry; + char name[MAX_PATH]; + byte *pbuf; + + if (pbuffer) + *pbuffer = NULL; + + if (bufsize) + *bufsize = 0; + + if (gp_hpak_queue) + { + for (hash_pack_queue_t *p = gp_hpak_queue; p != NULL; p = p->next) + { + if (Q_stricmp(p->pakname, pakname) != 0 || Q_memcmp(p->resource.rgucMD5_hash, pResource->rgucMD5_hash, 16) != 0) + continue; + + if (pbuffer) + { + pbuf = (byte *)Mem_Malloc(p->datasize); + if (!pbuf) + Sys_Error("Error allocating %i bytes for hpak!", p->datasize); + Q_memcpy((void *)pbuf, p->data, p->datasize); + *pbuffer = pbuf; + } + if (bufsize) + *bufsize = p->datasize; + return TRUE; + } + } + + Q_snprintf(name, ARRAYSIZE(name), "%s", pakname); +#ifdef REHLDS_FIXES + name[ARRAYSIZE(name) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + fp = FS_Open(name, "rb"); + if (!fp) + { + return FALSE; + } + FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); + if (Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp)) != 0) + { + Con_Printf("%s is not an HPAK file\n", name); + FS_Close(fp); + return FALSE; + } + if (header.version != HASHPAK_VERSION) + { + Con_Printf("HPAK_List: version mismatch\n"); + FS_Close(fp); + return FALSE; + } + FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&directory.nEntries, 4, 1, fp); + if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) + { + Con_Printf("ERROR: HPAK had bogus # of directory entries: %i\n", directory.nEntries); + FS_Close(fp); + return FALSE; + } + directory.p_rgEntries = (hash_pack_entry_t *)Mem_ZeroMalloc(sizeof(hash_pack_entry_t) * directory.nEntries); + FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); + + for (int i = 0; i < directory.nEntries; i++) + { + entry = &directory.p_rgEntries[i]; + + if (Q_memcmp(entry->resource.rgucMD5_hash, pResource->rgucMD5_hash, 16) != 0) + continue; + + retval = TRUE; + FS_Seek(fp, entry->nOffset, FILESYSTEM_SEEK_HEAD); + + if (pbuffer && entry->nFileLength > 0) + { + if (bufsize) + *bufsize = entry->nFileLength; + pbuf = (byte *)Mem_Malloc(entry->nFileLength); + + if (!pbuf) + { + Con_Printf("Couln't allocate %i bytes for HPAK entry\n", entry->nFileLength); + + if (bufsize) + *bufsize = 0; + retval = FALSE; + } + + FS_Read(pbuf, entry->nFileLength, 1, fp); + *pbuffer = pbuf; + } + break; + } + + Mem_Free(directory.p_rgEntries); + FS_Close(fp); + + return retval; +} + +/* <2a451> ../engine/hashpak.c:217 */ +qboolean HPAK_FindResource(hash_pack_directory_t *pDir, unsigned char *hash, struct resource_s *pResourceEntry) +{ + for (int i = 0; i < pDir->nEntries; i++) + { + if (Q_memcmp(hash, pDir->p_rgEntries[i].resource.rgucMD5_hash, 16) == 0) + { + if (pResourceEntry) + memcpy(pResourceEntry, &pDir->p_rgEntries[i].resource, sizeof(resource_t)); + + return TRUE; + } + } + return FALSE; +} + +/* <2a916> ../engine/hashpak.c:243 */ +void HPAK_AddToQueue(char *pakname, struct resource_s *pResource, void *pData, FileHandle_t fpSource) +{ + hash_pack_queue_t *n = (hash_pack_queue_t *)Mem_Malloc(sizeof(hash_pack_queue_t)); + if (!n) + Sys_Error("Unable to allocate %i bytes for hpak queue!", sizeof(hash_pack_queue_t)); + + Q_memset(n, 0, sizeof(hash_pack_queue_t)); + n->pakname = Mem_Strdup(pakname); + memcpy(&n->resource, pResource, sizeof(resource_t)); + n->datasize = pResource->nDownloadSize; + n->data = Mem_Malloc(pResource->nDownloadSize); + if (!n->data) + Sys_Error("Unable to allocate %i bytes for hpak queue!", n->datasize); + + if (pData) + { + Q_memcpy(n->data, pData, n->datasize); + n->next = gp_hpak_queue; + gp_hpak_queue = n; + } + else + { + if (!fpSource) + Sys_Error("Add to Queue called without data or file pointer!"); + FS_Read(n->data, n->datasize, 1, fpSource); + n->next = gp_hpak_queue; + gp_hpak_queue = n; + } +} + +/* <2a955> ../engine/hashpak.c:286 */ +void HPAK_FlushHostQueue(void) +{ + for (hash_pack_queue_t *p = gp_hpak_queue; gp_hpak_queue != NULL; p = gp_hpak_queue) + { + gp_hpak_queue = p->next; + HPAK_AddLump(0, p->pakname, &p->resource, p->data, 0); + Mem_Free(p->pakname); + Mem_Free(p->data); + Mem_Free(p); + } +} + +/* <2a494> ../engine/hashpak.c:322 */ +void HPAK_AddLump(qboolean bUseQueue, char *pakname, struct resource_s *pResource, void *pData, FileHandle_t fpSource) +{ + FileHandle_t iRead; + FileHandle_t iWrite; + char name[MAX_PATH]; + char szTempName[MAX_PATH]; + char szOriginalName[MAX_PATH]; + hash_pack_directory_t olddirectory; + hash_pack_directory_t newdirectory; + hash_pack_entry_t *pNewEntry; + + byte md5[16]; + MD5Context_t ctx; + byte *pDiskData; + + if (pakname == NULL) + { + Con_Printf("HPAK_AddLump called with invalid arguments: no .pak filename\n"); + return; + } + if (!pResource) + { + Con_Printf("HPAK_AddLump called with invalid arguments: no lump to add\n"); + return; + } + if (!pData && !fpSource) + { + Con_Printf("HPAK_AddLump called with invalid arguments: no file handle\n"); + return; + } + if (pResource->nDownloadSize < 1024 || (unsigned int)pResource->nDownloadSize > MAX_FILE_SIZE) + { + Con_Printf("HPAK_AddLump called with bogus lump, size: %i\n", pResource->nDownloadSize); + return; + } + Q_memset(&ctx, 0, sizeof(MD5Context_t)); + MD5Init(&ctx); + if (pData) + MD5Update(&ctx, (byte *)pData, pResource->nDownloadSize); + else + { + pDiskData = (byte *)Mem_Malloc(pResource->nDownloadSize + 1); + Q_memset(pDiskData, 0, pResource->nDownloadSize); + + FS_Read(pDiskData, pResource->nDownloadSize, 1, fpSource); + FS_Seek(fpSource, FS_Tell(fpSource), FILESYSTEM_SEEK_HEAD); + + MD5Update(&ctx, pDiskData, pResource->nDownloadSize); + Mem_Free(pDiskData); + } + MD5Final(md5, &ctx); + if (Q_memcmp(pResource->rgucMD5_hash, md5, sizeof(md5)) != 0) + { + Con_Printf("HPAK_AddLump called with bogus lump, md5 mismatch\n"); + Con_Printf("Purported: %s\n", MD5_Print(pResource->rgucMD5_hash)); + Con_Printf("Actual : %s\n", MD5_Print(md5)); + Con_Printf("Ignoring lump addition\n"); + return; + } + if (bUseQueue) + { + HPAK_AddToQueue(pakname, pResource, pData, fpSource); + return; + } + + Q_snprintf(name, ARRAYSIZE(name), "%s", pakname); +#ifdef REHLDS_FIXES + name[ARRAYSIZE(name) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + COM_FixSlashes(name); + + Q_strncpy(szOriginalName, name, ARRAYSIZE(szOriginalName) - 1); + szOriginalName[ARRAYSIZE(szOriginalName) - 1] = 0; + + + iRead = FS_Open(name, "rb"); + + if (!iRead) + { + HPAK_CreatePak(pakname, pResource, pData, fpSource); + return; + } + + COM_StripExtension(name, szTempName); + COM_DefaultExtension(szTempName, ".hp2"); + + iWrite = FS_Open(szTempName, "w+b"); + if (!iWrite) + { + FS_Close(iRead); + Con_Printf("ERROR: couldn't open %s.\n", szTempName); + return; + } + FS_Read(&hash_pack_header, sizeof(hash_pack_header_t), 1, iRead); + if (hash_pack_header.version != HASHPAK_VERSION) + { + FS_Close(iRead); + FS_Close(iWrite); + FS_Unlink(szTempName); + Con_Printf("Invalid .hpk version in HPAK_AddLump\n"); + return; + } + + FS_Seek(iRead, 0, FILESYSTEM_SEEK_HEAD); + COM_CopyFileChunk(iWrite, iRead, FS_Size(iRead)); + FS_Seek(iRead, hash_pack_header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&olddirectory.nEntries, 4, 1, iRead); + + if (olddirectory.nEntries < 1 || (unsigned int)olddirectory.nEntries > MAX_FILE_ENTRIES) + { + FS_Close(iRead); + FS_Close(iWrite); + FS_Unlink(szTempName); + Con_Printf("ERROR: .hpk had bogus # of directory entries: %i\n", olddirectory.nEntries); + return; + } + + olddirectory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * olddirectory.nEntries); + + FS_Read(olddirectory.p_rgEntries, sizeof(hash_pack_entry_t) * olddirectory.nEntries, 1, iRead); + FS_Close(iRead); + + if (HPAK_FindResource(&olddirectory, pResource->rgucMD5_hash, NULL) != FALSE) + { + FS_Close(iWrite); + FS_Unlink(szTempName); + Mem_Free(olddirectory.p_rgEntries); + return; + } + + newdirectory.nEntries = olddirectory.nEntries + 1; + newdirectory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * newdirectory.nEntries); + + Q_memset(newdirectory.p_rgEntries, 0, sizeof(hash_pack_entry_t) * newdirectory.nEntries); + Q_memcpy(newdirectory.p_rgEntries, olddirectory.p_rgEntries, sizeof(hash_pack_entry_t) * olddirectory.nEntries); + + pNewEntry = NULL; + + for (int i = 0; i < olddirectory.nEntries; i++) + { + if (Q_memcmp(pResource->rgucMD5_hash, olddirectory.p_rgEntries[i].resource.rgucMD5_hash, 16) >= 0) + { + pNewEntry = &newdirectory.p_rgEntries[i]; + while (i < olddirectory.nEntries) + { + memcpy(&newdirectory.p_rgEntries[i + 1], &olddirectory.p_rgEntries[i + 1], sizeof(hash_pack_entry_t)); + i++; + } + break; + } + } + + if (pNewEntry == NULL) + { + pNewEntry = &newdirectory.p_rgEntries[newdirectory.nEntries - 1]; + } + + Q_memset(pNewEntry, 0, sizeof(hash_pack_entry_t)); + FS_Seek(iWrite, hash_pack_header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + + memcpy(&pNewEntry->resource, pResource, sizeof(resource_t)); + + pNewEntry->nOffset = FS_Tell(iWrite); + pNewEntry->nFileLength = pResource->nDownloadSize; + + if (pData) + FS_Write(pData, pResource->nDownloadSize, 1, iWrite); + + else COM_CopyFileChunk(iWrite, fpSource, pResource->nDownloadSize); + + hash_pack_header.nDirectoryOffset = FS_Tell(iWrite); + + FS_Write(&newdirectory.nEntries, 4, 1, iWrite); + + for (int j = 0; j < newdirectory.nEntries; j++) + FS_Write(&newdirectory.p_rgEntries[j], sizeof(hash_pack_entry_t), 1, iWrite); + + if (newdirectory.p_rgEntries) + Mem_Free(newdirectory.p_rgEntries); + + if (olddirectory.p_rgEntries) + Mem_Free(olddirectory.p_rgEntries); + + FS_Seek(iWrite, 0, FILESYSTEM_SEEK_HEAD); + FS_Write(&hash_pack_header, sizeof(hash_pack_header_t), 1, iWrite); + FS_Close(iWrite); + FS_Unlink(szOriginalName); + FS_Rename(szTempName, szOriginalName); +} + +/* <2a974> ../engine/hashpak.c:598 */ +void HPAK_RemoveLump(char *pakname, resource_t *pResource) +{ + FileHandle_t fp; + FileHandle_t tmp; + char szTempName[MAX_PATH]; + char szOriginalName[MAX_PATH]; + hash_pack_directory_t olddir; + hash_pack_directory_t newdir; + hash_pack_entry_t *oldentry; + hash_pack_entry_t *newentry; + int n; + int i; + + if (pakname == NULL || *pakname == '\0' || pResource == NULL) + { + Con_Printf(__FUNCTION__ ": Invalid arguments\n"); + return; + } + HPAK_FlushHostQueue(); + +#ifdef REHLDS_FIXES + Q_strncpy(szOriginalName, pakname, ARRAYSIZE(szOriginalName) - 1); + szOriginalName[ARRAYSIZE(szOriginalName) - 1] = 0; + COM_DefaultExtension(szOriginalName, HASHPAK_EXTENSION); +#else + + //TODO: Not sure why Cmd_Argv(1) is used since function receives pakname parameter + char name[MAX_PATH]; + Q_snprintf(name, ARRAYSIZE(name), "%s", Cmd_Argv(1)); + COM_DefaultExtension(name, HASHPAK_EXTENSION); + Q_strncpy(szOriginalName, name, ARRAYSIZE(szOriginalName) - 1); + szOriginalName[ARRAYSIZE(szOriginalName) - 1] = 0; + +#endif // REHLDS_FIXES + + fp = FS_Open(szOriginalName, "rb"); + if (!fp) + { + Con_Printf("Error: couldn't open HPAK file %s for removal.\n", szOriginalName); + return; + } + COM_StripExtension(szOriginalName, szTempName); + COM_DefaultExtension(szTempName, ".hp2"); + + tmp = FS_Open(szTempName, "w+b"); + if (!tmp) + { + FS_Close(fp); + Con_Printf("ERROR: couldn't create %s.\n", szTempName); + return; + } + FS_Seek(fp, 0, FILESYSTEM_SEEK_HEAD); + FS_Seek(tmp, 0, FILESYSTEM_SEEK_HEAD); + FS_Read(&hash_pack_header, sizeof(hash_pack_header_t), 1, fp); + FS_Write(&hash_pack_header, sizeof(hash_pack_header_t), 1, tmp); + if (Q_strncmp(hash_pack_header.szFileStamp, "HPAK", sizeof(hash_pack_header.szFileStamp))) + { + FS_Close(fp); + FS_Close(tmp); + FS_Unlink(szTempName); + Con_Printf("%s is not an HPAK file\n", szOriginalName); + return; + } + if (hash_pack_header.version != HASHPAK_VERSION) + { + FS_Close(fp); + FS_Close(tmp); + FS_Unlink(szTempName); + Con_Printf("ERROR: HPAK version outdated\n"); + return; + } + FS_Seek(fp, hash_pack_header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&olddir.nEntries, 4, 1, fp); + if (olddir.nEntries < 1 || (unsigned int)olddir.nEntries > MAX_FILE_ENTRIES) + { + FS_Close(fp); + FS_Close(tmp); + FS_Unlink(szTempName); + Con_Printf("ERROR: HPAK had bogus # of directory entries: %i\n", olddir.nEntries); + return; + } + if (olddir.nEntries == 1) + { + FS_Close(fp); + FS_Close(tmp); + FS_Unlink(szOriginalName); + FS_Unlink(szTempName); + Con_Printf("Removing final lump from HPAK, deleting HPAK:\n %s\n", szOriginalName); + return; + } + olddir.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * olddir.nEntries); + FS_Read(olddir.p_rgEntries, sizeof(hash_pack_entry_t) * olddir.nEntries, 1, fp); + + newdir.nEntries = olddir.nEntries - 1; + newdir.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * newdir.nEntries); + if (!HPAK_FindResource(&olddir, pResource->rgucMD5_hash, NULL)) + { + FS_Close(fp); + FS_Close(tmp); + FS_Unlink(szTempName); + Mem_Free(olddir.p_rgEntries); + Mem_Free(newdir.p_rgEntries); + + Con_Printf("ERROR: HPAK doesn't contain specified lump: %s\n", pResource->szFileName); + return; + } + Con_Printf("Removing %s from HPAK %s.\n", pResource->szFileName, szOriginalName); + for (i = 0, n = 0; i < olddir.nEntries; i++) + { + oldentry = &olddir.p_rgEntries[i]; + + if (Q_memcmp(olddir.p_rgEntries[i].resource.rgucMD5_hash, pResource->rgucMD5_hash, 16)) + { + newentry = &newdir.p_rgEntries[n++]; + memcpy(newentry, oldentry, sizeof(hash_pack_entry_t)); + newentry->nOffset = FS_Tell(tmp); + + FS_Seek(fp, oldentry->nOffset, FILESYSTEM_SEEK_HEAD); + COM_CopyFileChunk(tmp, fp, newentry->nFileLength); + } + } + hash_pack_header.nDirectoryOffset = FS_Tell(tmp); + FS_Write(&newdir.nEntries, 4, 1, tmp); + for (i = 0; i < newdir.nEntries; i++) + FS_Write(&newdir.p_rgEntries[i], sizeof(hash_pack_entry_t), 1, tmp); + + FS_Seek(tmp, 0, FILESYSTEM_SEEK_HEAD); + FS_Write(&hash_pack_header, sizeof(hash_pack_header_t), 1, tmp); + FS_Close(fp); + FS_Close(tmp); + FS_Unlink(szOriginalName); + FS_Rename(szTempName, szOriginalName); + Mem_Free(olddir.p_rgEntries); + Mem_Free(newdir.p_rgEntries); +} + +/* <2aac9> ../engine/hashpak.c:772 */ +qboolean HPAK_ResourceForIndex(char *pakname, int nIndex, struct resource_s *pResource) +{ + hash_pack_header_t header; + hash_pack_directory_t directory; + hash_pack_entry_t *entry; + char name[MAX_PATH]; + FileHandle_t fp; + + if (cmd_source != src_command) + return FALSE; + + Q_snprintf(name, ARRAYSIZE(name), "%s", pakname); +#ifdef REHLDS_FIXES + name[ARRAYSIZE(name) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + fp = FS_Open(name, "rb"); + if (!fp) + { + Con_Printf("ERROR: couldn't open %s.\n", name); + return FALSE; + } + FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); + if (Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp))) + { + Con_Printf("%s is not an HPAK file\n", name); + FS_Close(fp); + return FALSE; + } + if (header.version != HASHPAK_VERSION) + { + Con_Printf("HPAK_List: version mismatch\n"); + FS_Close(fp); + return FALSE; + } + FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&directory.nEntries, 4, 1, fp); + if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) + { + Con_Printf("ERROR: HPAK had bogus # of directory entries: %i\n", directory.nEntries); + FS_Close(fp); + return FALSE; + } + if (nIndex < 1 || nIndex > directory.nEntries) + { + Con_Printf("ERROR: HPAK bogus directory entry request: %i\n", nIndex); + FS_Close(fp); + return FALSE; + } + directory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * directory.nEntries); + FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); + entry = &directory.p_rgEntries[nIndex - 1]; + memcpy(pResource, &entry->resource, sizeof(resource_t)); + FS_Close(fp); + Mem_Free(directory.p_rgEntries); + return TRUE; +} + +/* <2abc5> ../engine/hashpak.c:855 */ +qboolean HPAK_ResourceForHash(char *pakname, unsigned char *hash, struct resource_s *pResourceEntry) +{ + qboolean bFound; + hash_pack_header_t header; + hash_pack_directory_t directory; + char name[MAX_PATH]; + FileHandle_t fp; + + if (gp_hpak_queue) + { + for (hash_pack_queue_t *p = gp_hpak_queue; p != NULL; p = p->next) + { + if (Q_stricmp(p->pakname, pakname) != 0 || Q_memcmp(p->resource.rgucMD5_hash, hash, 16) != 0) + continue; + + if (pResourceEntry) + memcpy(pResourceEntry, &p->resource, sizeof(resource_t)); + + return TRUE; + } + } + + Q_snprintf(name, ARRAYSIZE(name), "%s", pakname); +#ifdef REHLDS_FIXES + name[ARRAYSIZE(name) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + fp = FS_Open(name, "rb"); + if (!fp) + { + Con_Printf("ERROR: couldn't open %s.\n", name); + return FALSE; + } + FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); + if (Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp))) + { + Con_Printf("%s is not an HPAK file\n", name); + FS_Close(fp); + return FALSE; + } + if (header.version != HASHPAK_VERSION) + { + Con_Printf("HPAK_List: version mismatch\n"); + FS_Close(fp); + return FALSE; + } + FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&directory.nEntries, 4, 1, fp); + if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) + { + Con_Printf("ERROR: HPAK had bogus # of directory entries: %i\n", directory.nEntries); + FS_Close(fp); + return FALSE; + } + directory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * directory.nEntries); + FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); + + bFound = HPAK_FindResource(&directory, hash, pResourceEntry); + + FS_Close(fp); + Mem_Free(directory.p_rgEntries); + return bFound; +} + +/* <2a644> ../engine/hashpak.c:945 */ +void HPAK_List_f(void) +{ + hash_pack_header_t header; + hash_pack_directory_t directory; + hash_pack_entry_t *entry; + char name[MAX_PATH]; + char szFileName[MAX_PATH]; + char type[32]; + FileHandle_t fp; + + if (cmd_source != src_command) + return; + + HPAK_FlushHostQueue(); + + Q_snprintf(name, ARRAYSIZE(name), "%s", Cmd_Argv(1)); +#ifdef REHLDS_FIXES + name[ARRAYSIZE(name) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + Con_Printf("Contents for %s.\n", name); + + fp = FS_Open(name, "rb"); + if (!fp) + { + Con_Printf("ERROR: couldn't open %s.\n", name); + return; + } + FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); + if (Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp))) + { + Con_Printf("%s is not an HPAK file\n", name); + FS_Close(fp); + return; + } + if (header.version != HASHPAK_VERSION) + { + Con_Printf("HPAK_List: version mismatch\n"); + FS_Close(fp); + return; + } + FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&directory.nEntries, 4, 1, fp); + if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) + { + Con_Printf("ERROR: HPAK had bogus # of directory entries: %i\n", directory.nEntries); + FS_Close(fp); + return; + } + Con_Printf("# of Entries: %i\n", directory.nEntries); + Con_Printf("# Type Size FileName : MD5 Hash\n"); + + directory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * directory.nEntries); + FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); + for (int nCurrent = 0; nCurrent < directory.nEntries; nCurrent++) + { + entry = &directory.p_rgEntries[nCurrent]; + COM_FileBase(entry->resource.szFileName, szFileName); + switch (entry->resource.type) + { + case t_sound: + strcpy(type, "sound"); + break; + case t_skin: + strcpy(type, "skin"); + break; + case t_model: + strcpy(type, "model"); + break; + case t_decal: + strcpy(type, "decal"); + break; + case t_generic: + strcpy(type, "generic"); + break; + case t_eventscript: + strcpy(type, "event"); + break; + default: + strcpy(type, "?"); + break; + } + Con_Printf("%i: %10s %.2fK %s\n : %s\n", nCurrent + 1, type, entry->resource.nDownloadSize / 1024.0f, szFileName, MD5_Print(entry->resource.rgucMD5_hash)); + } + FS_Close(fp); + Mem_Free(directory.p_rgEntries); +} + +/* <2a121> ../engine/hashpak.c:1060 */ +void HPAK_CreatePak(char *pakname, struct resource_s *pResource, void *pData, FileHandle_t fpSource) +{ + char name[MAX_PATH]; + int32_t curpos; + FileHandle_t fp; + hash_pack_entry_t *pCurrentEntry; + + byte md5[16]; + MD5Context_t ctx; + byte *pDiskData; + + if ((!fpSource && !pData) || (fpSource && pData)) + { + Con_Printf("HPAK_CreatePak, must specify one of pData or fpSource\n"); + return; + } + + Q_snprintf(name, ARRAYSIZE(name), "%s", pakname); +#ifdef REHLDS_FIXES + name[ARRAYSIZE(name) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + Con_Printf("Creating HPAK %s.\n", name); + + fp = FS_Open(name, "wb"); + if (!fp) + { + Con_Printf("ERROR: couldn't open new .hpk, check access rights to %s.\n", name); + return; + } + + Q_memset(&ctx, 0, sizeof(MD5Context_t)); + MD5Init(&ctx); + + if (pData) + MD5Update(&ctx, (byte *)pData, pResource->nDownloadSize); + else + { + curpos = FS_Tell(fpSource); + pDiskData = (byte *)Mem_Malloc(pResource->nDownloadSize + 1); + Q_memset(pDiskData, 0, pResource->nDownloadSize); + FS_Read(pDiskData, pResource->nDownloadSize, 1, fp); + FS_Seek(fpSource, curpos, FILESYSTEM_SEEK_HEAD); + MD5Update(&ctx, pDiskData, pResource->nDownloadSize); + Mem_Free(pDiskData); + } + + MD5Final(md5, &ctx); + if (Q_memcmp(pResource->rgucMD5_hash, md5, sizeof(md5)) != 0) + { + Con_Printf("HPAK_CreatePak called with bogus lump, md5 mismatch\n"); + Con_Printf("Purported: %s\n", MD5_Print(pResource->rgucMD5_hash)); + Con_Printf("Actual : %s\n", MD5_Print(md5)); + Con_Printf("Ignoring lump addition\n"); + return; + } + + Q_memset(&hash_pack_header, 0, sizeof(hash_pack_header_t)); + Q_strncpy(hash_pack_header.szFileStamp, "HPAK", sizeof(hash_pack_header.szFileStamp)); + + hash_pack_header.version = HASHPAK_VERSION; + hash_pack_header.nDirectoryOffset = 0; + + FS_Write(&hash_pack_header, sizeof(hash_pack_header_t), 1, fp); + Q_memset(&hash_pack_dir, 0, sizeof(hash_pack_directory_t)); + + hash_pack_dir.nEntries = 1; + hash_pack_dir.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t)); + Q_memset(hash_pack_dir.p_rgEntries, 0, sizeof(hash_pack_entry_t) * hash_pack_dir.nEntries); + + pCurrentEntry = &hash_pack_dir.p_rgEntries[0]; + memcpy(&pCurrentEntry->resource, pResource, sizeof(resource_t)); + + pCurrentEntry->nOffset = FS_Tell(fp); + pCurrentEntry->nFileLength = pResource->nDownloadSize; + + if (pData) + FS_Write(pData, pResource->nDownloadSize, 1, fp); + + else COM_CopyFileChunk(fp, fpSource, pResource->nDownloadSize); + + curpos = FS_Tell(fp); + FS_Write(&hash_pack_dir.nEntries, 4, 1, fp); + FS_Write(&hash_pack_dir.p_rgEntries, sizeof(hash_pack_entry_t), 1, fp); + + if (hash_pack_dir.p_rgEntries) + { + Mem_Free(hash_pack_dir.p_rgEntries); + hash_pack_dir.p_rgEntries = NULL; + } + + hash_pack_dir.nEntries = 0; + hash_pack_header.nDirectoryOffset = curpos; + + FS_Seek(fp, 0, FILESYSTEM_SEEK_HEAD); + FS_Write(&hash_pack_header, sizeof(hash_pack_header_t), 1, fp); + FS_Close(fp); +} + +/* <2ab62> ../engine/hashpak.c:1200 */ +void HPAK_Remove_f(void) +{ + int nIndex; + char *pakname; + + resource_t resource; + + if (cmd_source != src_command) + return; + + HPAK_FlushHostQueue(); + if (Cmd_Argc() != 3) + { + Con_Printf("Usage: hpkremove \n"); + return; + } + + pakname = (char *)Cmd_Argv(1); + + nIndex = Q_atoi(Cmd_Argv(2)); + if (HPAK_ResourceForIndex(pakname, nIndex, &resource)) + HPAK_RemoveLump(pakname, &resource); + else Con_Printf("Could not locate resource %i in %s\n", nIndex, pakname); +} + +/* <2a3cb> ../engine/hashpak.c:1235 */ +void HPAK_Validate_f(void) +{ + hash_pack_header_t header; + hash_pack_directory_t directory; + hash_pack_entry_t *entry; + char name[MAX_PATH]; + char szFileName[MAX_PATH]; + char type[32]; + FileHandle_t fp; + + byte *pData; + int nDataSize; + byte md5[16]; + MD5Context_t ctx; + + if (cmd_source != src_command) + return; + + HPAK_FlushHostQueue(); + + if (Cmd_Argc() != 2) + { + Con_Printf("Usage: hpkval hpkname\n"); + return; + } + + Q_snprintf(name, ARRAYSIZE(name), "%s", Cmd_Argv(1)); +#ifdef REHLDS_FIXES + name[ARRAYSIZE(name) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + Con_Printf("Validating %s.\n", name); + + fp = FS_Open(name, "rb"); + if (!fp) + { + Con_Printf("ERROR: couldn't open %s.\n", name); + return; + } + FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); + if (Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp))) + { + Con_Printf("%s is not an HPAK file\n", name); + FS_Close(fp); + return; + } + if (header.version != HASHPAK_VERSION) + { + Con_Printf("hpkval: version mismatch\n"); + FS_Close(fp); + return; + } + FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&directory.nEntries, 4, 1, fp); + if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) + { + Con_Printf("ERROR: HPAK had bogus # of directory entries: %i\n", directory.nEntries); + FS_Close(fp); + return; + } + + Con_Printf("# of Entries: %i\n", directory.nEntries); + Con_Printf("# Type Size FileName : MD5 Hash\n"); + + directory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * directory.nEntries); + FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); + for (int nCurrent = 0; nCurrent < directory.nEntries; nCurrent++) + { + entry = &directory.p_rgEntries[nCurrent]; + COM_FileBase(entry->resource.szFileName, szFileName); + switch (entry->resource.type) + { + case t_sound: + strcpy(type, "sound"); + break; + case t_skin: + strcpy(type, "skin"); + break; + case t_model: + strcpy(type, "model"); + break; + case t_decal: + strcpy(type, "decal"); + break; + case t_generic: + strcpy(type, "generic"); + break; + case t_eventscript: + strcpy(type, "event"); + break; + default: + strcpy(type, "?"); + break; + } + + Con_Printf("%i: %10s %.2fK %s: ", nCurrent + 1, type, entry->resource.nDownloadSize / 1024.0f, szFileName); + + nDataSize = entry->nFileLength; + if (nDataSize < 1 || (unsigned int)nDataSize >= MAX_FILE_SIZE) + Con_Printf("Unable to MD5 hash data, size invalid: %i\n", nDataSize); + else + { + pData = (byte *)Mem_Malloc(nDataSize + 1); + Q_memset(pData, 0, nDataSize); + FS_Seek(fp, entry->nOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(pData, nDataSize, 1, fp); + Q_memset(&ctx, 0, sizeof(MD5Context_t)); + + MD5Init(&ctx); + MD5Update(&ctx, pData, nDataSize); + MD5Final(md5, &ctx); + + if (Q_memcmp(entry->resource.rgucMD5_hash, md5, sizeof(md5)) == 0) + Con_Printf(" OK\n"); + else + { + Con_Printf(" MISMATCHED\n"); + Con_Printf("--------------------\n"); + Con_Printf(" File : %s\n", MD5_Print(entry->resource.rgucMD5_hash)); + Con_Printf(" Actual: %s\n", MD5_Print(md5)); + Con_Printf("--------------------\n"); + } + if (pData) + Mem_Free(pData); + } + } + FS_Close(fp); + Mem_Free(directory.p_rgEntries); +} + +/* <2a33c> ../engine/hashpak.c:1401 */ +void HPAK_Extract_f(void) +{ + hash_pack_header_t header; + hash_pack_directory_t directory; + hash_pack_entry_t *entry; + char name[MAX_PATH]; + char type[32]; + FileHandle_t fp; + int nIndex; + + byte *pData; + int nDataSize; + FileHandle_t fpOutput; + char szFileOut[MAX_PATH]; + + if (cmd_source != src_command) + return; + + HPAK_FlushHostQueue(); + + if (Cmd_Argc() != 3) + { + Con_Printf("Usage: hpkextract hpkname [all | single index]\n"); + return; + } + if (Q_stricmp(Cmd_Argv(2),"all") != 0) + { + nIndex = Q_atoi(Cmd_Argv(2)); + +#ifdef REHLDS_FIXES + Q_snprintf(name, sizeof(name), "%s", Cmd_Argv(1)); +#else + Q_snprintf(name, 256, "%s", Cmd_Argv(1)); +#endif // REHLDS_FIXES + if (nIndex != -1) + Con_Printf("Extracting lump %i from %s\n", nIndex, name); + } + else + { + nIndex = -1; + + Q_snprintf(name, ARRAYSIZE(name), "%s", Cmd_Argv(1)); +#ifdef REHLDS_FIXES + name[ARRAYSIZE(name) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + Con_Printf("Extracting all lumps from %s.\n", name); + } + + fp = FS_Open(name, "rb"); + if (!fp) + { + Con_Printf("ERROR: couldn't open %s.\n", name); + return; + } + FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); + if (Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp))) + { + Con_Printf("%s is not an HPAK file\n", name); + FS_Close(fp); + return; + } + if (header.version != HASHPAK_VERSION) + { + Con_Printf("hpkextract: version mismatch\n"); + FS_Close(fp); + return; + } + FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&directory.nEntries, 4, 1, fp); + if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) + { + Con_Printf("ERROR: HPAK had bogus # of directory entries: %i\n", directory.nEntries); + FS_Close(fp); + return; + } + + Con_Printf("# of Entries: %i\n", directory.nEntries); + Con_Printf("# Type Size FileName : MD5 Hash\n"); + + directory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * directory.nEntries); + FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); + for (int nCurrent = 0; nCurrent < directory.nEntries; nCurrent++) + { + entry = &directory.p_rgEntries[nCurrent]; + if (nIndex == -1 || nIndex == nCurrent) + { + COM_FileBase(entry->resource.szFileName, szFileOut); + switch (entry->resource.type) + { + case t_sound: + strcpy(type, "sound"); + break; + case t_skin: + strcpy(type, "skin"); + break; + case t_model: + strcpy(type, "model"); + break; + case t_decal: + strcpy(type, "decal"); + break; + case t_generic: + strcpy(type, "generic"); + break; + case t_eventscript: + strcpy(type, "event"); + break; + default: + strcpy(type, "?"); + break; + } + + Con_Printf("Extracting %i: %10s %.2fK %s\n", nCurrent, type, entry->resource.nDownloadSize / 1024.0f, szFileOut); + nDataSize = entry->nFileLength; + if (nDataSize < 1 || (unsigned int)nDataSize >= MAX_FILE_SIZE) + Con_Printf("Unable to extract data, size invalid: %s\n", nDataSize); + + else + { + pData = (byte *)Mem_Malloc(nDataSize + 1); + Q_memset(pData, 0, nDataSize); + FS_Seek(fp, entry->nOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(pData, nDataSize, 1, fp); + Q_snprintf(szFileOut, sizeof(szFileOut), "hpklmps\\lmp%04i.wad", nCurrent); + COM_FixSlashes(szFileOut); + COM_CreatePath(szFileOut); + fpOutput = FS_Open(szFileOut, "wb"); + if (fpOutput) + { + FS_Write(pData, nDataSize, 1, fpOutput); + FS_Close(fpOutput); + } + else Con_Printf("Error creating lump file %s\n", szFileOut); + if (pData) + Mem_Free(pData); + } + } + } + + FS_Close(fp); + Mem_Free(directory.p_rgEntries); +} + +/* <2ae78> ../engine/hashpak.c:1580 */ +void HPAK_Init(void) +{ +#ifdef HOOK_ENGINE + Cmd_AddCommand("hpklist", (xcommand_t)GetOriginalFuncAddrOrDefault("HPAK_List_f", (void *)HPAK_List_f)); + Cmd_AddCommand("hpkremove", (xcommand_t)GetOriginalFuncAddrOrDefault("HPAK_Remove_f", (void *)HPAK_Remove_f)); + Cmd_AddCommand("hpkval", (xcommand_t)GetOriginalFuncAddrOrDefault("HPAK_Validate_f", (void *)HPAK_Validate_f)); + Cmd_AddCommand("hpkextract", (xcommand_t)GetOriginalFuncAddrOrDefault("HPAK_Extract_f", (void *)HPAK_Extract_f)); +#else + Cmd_AddCommand("hpklist", HPAK_List_f); + Cmd_AddCommand("hpkremove", HPAK_Remove_f); + Cmd_AddCommand("hpkval", HPAK_Validate_f); + Cmd_AddCommand("hpkextract", HPAK_Extract_f); +#endif // HOOK_ENGINE + gp_hpak_queue = NULL; +} + +/* <2ae8e> ../engine/hashpak.c:1599 */ +NOXREF char *HPAK_GetItem(int item) +{ + NOXREFCHECK; + + int nCurrent; + hash_pack_header_t header; + hash_pack_directory_t directory; + hash_pack_entry_t *entry; + static char name[MAX_PATH]; + char szFileName[MAX_PATH]; + FileHandle_t fp; + + HPAK_FlushHostQueue(); + + Q_snprintf(name, ARRAYSIZE(name), "%s", "custom"); + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + fp = FS_Open(name, "rb"); + + if (!fp) + return ""; + + FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); + if (Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp))) + { + Con_Printf("%s is not an HPAK file\n", name); + FS_Close(fp); + return ""; + } + if (header.version != HASHPAK_VERSION) + { + Con_Printf("HPAK_List: version mismatch\n"); + FS_Close(fp); + return ""; + } + FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&directory.nEntries, 4, 1, fp); + if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) + { + Con_Printf("ERROR: HPAK had bogus # of directory entries: %i\n", directory.nEntries); + FS_Close(fp); + return ""; + } + directory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * directory.nEntries); + FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); + nCurrent = directory.nEntries - 1; + if (nCurrent > item) + nCurrent = item; + entry = &directory.p_rgEntries[nCurrent]; + COM_FileBase(entry->resource.szFileName, szFileName); + Q_snprintf(name, sizeof(name), "!MD5%s", MD5_Print(entry->resource.rgucMD5_hash)); + FS_Close(fp); + Mem_Free(directory.p_rgEntries); + return name; +} + +/* <2af4b> ../engine/hashpak.c:1678 */ +void HPAK_CheckSize(char *pakname) +{ + char fullname[MAX_PATH]; + float maxSize; + float actualSize; + FileHandle_t hfile; + + maxSize = hpk_maxsize.value; + if (!maxSize || pakname == NULL) + return; + + if (maxSize < 0.0f) + { + Con_Printf("hpk_maxsize < 0, setting to 0\n"); + Cvar_DirectSet(&hpk_maxsize, "0"); + return; + } + + Q_snprintf(fullname, ARRAYSIZE(fullname), "%s", pakname); +#ifdef REHLDS_FIXES + fullname[ARRAYSIZE(fullname) - 1] = 0; +#endif // REHLDS_FIXES + + COM_DefaultExtension(fullname, HASHPAK_EXTENSION); + COM_FixSlashes(fullname); + + actualSize = 0.0f; + maxSize *= 1000000.0f; + + hfile = FS_Open(fullname, "rb"); + if (hfile) + { + actualSize = (float)FS_Size(hfile); + FS_Close(hfile); + } + if (actualSize >= maxSize) + { + Con_Printf("Server: Size of %s > %f MB, deleting.\n", fullname, hpk_maxsize.value); + Log_Printf("Server: Size of %s > %f MB, deleting.\n", fullname, hpk_maxsize.value); + FS_RemoveFile(fullname, 0); + } +} + +/* <2afb5> ../engine/hashpak.c:1728 */ +void HPAK_ValidatePak(char *fullpakname) +{ + hash_pack_header_t header; + hash_pack_directory_t directory; + hash_pack_entry_t *entry; + char szFileName[MAX_PATH]; + FileHandle_t fp; + + byte *pData; + byte md5[16]; + + MD5Context_t ctx; + + HPAK_FlushHostQueue(); + fp = FS_Open(fullpakname, "rb"); + + if (!fp) + return; + + FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); + + if (header.version != HASHPAK_VERSION || Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp)) != 0) + { + Con_Printf("%s is not a PAK file, deleting\n", fullpakname); + FS_Close(fp); + FS_RemoveFile(fullpakname, 0); + return; + } + + FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&directory, 4, 1, fp); + + if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) + { + Con_Printf("ERROR: HPAK %s had bogus # of directory entries: %i, deleting\n", fullpakname, directory.nEntries); + FS_Close(fp); + FS_RemoveFile(fullpakname, 0); + return; + } + + directory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * directory.nEntries); + FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); + for (int nCurrent = 0; nCurrent < directory.nEntries; nCurrent++) + { + entry = &directory.p_rgEntries[nCurrent]; + COM_FileBase(entry->resource.szFileName, szFileName); + + if ((unsigned int)entry->nFileLength >= MAX_FILE_SIZE) + { + Con_Printf("Mismatched data in HPAK file %s, deleting\n", fullpakname); + Con_Printf("Unable to MD5 hash data lump %i, size invalid: %i\n", nCurrent + 1, entry->nFileLength); + + FS_Close(fp); + FS_RemoveFile(fullpakname, 0); + Mem_Free(directory.p_rgEntries); + return; + } + + pData = (byte *)Mem_Malloc(entry->nFileLength + 1); + + Q_memset(pData, 0, entry->nFileLength); + FS_Seek(fp, entry->nOffset, FILESYSTEM_SEEK_HEAD); + FS_Read(pData, entry->nFileLength, 1, fp); + Q_memset(&ctx, 0, sizeof(MD5Context_t)); + + MD5Init(&ctx); + MD5Update(&ctx, pData, entry->nFileLength); + MD5Final(md5, &ctx); + + if (pData) + Mem_Free(pData); + + if (Q_memcmp(entry->resource.rgucMD5_hash, md5, sizeof(md5)) != 0) + { + Con_Printf("Mismatched data in HPAK file %s, deleting\n", fullpakname); + FS_Close(fp); + FS_RemoveFile(fullpakname, 0); + Mem_Free(directory.p_rgEntries); + return; + } + } + FS_Close(fp); + Mem_Free(directory.p_rgEntries); +} + +/* <2b0b6> ../engine/hashpak.c:1848 */ +void HPAK_CheckIntegrity(char *pakname) +{ + char name[256]; + Q_snprintf(name, sizeof(name), "%s", pakname); + + COM_DefaultExtension(name, HASHPAK_EXTENSION); + COM_FixSlashes(name); + HPAK_ValidatePak(name); +} diff --git a/rehlds/engine/hashpak.h b/rehlds/engine/hashpak.h new file mode 100644 index 0000000..ead75a9 --- /dev/null +++ b/rehlds/engine/hashpak.h @@ -0,0 +1,109 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef HASHPAK_H +#define HASHPAK_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "custom.h" +#include "FileSystem.h" + +#define HASHPAK_EXTENSION ".hpk" +#define HASHPAK_VERSION 0x0001 + +#define MAX_FILE_SIZE 0x20000 /* size: 131072 */ +#define MAX_FILE_ENTRIES 0x8000 /* size: 32768 */ + +/* <29eca> ../engine/hashpak.c:40 */ +typedef struct hash_pack_queue_s +{ + char *pakname; + resource_t resource; + int datasize; + void *data; + struct hash_pack_queue_s *next; +} hash_pack_queue_t; + +/* <29e0a> ../engine/hashpak.c:20 */ +typedef struct hash_pack_entry_s +{ + resource_t resource; + int nOffset; + int nFileLength; +} hash_pack_entry_t; + +/* <29e4e> ../engine/hashpak.c:27 */ +typedef struct hash_pack_directory_s +{ + int nEntries; + hash_pack_entry_t *p_rgEntries; +} hash_pack_directory_t; + +/* <29e88> ../engine/hashpak.c:33 */ +typedef struct hash_pack_header_s +{ + char szFileStamp[4]; + int version; + int nDirectoryOffset; +} hash_pack_header_t; + +#ifdef HOOK_ENGINE +#define gp_hpak_queue (*pgp_hpak_queue) +#define hash_pack_dir (*phash_pack_dir) +#define hash_pack_header (*phash_pack_header) +#endif // HOOK_ENGINE + +extern hash_pack_queue_t *gp_hpak_queue; + +//TODO: used only in hashpak +extern hash_pack_directory_t hash_pack_dir; +extern hash_pack_header_t hash_pack_header; + +qboolean HPAK_GetDataPointer(char *pakname, struct resource_s *pResource, unsigned char **pbuffer, int *bufsize); +qboolean HPAK_FindResource(hash_pack_directory_t *pDir, unsigned char *hash, struct resource_s *pResourceEntry); +void HPAK_AddToQueue(char *pakname, struct resource_s *pResource, void *pData, FileHandle_t fpSource); +void HPAK_FlushHostQueue(void); +void HPAK_AddLump(qboolean bUseQueue, char *pakname, struct resource_s *pResource, void *pData, FileHandle_t fpSource); +void HPAK_RemoveLump(char *pakname, struct resource_s *pResource); +qboolean HPAK_ResourceForIndex(char *pakname, int nIndex, struct resource_s *pResource); +qboolean HPAK_ResourceForHash(char *pakname, unsigned char *hash, struct resource_s *pResourceEntry); +void HPAK_List_f(void); +void HPAK_CreatePak(char *pakname, struct resource_s *pResource, void *pData, FileHandle_t fpSource); +void HPAK_Remove_f(void); +void HPAK_Validate_f(void); +void HPAK_Extract_f(void); +void HPAK_Init(void); +NOXREF char *HPAK_GetItem(int item); +void HPAK_CheckSize(char *pakname); +void HPAK_ValidatePak(char *fullpakname); +void HPAK_CheckIntegrity(char *pakname); + +#endif // HASHPAK_H diff --git a/rehlds/engine/host.cpp b/rehlds/engine/host.cpp new file mode 100644 index 0000000..a99ea29 --- /dev/null +++ b/rehlds/engine/host.cpp @@ -0,0 +1,1285 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +double realtime; +double rolling_fps; +quakeparms_t host_parms; +qboolean host_initialized; +double host_frametime; +//short unsigned int *host_basepal; +int host_framecount; +//int minimum_memory; +client_t *host_client; +qboolean gfNoMasterServer; +//qboolean g_bUsingInGameAdvertisements; +double oldrealtime; +int host_hunklevel; +jmp_buf host_abortserver; +jmp_buf host_enddemo; +unsigned short *host_basepal; +//unsigned char *host_colormap; +//const char *g_InGameAdsAllowed[3]; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t host_name = { "hostname", "Half-Life", 0, 0.0f, NULL }; +cvar_t host_speeds = { "host_speeds", "0", 0, 0.0f, NULL }; +cvar_t host_profile = { "host_profile", "0", 0, 0.0f, NULL }; +cvar_t developer = { "developer", "0", 0, 0.0f, NULL }; +cvar_t host_limitlocal = { "host_limitlocal", "0", 0, 0.0f, NULL }; +cvar_t skill = { "skill", "1", 0, 0.0f, NULL }; +cvar_t deathmatch = { "deathmatch", "0", FCVAR_SERVER, 0.0f, NULL }; +cvar_t coop = { "coop", "0", FCVAR_SERVER, 0.0f, NULL }; + +cvar_t sys_ticrate = { "sys_ticrate", "100.0", 0, 0.0f, NULL }; +cvar_t sys_timescale = { "sys_timescale", "1.0", 0, 0.0f, NULL }; +cvar_t fps_max = { "fps_max", "100.0", FCVAR_ARCHIVE, 0.0f, NULL }; +cvar_t host_killtime = { "host_killtime", "0.0", 0, 0.0f, NULL }; +cvar_t sv_stats = { "sv_stats", "1", 0, 0.0f, NULL }; +cvar_t fps_override = { "fps_override", "0", 0, 0.0f, NULL }; +cvar_t host_framerate = { "host_framerate", "0", 0, 0.0f, NULL }; +cvar_t pausable = { "pausable", "1", FCVAR_SERVER, 0.0f, NULL }; +cvar_t suitvolume = { "suitvolume", "0.25", FCVAR_ARCHIVE, 0.0f, NULL }; + +#else //HOOK_ENGINE + +cvar_t host_name; +cvar_t host_speeds; +cvar_t host_profile; +cvar_t developer; +cvar_t host_limitlocal; +cvar_t skill; +cvar_t deathmatch; +cvar_t coop; + +cvar_t sys_ticrate; +cvar_t sys_timescale; +cvar_t fps_max; +cvar_t host_killtime; +cvar_t sv_stats; +cvar_t fps_override; +cvar_t host_framerate; +cvar_t pausable; +cvar_t suitvolume; + +#endif //HOOK_ENGINE + +/* <3617e> ../engine/host.c:201 */ +NOXREF void Host_EndGame(const char *message, ...) +{ + int oldn; + va_list argptr; + char string[1024]; + + va_start(argptr,message); + Q_vsnprintf(string, sizeof(string), message, argptr); + va_end(argptr); + + Con_DPrintf("Host_EndGame: %s\n", string); + + oldn = g_pcls.demonum; + + if (g_psv.active) + Host_ShutdownServer(FALSE); + + g_pcls.demonum = oldn; + + if (!g_pcls.state) + { + Sys_Error("Host_EndGame: %s\n", string); + } + + if (oldn != -1) + { + CL_Disconnect_f(); + g_pcls.demonum = oldn; + Host_NextDemo(); + longjmp(host_enddemo, 1); + } + + CL_Disconnect(); + Cbuf_AddText("cd stop\n"); + Cbuf_Execute(); + longjmp(host_abortserver, 1); +} + +/* <36123> ../engine/host.c:255 */ +void __declspec(noreturn) Host_Error(const char *error, ...) +{ + va_list argptr; + char string[1024]; + static qboolean inerror = FALSE; + + va_start(argptr, error); + + if (inerror) + Sys_Error("Host_Error: recursively entered"); + + inerror = TRUE; + SCR_EndLoadingPlaque(); + Q_vsnprintf(string, sizeof(string), error, argptr); + va_end(argptr); + + if (g_psv.active && developer.value != 0.0 ) + CL_WriteMessageHistory(0, 0); + + Con_Printf("Host_Error: %s\n", string); + if (g_psv.active) + Host_ShutdownServer(FALSE); + + if (g_pcls.state) + { + CL_Disconnect(); + g_pcls.demonum = -1; + inerror = FALSE; + longjmp(host_abortserver, 1); + } + Sys_Error("Host_Error: %s\n", string); +} + +/* <35d12> ../engine/host.c:297 */ +void Host_InitLocal(void) +{ + Host_InitCommands(); + Cvar_RegisterVariable(&host_killtime); + Cvar_RegisterVariable(&sys_ticrate); + Cvar_RegisterVariable(&fps_max); + Cvar_RegisterVariable(&fps_override); + Cvar_RegisterVariable(&host_name); + Cvar_RegisterVariable(&host_limitlocal); + + sys_timescale.value = 1.0f; + + Cvar_RegisterVariable(&host_framerate); + Cvar_RegisterVariable(&host_speeds); + Cvar_RegisterVariable(&host_profile); + Cvar_RegisterVariable(&mp_logfile); + Cvar_RegisterVariable(&mp_logecho); + Cvar_RegisterVariable(&sv_log_onefile); + Cvar_RegisterVariable(&sv_log_singleplayer); + Cvar_RegisterVariable(&sv_logsecret); + Cvar_RegisterVariable(&sv_stats); + Cvar_RegisterVariable(&developer); + Cvar_RegisterVariable(&deathmatch); + Cvar_RegisterVariable(&coop); + Cvar_RegisterVariable(&pausable); + Cvar_RegisterVariable(&skill); + + SV_SetMaxclients(); +} + +/* <35d28> ../engine/host.c:349 */ +NOXREF void Info_WriteVars(FileHandle_t fp) +{ + cvar_t *pcvar; + char *s; + char pkey[512]; + + static char value[4][512]; + static int valueindex; + + char *o; + + valueindex = (valueindex + 1) % 4; + s = &g_pcls.userinfo[0]; + + if (*s == '\\') + s++; + + while (1) + { + o = pkey; + while (*s != '\\') + { + if (!*s) + return; + *o++ = *s++; + } + + *o = 0; + s++; + + o = value[valueindex]; + + while (*s != '\\' && *s) + { + if (!*s) + return; + *o++ = *s++; + } + *o = 0; + + pcvar = Cvar_FindVar(pkey); + if (!pcvar && pkey[0] != '*') + FS_FPrintf(fp, "setinfo \"%s\" \"%s\"\n", pkey, value[valueindex]); + + if (!*s) + return; + s++; + } +} + +/* <35dc8> ../engine/host.c:409 */ +void Host_WriteConfiguration(void) +{ +#ifndef SWDS + FILE *f; + kbutton_t *ml; + kbutton_t *jl; + qboolean bSetFileToReadOnly; + char nameBuf[4096]; + + if (!host_initialized || g_pcls.state == ca_dedicated) + return; + +#ifdef _WIN32 + Sys_GetRegKeyValue("Software\\Valve\\Steam", "rate", rate_.string); + if (cl_name.string && Q_stricmp(cl_name.string, "unnamed") && Q_stricmp(cl_name.string, "player") && Q_strlen(cl_name.string)) + Sys_GetRegKeyValue("Software\\Valve\\Steam", "LastGameNameUsed", cl_name.string); +#else + SetRateRegistrySetting(rate_.string); +#endif // _WIN32 + if (Key_CountBindings() <= 1) + { + Con_Printf("skipping config.cfg output, no keys bound\n"); + return; + } + + bSetFileToReadOnly = FALSE; + f = FS_OpenPathID("config.cfg", "w", "GAMECONFIG"); + if (!f) + { + if (!developer.value || !FS_FileExists("../goldsrc/dev_build_all.bat")) + { + if (FS_GetLocalPath("config.cfg", nameBuf, sizeof(nameBuf))) + { + bSetFileToReadOnly = TRUE; + chmod(nameBuf, S_IREAD|S_IWRITE); + } + f = FS_OpenPathID("config.cfg", "w", "GAMECONFIG"); + if (!f) + { + Con_Printf("Couldn't write config.cfg.\n"); + return; + } + } + } + + FS_FPrintf(f, "// This file is overwritten whenever you change your user settings in the game.\n"); + FS_FPrintf(f, "// Add custom configurations to the file \"userconfig.cfg\".\n\n"); + FS_FPrintf(f, "unbindall\n"); + + Key_WriteBindings(f); + Cvar_WriteVariables(f); + Info_WriteVars(f); + + ml = ClientDLL_FindKey("in_mlook"); + jl = ClientDLL_FindKey("in_jlook"); + + if (ml && (ml->state & 1)) + FS_FPrintf(f, "+mlook\n"); + + if (jl && (jl->state & 1)) + FS_FPrintf(f, "+jlook\n"); + + FS_FPrintf(f, "exec userconfig.cfg\n"); + FS_Close(f); + + if (bSetFileToReadOnly) + { + FS_GetLocalPath("config.cfg", nameBuf, sizeof(nameBuf)); + chmod(nameBuf, S_IREAD); + } +#endif // SWDS +} + +/* <35df2> ../engine/host.c:516 */ +void Host_WriteCustomConfig(void) +{ +#ifndef SWDS + FILE *f; + kbutton_t *ml; + kbutton_t *jl; +#endif + char configname[261]; + Q_snprintf(configname, 257, "%s", Cmd_Args()); + if (Q_strstr(configname, "..") + || !Q_stricmp(configname, "config") + || !Q_stricmp(configname, "autoexec") + || !Q_stricmp(configname, "listenserver") + || !Q_stricmp(configname, "server") + || !Q_stricmp(configname, "userconfig")) + { + Con_Printf("skipping writecfg output, invalid filename given\n"); + } +#ifndef SWDS + else + { + if (host_initialized && g_pcls.state != ca_dedicated) + { + if (Key_CountBindings() < 2) + Con_Printf("skipping config.cfg output, no keys bound\n"); + else + { + Q_strcat(configname, ".cfg"); + f = FS_OpenPathID(configname, "w", "GAMECONFIG"); + if (!f) + { + Con_Printf("Couldn't write %s.\n", configname); + return; + } + + FS_FPrintf(f, "unbindall\n"); + Key_WriteBindings(f); + Cvar_WriteVariables(f); + Info_WriteVars(f); + + ml = ClientDLL_FindKey("in_mlook"); + jl = ClientDLL_FindKey("in_jlook"); + + if (ml && ml->state & 1) + FS_FPrintf(f, "+mlook\n"); + + if (jl && jl->state & 1) + FS_FPrintf(f, "+jlook\n"); + + FS_Close(f); + Con_Printf("%s successfully created!\n", configname); + } + } + } +#endif // SWDS +} + +/* <35e4e> ../engine/host.c:594 */ +void SV_ClientPrintf(const char *fmt, ...) +{ + va_list va; + char string[1024]; + + if (!host_client->fakeclient) + { + va_start(va, fmt); + Q_vsnprintf(string, ARRAYSIZE(string) - 1, fmt, va); + va_end(va); + + string[ARRAYSIZE(string) - 1] = 0; + + MSG_WriteByte(&host_client->netchan.message, svc_print); + MSG_WriteString(&host_client->netchan.message, string); + } +} + +/* <35eaa> ../engine/host.c:617 */ +void SV_BroadcastPrintf(const char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start(argptr, fmt); + Q_vsnprintf(string, ARRAYSIZE(string) - 1, fmt, argptr); + va_end(argptr); + + string[ARRAYSIZE(string) - 1] = 0; + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + if ((cl->active || cl->spawned) && !cl->fakeclient) + { + MSG_WriteByte(&cl->netchan.message, svc_print); + MSG_WriteString(&cl->netchan.message, string); + } + } + Con_DPrintf("%s", string); +} + +/* <35f03> ../engine/host.c:646 */ +void Host_ClientCommands(const char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start(argptr, fmt); + if (!host_client->fakeclient) + { + Q_vsnprintf(string, sizeof(string), fmt, argptr); + string[sizeof(string) - 1] = 0; + + MSG_WriteByte(&host_client->netchan.message, svc_stufftext); + MSG_WriteString(&host_client->netchan.message, string); + } + va_end(argptr); +} + +void SV_DropClient_api(IGameClient* cl, bool crash, const char* fmt, ...) +{ + char buf[1024]; + va_list argptr; + va_start(argptr, fmt); + + Q_vsnprintf(buf, ARRAYSIZE(buf) - 1, fmt, (va_list)argptr); + va_end(argptr); + buf[ARRAYSIZE(buf) - 1] = 0; + + SV_DropClient(cl->GetClient(), crash ? TRUE : FALSE, "%s", buf); +} + +/* <35f4e> ../engine/host.c:673 */ +void SV_DropClient(client_t *cl, qboolean crash, const char *fmt, ...) +{ + int i; + char string[1024]; + unsigned char final[512]; + float connection_time; + va_list argptr; + + va_start(argptr, fmt); + i = 0; + +#ifdef REHLDS_CHECKS + Q_vsnprintf(string, sizeof(string) - 1, fmt, (va_list)argptr); + string[sizeof(string) - 1] = 0; +#else + Q_vsnprintf(string, sizeof(string), fmt, (va_list)argptr); +#endif // REHLDS_CHECKS + + va_end(argptr); + + if (!crash) + { + if (!cl->fakeclient) + { + MSG_WriteByte(&cl->netchan.message, svc_disconnect); + MSG_WriteString(&cl->netchan.message, string); + final[0] = svc_disconnect; + Q_strncpy((char *)&final[1], string, min(sizeof(final) - 1, Q_strlen(string) + 1)); + final[sizeof(final) - 1] = 0; + i = 1 + min(sizeof(final) - 1, Q_strlen(string) + 1); + } + if (cl->edict && cl->spawned) + gEntityInterface.pfnClientDisconnect(cl->edict); + + Sys_Printf("Dropped %s from server\nReason: %s\n", cl->name, string); + + if (!cl->fakeclient) + Netchan_Transmit(&cl->netchan, i, final); + } + + connection_time = realtime - cl->netchan.connect_time; + if (connection_time > 60.0) + { + ++g_psvs.stats.num_sessions; + g_psvs.stats.cumulative_sessiontime = g_psvs.stats.cumulative_sessiontime + connection_time; + } + + Netchan_Clear(&cl->netchan); + + Steam_NotifyClientDisconnect(cl); + + cl->active = FALSE; + cl->connected = FALSE; + cl->hasusrmsgs = FALSE; + cl->fakeclient = FALSE; + cl->spawned = FALSE; + cl->fully_connected = FALSE; + cl->name[0] = 0; + cl->connection_started = realtime; + cl->proxy = FALSE; + COM_ClearCustomizationList(&cl->customdata, FALSE); + cl->edict = NULL; + Q_memset(cl->userinfo, 0, sizeof(cl->userinfo)); + Q_memset(cl->physinfo, 0, sizeof(cl->physinfo)); + + SV_FullClientUpdate(cl, &g_psv.reliable_datagram); + + NotifyDedicatedServerUI("UpdatePlayers"); +} + +/* <35cc8> ../engine/host.c:763 */ +void Host_ClearClients(qboolean bFramesOnly) +{ + int i; + int j; + client_frame_t *frame; + netadr_t save; + + host_client = g_psvs.clients; + for (i = 0; i < g_psvs.maxclients; i++, host_client++) + { + if (host_client->frames) + { + for (j = 0; j < SV_UPDATE_BACKUP; j++) + { + frame = &(host_client->frames[j]); + SV_ClearPacketEntities(frame); + frame->senttime = 0; + frame->ping_time = -1; + } + } + if (host_client->netchan.remote_address.type) + { + Q_memcpy(&save, &host_client->netchan.remote_address, sizeof(netadr_t)); + Q_memset(&host_client->netchan, 0, sizeof(netchan_t)); + Netchan_Setup(NS_SERVER, &host_client->netchan, save, host_client - g_psvs.clients, (void *)host_client, SV_GetFragmentSize); + } + COM_ClearCustomizationList(&host_client->customdata, 0); + } + + if (bFramesOnly == FALSE) + { + host_client = g_psvs.clients; + for (i = 0; i < g_psvs.maxclientslimit; i++, host_client++) + SV_ClearFrames(&host_client->frames); + + Q_memset(g_psvs.clients, 0, sizeof(client_t) * g_psvs.maxclientslimit); + SV_AllocClientFrames(); + } +} + +/* <3605a> ../engine/host.c:815 */ +void Host_ShutdownServer(qboolean crash) +{ + int i; + if (!g_psv.active) + return; + + SV_ServerShutdown(); + g_psv.active = FALSE; + NET_ClearLagData(TRUE, TRUE); + + host_client = g_psvs.clients; + for (i = 0; i < g_psvs.maxclients; i++, host_client++) + { + if (host_client->active || host_client->connected) + SV_DropClient(host_client, crash, "Server shutting down"); + } + + CL_Disconnect(); + SV_ClearEntities(); + SV_ClearCaches(); + FreeAllEntPrivateData(); + Q_memset(&g_psv, 0, sizeof(server_t)); + CL_ClearClientState(); + + SV_ClearClientStates(); + Host_ClearClients(FALSE); + + host_client = g_psvs.clients; + for (i = 0; i < g_psvs.maxclientslimit; i++, host_client++) + SV_ClearFrames(&host_client->frames); + + Q_memset(g_psvs.clients, 0, sizeof(client_t) * g_psvs.maxclientslimit); + HPAK_FlushHostQueue(); + Steam_Shutdown(); + Log_Printf("Server shutdown\n"); + Log_Close(); +} + +/* <361d4> ../engine/host.c:924 */ +void SV_ClearClientStates(void) +{ + int i; + client_t *cl; + + for (i = 0, cl = g_psvs.clients; i < g_psvs.maxclients; i++, cl++) + { + COM_ClearCustomizationList(&cl->customdata, FALSE); + SV_ClearResourceLists(cl); + } +} + +/* <361fc> ../engine/host.c:942 */ +void Host_CheckDyanmicStructures(void) +{ + int i; + client_t *cl; + + cl = g_psvs.clients; + for (i = 0; i < g_psvs.maxclients; i++, cl++) + { + if (cl->frames) + SV_ClearFrames(&cl->frames); + } +} + +/* <36249> ../engine/host.c:970 */ +void Host_ClearMemory(qboolean bQuiet) +{ + + //Engine string pooling +#ifdef REHLDS_FIXES + Ed_StrPool_Reset(); +#endif //REHLDS_FIXES + + CM_FreePAS(); + SV_ClearEntities(); + + if (!bQuiet) + Con_DPrintf("Clearing memory\n"); + + D_FlushCaches(); + Mod_ClearAll(); + if (host_hunklevel) + { + Host_CheckDyanmicStructures(); + Hunk_FreeToLowMark(host_hunklevel); + } + + g_pcls.signon = 0; + SV_ClearCaches(); + Q_memset(&g_psv, 0, sizeof(server_t)); + CL_ClearClientState(); + SV_ClearClientStates(); +} + +/* <362d1> ../engine/host.c:1003 */ +qboolean Host_FilterTime(float time) +{ + float fps; + static int command_line_ticrate = -1; + + if (host_framerate.value > 0.0f) + { + if (Host_IsSinglePlayerGame() || g_pcls.demoplayback) + { + host_frametime = sys_timescale.value * host_framerate.value; + realtime += host_frametime; + return TRUE; + } + } + + realtime += sys_timescale.value * time; + if (g_bIsDedicatedServer) + { + if (command_line_ticrate == -1) + command_line_ticrate = COM_CheckParm("-sys_ticrate"); + + if (command_line_ticrate > 0) + fps = atof(com_argv[command_line_ticrate + 1]); + else + fps = sys_ticrate.value; + + if (fps > 0.0f) + { + if (1.0f / (fps + 1.0f) > realtime - oldrealtime) + return FALSE; + } + } + else + { + fps = 31.0f; + if (g_psv.active || g_pcls.state == ca_disconnected || g_pcls.state == ca_active) + { + fps = 0.5f; + if (fps_max.value >= 0.5f) + fps = fps_max.value; + } + if (!fps_override.value) + { + if (fps > 100.0f) + fps = 100.0f; + } + if (g_pcl.maxclients > 1) + { + if (fps < 20.0f) + fps = 20.0f; + } + if (gl_vsync.value) + { + if (!fps_override.value) + fps = 100.f; + } + if (!g_pcls.timedemo) + { + if (sys_timescale.value / (fps + 0.5f) > realtime - oldrealtime) + return FALSE; + } + } + + host_frametime = realtime - oldrealtime; + oldrealtime = realtime; + + if (host_frametime > 0.25f) + host_frametime = 0.25f; + + return TRUE; +} + +/* <36351> ../engine/host.c:1100 */ +qboolean Master_IsLanGame(void) +{ + return sv_lan.value != 0.0f; +} + +/* <3636a> ../engine/host.c:1116 */ +void Master_Heartbeat_f(void) +{ + //Steam_ForceHeartbeat in move? + CRehldsPlatformHolder::get()->SteamGameServer()->ForceHeartbeat(); +} + +/* <3637f> ../engine/host.c:1130 */ +void Host_ComputeFPS(double frametime) +{ + rolling_fps = 0.6 * rolling_fps + 0.4 * frametime; +} + +/* <3639c> ../engine/host.c:1140 */ +void Host_GetHostInfo(float *fps, int *nActive, int *unused, int *nMaxPlayers, char *pszMap) +{ + if (rolling_fps > 0.0) + { + *fps = 1.0 / rolling_fps; + } + else + { + rolling_fps = 0; + *fps = 0; + } + + int clients = 0; + SV_CountPlayers(&clients); + *nActive = clients; + + if (unused) + *unused = 0; + + if (pszMap) + { + if (g_psv.name[0]) + { + Q_strcpy(pszMap, g_psv.name); + } + else + { + *pszMap = 0; + } + } + + *nMaxPlayers = g_psvs.maxclients; +} + +/* <36411> ../engine/host.c:1174 */ +void Host_Speeds(double *time) +{ + float pass1, pass2, pass3, pass4, pass5; + double frameTime; + double fps; + +#ifdef REHLDS_FIXES + if (host_speeds.value != 0.0f) // FIXED: do calculations only if host_speeds is enabled + { +#endif // REHLDS_FIXES + pass1 = (float)((time[1] - time[0]) * 1000.0); + pass2 = (float)((time[2] - time[1]) * 1000.0); + pass3 = (float)((time[3] - time[2]) * 1000.0); + pass4 = (float)((time[4] - time[3]) * 1000.0); + pass5 = (float)((time[5] - time[4]) * 1000.0); + + frameTime = (pass5 + pass4 + pass3 + pass2 + pass1) / 1000.0; + + if (frameTime >= 0.0001) + fps = 1.0 / frameTime; + else + fps = 999.0; + + // FIXED: do calculations only if host_speeds is enabled +#ifndef REHLDS_FIXES + if (host_speeds.value != 0.0f) + { +#endif // REHLDS_FIXES + int ent_count = 0; + for (int i = 0; i < g_psv.num_edicts; i++) + { + if (!g_psv.edicts[i].free) + ++ent_count; + } + Con_Printf("%3i fps -- host(%3.0f) sv(%3.0f) cl(%3.0f) gfx(%3.0f) snd(%3.0f) ents(%d)\n", (int)fps, pass1, pass2, pass3, pass4, pass5, ent_count); + } + +#ifndef SWDS + if (cl_gg.value != 0.0f) + { + //sub_1D10B2D + CL_GGSpeeds(time[3]); + } +#endif // SWDS +} + +/* <36495> ../engine/host.c:1231 */ +void Host_UpdateScreen(void) +{ + if (!gfBackground) + { + SCR_UpdateScreen(); + if (cl_inmovie) + { + if (*(float *)&scr_con_current == 0.0f) + VID_WriteBuffer(NULL); + } + } +} + +/* <364b1> ../engine/host.c:1288 */ +void Host_UpdateSounds(void) +{ + if (!gfBackground) + { + //S_PrintStats(); + } +} + +/* <364dd> ../engine/host.c:1320 */ +void Host_CheckConnectionFailure(void) +{ + static int frames = 5; + if (g_pcls.state == ca_disconnected && (giSubState & 4 || console.value == 0.0f)) + { + if (frames-- > 0) + return; + + giActive = DLL_PAUSED; + frames = 5; + } +} + +/* <364fd> ../engine/host.c:1350 */ +void _Host_Frame(float time) +{ + static double host_times[6]; + if (setjmp(host_enddemo)) + return; + + //Unknown_windows_func_01D37CD0(); + if (!Host_FilterTime(time)) + return; + + FR_StartFrame(); + + //SystemWrapper_RunFrame(host_frametime); + + if (g_modfuncs.m_pfnFrameBegin) + g_modfuncs.m_pfnFrameBegin(); + + Host_ComputeFPS(host_frametime); + R_SetStackBase(); + CL_CheckClientState(); + Cbuf_Execute(); + ClientDLL_UpdateClientData(); + + if (g_psv.active) + CL_Move(); + + host_times[1] = Sys_FloatTime(); + SV_Frame(); + host_times[2] = Sys_FloatTime(); + SV_CheckForRcon(); + + if (!g_psv.active) + CL_Move(); + + ClientDLL_Frame(host_frametime); + CL_SetLastUpdate(); + CL_ReadPackets(); + CL_RedoPrediction(); + CL_VoiceIdle(); + CL_EmitEntities(); + CL_CheckForResend(); + + while (CL_RequestMissingResources()) + ; + CL_UpdateSoundFade(); + Host_CheckConnectionFailure(); + //CL_HTTPUpdate(); + Steam_ClientRunFrame(); + ClientDLL_CAM_Think(); + CL_MoveSpectatorCamera(); + host_times[3] = Sys_FloatTime(); + Host_UpdateScreen(); + host_times[4] = Sys_FloatTime(); + CL_DecayLights(); + Host_UpdateSounds(); + host_times[0] = host_times[5]; + host_times[5] = Sys_FloatTime(); + + Host_Speeds(host_times); + ++host_framecount; + CL_AdjustClock(); + + if (sv_stats.value == 1.0f) + Host_UpdateStats(); + + if (host_killtime.value != 0.0 && host_killtime.value < g_psv.time) + { + Host_Quit_f(); + } + + FR_EndFrame(); +} + +/* <36628> ../engine/host.c:1501 */ +int Host_Frame(float time, int iState, int *stateInfo) +{ + double time1; + double time2; + + if (setjmp(host_abortserver)) + { + return giActive; + } + + if (giActive != 3 || !g_iQuitCommandIssued) + giActive = iState; + + *stateInfo = 0; + if (host_profile.value != 0.0f) + time1 = Sys_FloatTime(); + + _Host_Frame(time); + if (host_profile.value != 0.0) + time2 = Sys_FloatTime(); + + if (giStateInfo) + { + *stateInfo = giStateInfo; + giStateInfo = 0; + Cbuf_Execute(); + } + + if (host_profile.value != 0.0) + { + static double timetotal; + static int timecount; + + timecount++; + timetotal += time2 - time1; + if (++timecount >= 1000) + { + int m = (timetotal * 1000.0 / (double)timecount); + int c = 0; + timecount = 0; + timetotal = 0.0; + for (int i = 0; i < g_psvs.maxclients; i++) + { + if (g_psvs.clients[i].active) + ++c; + } + + Con_Printf("host_profile: %2i clients %2i msec\n", c, m); + } + } + + return giActive; +} + +/* <3672c> ../engine/host.c:1577 */ +void CheckGore(void) +{ + if (bLowViolenceBuild) + { + Cvar_SetValue("violence_hblood", 0.0); + Cvar_SetValue("violence_hgibs", 0.0); + Cvar_SetValue("violence_ablood", 0.0); + Cvar_SetValue("violence_agibs", 0.0); + } + else + { + Cvar_SetValue("violence_hblood", 1.0); + Cvar_SetValue("violence_hgibs", 1.0); + Cvar_SetValue("violence_ablood", 1.0); + Cvar_SetValue("violence_agibs", 1.0); + } +} + +/* <35bad> ../engine/host.c:1649 */ +qboolean Host_IsSinglePlayerGame(void) +{ + if (g_psv.active) + return g_psvs.maxclients == 1; + else + return g_pcl.maxclients == 1; + +} + +/* <3676e> ../engine/host.c:1656 */ +qboolean Host_IsServerActive(void) +{ + return g_psv.active; +} + +/* <36787> ../engine/host.c:1664 */ +void Host_Version(void) +{ + char szFileName[MAX_PATH]; + + Q_strcpy(gpszVersionString, "1.0.1.4"); + Q_strcpy(gpszProductString, "valve"); + strcpy(szFileName, "steam.inf"); + FileHandle_t fp = FS_Open(szFileName, "r"); + if (fp) + { + int bufsize = FS_Size(fp); + char* buffer = (char*)Mem_Malloc(bufsize + 1); + FS_Read(buffer, bufsize, 1, fp); + char *pbuf = buffer; + FS_Close(fp); + buffer[bufsize] = 0; + int gotKeys = 0; + + pbuf = COM_Parse(pbuf); + if (pbuf) + { + while (Q_strlen(com_token) > 0 && gotKeys <= 1) + { + if (!Q_strnicmp(com_token, "PatchVersion=", Q_strlen("PatchVersion="))) + { + Q_strncpy(gpszVersionString, &com_token[Q_strlen("PatchVersion=")], sizeof(gpszVersionString)); + gpszVersionString[sizeof(gpszVersionString) - 1] = 0; + if (COM_CheckParm("-steam")) + { + char szSteamVersionId[32]; + FS_GetInterfaceVersion(szSteamVersionId, sizeof(szSteamVersionId) - 1); + _snprintf(gpszVersionString, sizeof(gpszVersionString), "%s/%s", &com_token[Q_strlen("PatchVersion=")], szSteamVersionId); + gpszVersionString[sizeof(gpszVersionString) - 1] = 0; + } + ++gotKeys; + } + else if (!Q_strnicmp(com_token, "ProductName=", Q_strlen("ProductName="))) + { + ++gotKeys; + Q_strncpy(gpszProductString, &com_token[Q_strlen("ProductName=")], sizeof(gpszProductString) - 1); + gpszProductString[sizeof(gpszProductString) - 1] = 0; + } + + pbuf = COM_Parse(pbuf); + if (!pbuf) + break; + } + } + if (buffer) + Mem_Free(buffer); + } + + if (g_pcls.state != ca_dedicated) + { + Con_DPrintf("Protocol version %i\nExe version %s (%s)\n", PROTOCOL_VERSION, gpszVersionString, gpszProductString); + Con_DPrintf("Exe build: 13:14:09 Aug 29 2013 (%i)\n", build_number()); + } + else + { + Con_Printf("Protocol version %i\nExe version %s (%s)\n", PROTOCOL_VERSION, gpszVersionString, gpszProductString); + Con_Printf("Exe build: 13:14:09 Aug 29 2013 (%i)\n", build_number()); + } +} + +/* <36823> ../engine/host.c:1764 */ +int Host_Init(quakeparms_t *parms) +{ + char versionString[256]; + + CRehldsPlatformHolder::get()->srand(CRehldsPlatformHolder::get()->time(NULL)); + + memcpy(&host_parms, parms, sizeof(host_parms)); + com_argc = parms->argc; + com_argv = parms->argv; + realtime = 0; + + Memory_Init(parms->membase, parms->memsize); + + Voice_RegisterCvars(); + Cvar_RegisterVariable(&console); + if (COM_CheckParm("-console") || COM_CheckParm("-toconsole") || COM_CheckParm("-dev")) + Cvar_DirectSet(&console, "1.0"); + Host_InitLocal(); + if (COM_CheckParm("-dev")) + Cvar_SetValue("developer", 1.0); + + //Engine string pooling +#ifdef REHLDS_FIXES + Ed_StrPool_Init(); +#endif //REHLDS_FIXES + + FR_Init(); + + Cbuf_Init(); + Cmd_Init(); + Cvar_Init(); + Cvar_CmdInit(); + V_Init(); + Chase_Init(); + COM_Init(parms->basedir); + Host_ClearSaveDirectory(); + HPAK_Init(); + W_LoadWadFile("gfx.wad"); + W_LoadWadFile("fonts.wad"); + Key_Init(); + Con_Init(); + Decal_Init(); + Mod_Init(); + NET_Init(); + Netchan_Init(); + DELTA_Init(); + SV_Init(); + //SystemWrapper_Init(); + Host_Version(); + + + + _snprintf(versionString, sizeof(versionString), "%s,%i,%i", gpszVersionString, PROTOCOL_VERSION, build_number()); + Cvar_Set("sv_version", versionString); + Con_DPrintf("%4.1f Mb heap\n", (double)parms->memsize / (1024.0f * 1024.0f)); + R_InitTextures(); + HPAK_CheckIntegrity("custom"); + Q_memset(&g_module, 0, sizeof(g_module)); + if (g_pcls.state != ca_dedicated) + { + //Sys_Error("Only dedicated server mode is supported"); + + color24 *disk_basepal = (color24 *)COM_LoadHunkFile("gfx/palette.lmp"); + if (!disk_basepal) + Sys_Error("Host_Init: Couldn't load gfx/palette.lmp"); + + host_basepal = (unsigned short *)Hunk_AllocName(sizeof(PackedColorVec) * 256, "palette.lmp"); + for (int i = 0; i < 256; i++) + { + PackedColorVec *basepal = (PackedColorVec *)&host_basepal[i]; + + basepal->b = disk_basepal->r; + basepal->g = disk_basepal->g; + basepal->r = disk_basepal->b; + basepal->a = 0;//alpha + + disk_basepal++; + } + + //GL_Init(); + PM_Init(&g_clmove); + CL_InitEventSystem(); + ClientDLL_Init(); + //VGui_Startup(); + if (!VID_Init(host_basepal)) + { + //VGui_Shutdown(); + return 0; + } + Draw_Init(); + SCR_Init(); + R_Init(); + S_Init(); + //CDAudio_Init(); + //Voice_Init("voice_speex", 1); + //DemoPlayer_Init(); + CL_Init(); + } + else + { + Cvar_RegisterVariable(&suitvolume); + } + Cbuf_InsertText("exec valve.rc\n"); + Hunk_AllocName(0, "-HOST_HUNKLEVEL-"); + host_hunklevel = Hunk_LowMark(); + giActive = DLL_ACTIVE; + scr_skipupdate = FALSE; + CheckGore(); + host_initialized = TRUE; + return 1; +} + +/* <368c2> ../engine/host.c:1977 */ +void Host_Shutdown(void) +{ + static qboolean isdown = FALSE; + + int i; + client_t *pclient; + + if (isdown) + { + printf("recursive shutdown\n"); + return; + } + + isdown = TRUE; + if (host_initialized) // Client-side + Host_WriteConfiguration(); + + SV_ServerShutdown(); + Voice_Deinit(); + host_initialized = FALSE; + + //CDAudio_Shutdown(); + //VGui_Shutdown(); + if (g_pcls.state != ca_dedicated) + ClientDLL_Shutdown(); + + Cmd_RemoveGameCmds(); + Cmd_Shutdown(); + Cvar_Shutdown(); + HPAK_FlushHostQueue(); + SV_DeallocateDynamicData(); + + pclient = g_psvs.clients; + for (i = 0; i < g_psvs.maxclientslimit; i++, pclient++) + SV_ClearFrames(&pclient->frames); + + SV_Shutdown(); + //SystemWrapper_ShutDown(); + NET_Shutdown(); + S_Shutdown(); + Con_Shutdown(); + ReleaseEntityDlls(); + CL_ShutDownClientStatic(); + CM_FreePAS(); + + if (wadpath) + { + Mem_Free(wadpath); + wadpath = NULL; + } + + if (g_pcls.state != ca_dedicated) + Draw_Shutdown(); + + Draw_DecalShutdown(); + W_Shutdown(); + Log_Printf("Server shutdown\n"); + Log_Close(); + COM_Shutdown(); + CL_Shutdown(); + DELTA_Shutdown(); + //Key_Shutdown(); + realtime = 0.0f; + g_psv.time = 0.0f; + g_pcl.time = 0.0f; +} diff --git a/rehlds/engine/host.h b/rehlds/engine/host.h new file mode 100644 index 0000000..f6232b6 --- /dev/null +++ b/rehlds/engine/host.h @@ -0,0 +1,162 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef HOST_H +#define HOST_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "filesystem_internal.h" +#include "sys_dll.h" +#include "server.h" +#include "rehlds_api.h" + + +#define MAX_COMMAND_LINE_PARAMS 50 + +/* <271d2> ../engine/host.h:19 */ +typedef struct quakeparms_s +{ + char *basedir; + char *cachedir; + int argc; + char **argv; + void *membase; + int memsize; +} quakeparms_t; + +#ifdef HOOK_ENGINE +#define host_name (*phost_name) +#define host_speeds (*phost_speeds) +#define host_profile (*phost_profile) +#define developer (*pdeveloper) +#define host_limitlocal (*phost_limitlocal) +#define skill (*pskill) +#define deathmatch (*pdeathmatch) +#define coop (*pcoop) +#define sys_ticrate (*psys_ticrate) +#define sys_timescale (*psys_timescale) +#define fps_max (*pfps_max) +#define host_killtime (*phost_killtime) +#define sv_stats (*psv_stats) +#define fps_override (*pfps_override) +#define host_framerate (*phost_framerate) +#define pausable (*ppausable) + +#define suitvolume (*psuitvolume) + +#define realtime (*prealtime) +#define rolling_fps (*prolling_fps) +#define host_parms (*phost_parms) +#define host_initialized (*phost_initialized) +#define host_frametime (*phost_frametime) + +#define host_framecount (*phost_framecount) + +#define host_client (*phost_client) +#define gfNoMasterServer (*pgfNoMasterServer) +#define oldrealtime (*poldrealtime) +#define host_hunklevel (*phost_hunklevel) +#define host_abortserver (*phost_abortserver) +#define host_enddemo (*phost_enddemo) +#define host_basepal (*phost_basepal) +#endif // HOOK_ENGINE + +extern cvar_t host_name; +extern cvar_t host_speeds; +extern cvar_t host_profile; +extern cvar_t developer; +extern cvar_t host_limitlocal; +extern cvar_t skill; +extern cvar_t deathmatch; +extern cvar_t coop; +extern cvar_t sys_ticrate; +extern cvar_t sys_timescale; +extern cvar_t fps_max; +extern cvar_t host_killtime; +extern cvar_t sv_stats; +extern cvar_t fps_override; +extern cvar_t host_framerate; +extern cvar_t pausable; + +extern cvar_t suitvolume; + +extern double realtime; +extern double rolling_fps; +extern quakeparms_t host_parms; +extern qboolean host_initialized; +extern double host_frametime; + +extern int host_framecount; + +extern client_t *host_client; +extern qboolean gfNoMasterServer; +extern double oldrealtime; +extern int host_hunklevel; +extern jmp_buf host_abortserver; +extern jmp_buf host_enddemo; +extern unsigned short *host_basepal; + + +NOXREF void Host_EndGame(const char *message, ...); +void __declspec(noreturn) Host_Error(const char *error, ...); +void Host_InitLocal(void); +NOBODY void Info_WriteVars(FileHandle_t fp); +void Host_WriteConfiguration(void); +void Host_WriteCustomConfig(void); +void SV_ClientPrintf(const char *fmt, ...); +void SV_BroadcastPrintf(const char *fmt, ...); +void Host_ClientCommands(const char *fmt, ...); +void SV_DropClient_api(IGameClient* cl, bool crash, const char* fmt, ...); +void SV_DropClient(client_t *cl, qboolean crash, const char *fmt, ...); +void Host_ClearClients(qboolean bFramesOnly); +void Host_ShutdownServer(qboolean crash); +void SV_ClearClientStates(void); +void Host_CheckDyanmicStructures(void); +void Host_ClearMemory(qboolean bQuiet); +qboolean Host_FilterTime(float time); +qboolean Master_IsLanGame(void); +void Master_Heartbeat_f(void); +void Host_ComputeFPS(double frametime); +void Host_GetHostInfo(float *fps, int *nActive, int *unused, int *nMaxPlayers, char *pszMap); +void Host_Speeds(double *time); +void Host_UpdateScreen(void); +void Host_UpdateSounds(void); +void Host_CheckConnectionFailure(void); +void _Host_Frame(float time); +int Host_Frame(float time, int iState, int *stateInfo); +void CheckGore(void); +qboolean Host_IsSinglePlayerGame(void); +qboolean Host_IsServerActive(void); +void Host_Version(void); +int Host_Init(quakeparms_t *parms); +void Host_Shutdown(void); + +#endif // HOST_H diff --git a/rehlds/engine/host_cmd.cpp b/rehlds/engine/host_cmd.cpp new file mode 100644 index 0000000..db6634d --- /dev/null +++ b/rehlds/engine/host_cmd.cpp @@ -0,0 +1,3116 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#define FILETIME_TO_QWORD(ft) \ + ((((uint64_t)ft.dwHighDateTime) << 32) + ft.dwLowDateTime) + +#define FILETIME_TO_PAIR(f,h)\ + (((uint64_t)f << 32) | h) + +/* <3d3ff> ../engine/host_cmd.c:4378 */ +typedef int(*SV_BLENDING_INTERFACE_FUNC)(int, struct sv_blending_interface_s **, struct server_studio_api_s *, float *, float *); + +vec3_t r_origin; +double cpuPercent; +int32 startTime; +int current_skill; +CareerStateType g_careerState; +int gHostSpawnCount; + +//qboolean noclip_anglehack; +qboolean g_bMajorMapChange; + +int g_iQuitCommandIssued; +char *g_pPostRestartCmdLineArgs; + + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +int r_dointerp = 1; + +SV_SAVEGAMECOMMENT_FUNC g_pSaveGameCommentFunc = &Host_SavegameComment; + +cvar_t voice_recordtofile = { "voice_recordtofile", "0", 0, 0.0f, NULL }; +cvar_t voice_inputfromfile = { "voice_inputfromfile", "0", 0, 0.0f, NULL }; +cvar_t gHostMap = { "HostMap", "C1A0", 0, 0.0f, NULL }; + +TITLECOMMENT gTitleComments[] = +{ + { "T0A0", "#T0A0TITLE" }, + { "C0A0", "#C0A0TITLE" }, + { "C1A0", "#C0A1TITLE" }, + { "C1A1", "#C1A1TITLE" }, + { "C1A2", "#C1A2TITLE" }, + { "C1A3", "#C1A3TITLE" }, + { "C1A4", "#C1A4TITLE" }, + { "C2A1", "#C2A1TITLE" }, + { "C2A2", "#C2A2TITLE" }, + { "C2A3", "#C2A3TITLE" }, + { "C2A4D", "#C2A4TITLE2" }, + { "C2A4E", "#C2A4TITLE2" }, + { "C2A4F", "#C2A4TITLE2" }, + { "C2A4G", "#C2A4TITLE2" }, + { "C2A4", "#C2A4TITLE1" }, + { "C2A5", "#C2A5TITLE" }, + { "C3A1", "#C3A1TITLE" }, + { "C3A2", "#C3A2TITLE" }, + { "C4A1A", "#C4A1ATITLE" }, + { "C4A1B", "#C4A1ATITLE" }, + { "C4A1C", "#C4A1ATITLE" }, + { "C4A1D", "#C4A1ATITLE" }, + { "C4A1E", "#C4A1ATITLE" }, + { "C4A1", "#C4A1TITLE" }, + { "C4A2", "#C4A2TITLE" }, + { "C4A3", "#C4A3TITLE" }, + { "C5A1", "#C5TITLE" }, + { "OFBOOT", "#OF_BOOT0TITLE" }, + { "OF0A", "#OF1A1TITLE" }, + { "OF1A1", "#OF1A3TITLE" }, + { "OF1A2", "#OF1A3TITLE" }, + { "OF1A3", "#OF1A3TITLE" }, + { "OF1A4", "#OF1A3TITLE" }, + { "OF1A", "#OF1A5TITLE" }, + { "OF2A1", "#OF2A1TITLE" }, + { "OF2A2", "#OF2A1TITLE" }, + { "OF2A3", "#OF2A1TITLE" }, + { "OF2A", "#OF2A4TITLE" }, + { "OF3A1", "#OF3A1TITLE" }, + { "OF3A2", "#OF3A1TITLE" }, + { "OF3A", "#OF3A3TITLE" }, + { "OF4A1", "#OF4A1TITLE" }, + { "OF4A2", "#OF4A1TITLE" }, + { "OF4A3", "#OF4A1TITLE" }, + { "OF4A", "#OF4A4TITLE" }, + { "OF5A", "#OF5A1TITLE" }, + { "OF6A1", "#OF6A1TITLE" }, + { "OF6A2", "#OF6A1TITLE" }, + { "OF6A3", "#OF6A1TITLE" }, + { "OF6A4b", "#OF6A4TITLE" }, + { "OF6A4", "#OF6A1TITLE" }, + { "OF6A5", "#OF6A4TITLE" }, + { "OF6A", "#OF6A4TITLE" }, + { "OF7A", "#OF7A0TITLE" }, + { "ba_tram", "#BA_TRAMTITLE" }, + { "ba_security", "#BA_SECURITYTITLE" }, + { "ba_main", "#BA_SECURITYTITLE" }, + { "ba_elevator", "#BA_SECURITYTITLE" }, + { "ba_canal", "#BA_CANALSTITLE" }, + { "ba_yard", "#BA_YARDTITLE" }, + { "ba_xen", "#BA_XENTITLE" }, + { "ba_hazard", "#BA_HAZARD" }, + { "ba_power", "#BA_POWERTITLE" }, + { "ba_teleport1", "#BA_YARDTITLE" }, + { "ba_teleport", "#BA_TELEPORTTITLE" }, + { "ba_outro", "#BA_OUTRO" } +}; +TYPEDESCRIPTION gGameHeaderDescription[] = +{ + DEFINE_FIELD(GAME_HEADER, mapCount, FIELD_INTEGER), + DEFINE_ARRAY(GAME_HEADER, mapName, FIELD_CHARACTER, 32), + DEFINE_ARRAY(GAME_HEADER, comment, FIELD_CHARACTER, 80), +}; +TYPEDESCRIPTION gSaveHeaderDescription[] = +{ + DEFINE_FIELD(SAVE_HEADER, skillLevel, FIELD_INTEGER), + DEFINE_FIELD(SAVE_HEADER, entityCount, FIELD_INTEGER), + DEFINE_FIELD(SAVE_HEADER, connectionCount, FIELD_INTEGER), + DEFINE_FIELD(SAVE_HEADER, lightStyleCount, FIELD_INTEGER), + DEFINE_FIELD(SAVE_HEADER, time, FIELD_TIME), + DEFINE_ARRAY(SAVE_HEADER, mapName, FIELD_CHARACTER, 32), + DEFINE_ARRAY(SAVE_HEADER, skyName, FIELD_CHARACTER, 32), + DEFINE_FIELD(SAVE_HEADER, skyColor_r, FIELD_INTEGER), + DEFINE_FIELD(SAVE_HEADER, skyColor_g, FIELD_INTEGER), + DEFINE_FIELD(SAVE_HEADER, skyColor_b, FIELD_INTEGER), + DEFINE_FIELD(SAVE_HEADER, skyVec_x, FIELD_FLOAT), + DEFINE_FIELD(SAVE_HEADER, skyVec_y, FIELD_FLOAT), + DEFINE_FIELD(SAVE_HEADER, skyVec_z, FIELD_FLOAT), +}; +TYPEDESCRIPTION gAdjacencyDescription[] = +{ + DEFINE_ARRAY(LEVELLIST, mapName, FIELD_CHARACTER, 32), + DEFINE_ARRAY(LEVELLIST, landmarkName, FIELD_CHARACTER, 32), + DEFINE_FIELD(LEVELLIST, pentLandmark, FIELD_EDICT), + DEFINE_FIELD(LEVELLIST, vecLandmarkOrigin, FIELD_VECTOR), +}; +TYPEDESCRIPTION gEntityTableDescription[] = +{ + DEFINE_FIELD(ENTITYTABLE, id, FIELD_INTEGER), + DEFINE_FIELD(ENTITYTABLE, location, FIELD_INTEGER), + DEFINE_FIELD(ENTITYTABLE, size, FIELD_INTEGER), + DEFINE_FIELD(ENTITYTABLE, flags, FIELD_INTEGER), + DEFINE_FIELD(ENTITYTABLE, classname, FIELD_STRING), +}; +TYPEDESCRIPTION gLightstyleDescription[] = +{ + DEFINE_FIELD(SAVELIGHTSTYLE, index, FIELD_INTEGER), + DEFINE_ARRAY(SAVELIGHTSTYLE, style, FIELD_CHARACTER, MAX_LIGHTSTYLES), +}; + +#else //HOOK_ENGINE + +int r_dointerp; + +SV_SAVEGAMECOMMENT_FUNC g_pSaveGameCommentFunc; + +cvar_t voice_recordtofile; +cvar_t voice_inputfromfile; +cvar_t gHostMap; + +TITLECOMMENT gTitleComments[66]; +TYPEDESCRIPTION gGameHeaderDescription[3]; +TYPEDESCRIPTION gSaveHeaderDescription[13]; +TYPEDESCRIPTION gAdjacencyDescription[4]; +TYPEDESCRIPTION gEntityTableDescription[5]; +TYPEDESCRIPTION gLightstyleDescription[2]; + +#endif //HOOK_ENGINE + + +/* <3e21d> ../engine/host_cmd.c:192 */ +void SV_GetPlayerHulls(void) +{ + int i; + //int iResult;//unused? + for (i = 0; i < 4; i++) + { + if (!gEntityInterface.pfnGetHullBounds(i, player_mins[i], player_maxs[i])) + break; + } +} +/* <3e298> ../engine/host_cmd.c:216 */ +void Host_InitializeGameDLL(void) +{ + Cbuf_Execute(); + NET_Config(g_psvs.maxclients > 1); + + if (g_psvs.dll_initialized) + { + Con_DPrintf("Sys_InitializeGameDLL called twice, skipping second call\n"); + return; + } + + g_psvs.dll_initialized = TRUE; + LoadEntityDLLs(host_parms.basedir); + gEntityInterface.pfnGameInit(); + gEntityInterface.pfnPM_Init(&g_svmove); + gEntityInterface.pfnRegisterEncoders(); + + SV_InitEncoders(); + SV_GetPlayerHulls(); + SV_CheckBlendingInterface(); + SV_CheckSaveGameCommentInterface(); + Cbuf_Execute(); +} + +/* <3d608> ../engine/host_cmd.c:271 */ +void Host_Motd_f(void) +{ + int length; + FileHandle_t pFile; + char *pFileList; + char *next; + char *now; + + pFileList = motdfile.string; + if (*pFileList == '/' || Q_strstr(pFileList, ":") || Q_strstr(pFileList, "..") || Q_strstr(pFileList, "\\")) + { + Con_Printf("Unable to open %s (contains illegal characters)\n", pFileList); + return; + } + pFile = FS_Open(pFileList, "rb"); + if (!pFile) + { + Con_Printf("Unable to open %s\n", pFileList); + return; + } + length = FS_Size(pFile); + if (length > 0) + { + now = (char *)Mem_Malloc(length + 1); + if (now) + { + FS_Read(now, length, 1, pFile); + now[length] = 0; + Con_Printf("motd:"); + next = strchr(now, '\n'); + while (next != NULL) + { + *next = 0; + Con_Printf("%s\n", now); + now = next + 1; + next = strchr(now, '\n'); + } + if (now) + Con_Printf("%s\n", now); + Mem_Free(now); + } + } + FS_Close(pFile); +} + +/* <3d5d4> ../engine/host_cmd.c:335 */ +void Host_Motd_Write_f(void) +{ + char newFile[2048]; + unsigned int i; + FileHandle_t pFile; + + if (!g_psv.active || cmd_source != src_command || g_pcls.state) + return; + + if (!IsSafeFileToDownload(motdfile.string) || !strstr(motdfile.string, ".txt")) + { + Con_Printf("Invalid motdfile name (%s)\n", motdfile.string); + return; + } + pFile = FS_Open(motdfile.string, "wb+"); + if (!pFile) + { + Con_Printf("Unable to open %s\n", motdfile.string); + return; + } + + Q_strncpy(newFile, Cmd_Args(), ARRAYSIZE(newFile)); +#ifdef REHLDS_FIXES + newFile[ARRAYSIZE(newFile) - 1] = 0; +#endif // REHLDS_FIXES + + for (i = 0; i < Q_strlen(newFile); i++) + { + if (newFile[i] == '\\' && newFile[i + 1] == 'n') + { + newFile[i] = '\n'; + Q_strncpy(&newFile[i + 1], &newFile[i + 2], min(sizeof(newFile) - 1, Q_strlen(newFile) + 1)); + newFile[sizeof(newFile) - 1] = 0; + } + } + FS_Write(newFile, Q_strlen(newFile), 1, pFile); + FS_Close(pFile); + Con_Printf("Done.\n"); +} + +/* <3e382> ../engine/host_cmd.c:395 */ +int Host_GetStartTime(void) +{ + return startTime; +} + +/* <3e39a> ../engine/host_cmd.c:405 */ +void Host_UpdateStats(void) +{ + uint32_t runticks = 0; + uint32_t cputicks = 0; + + static float last = 0.0f; + static float lastAvg = 0.0f; + + static uint64_t lastcputicks = 0; + static uint64_t lastrunticks = 0; + +#ifdef _WIN32 + + struct _FILETIME ExitTime; + struct _FILETIME UserTime; + struct _FILETIME KernelTime; + struct _FILETIME CreationTime; + struct _FILETIME SystemTimeAsFileTime; + + if (!startTime) + startTime = Sys_FloatTime(); + + if (last + 1.0 < Sys_FloatTime()) + { + GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime); + GetSystemTimeAsFileTime(&SystemTimeAsFileTime); + + //CRehldsPlatformHolder::get()->GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime); + //CRehldsPlatformHolder::get()->GetSystemTimeAsFileTime(&SystemTimeAsFileTime); + + if (!lastcputicks) + { + cputicks = CreationTime.dwLowDateTime; + runticks = CreationTime.dwHighDateTime; + + lastcputicks = FILETIME_TO_QWORD(CreationTime); + } + else + { + cputicks = (uint32_t)(lastcputicks & 0xFFFFFFFF); + runticks = (uint32_t)(lastcputicks >> 32); + } + + cpuPercent = + (FILETIME_TO_QWORD(UserTime) + FILETIME_TO_QWORD(KernelTime) - lastrunticks) + / (FILETIME_TO_QWORD(SystemTimeAsFileTime) + - (double)FILETIME_TO_PAIR(runticks, cputicks)); + + if (lastAvg + 5.0f < Sys_FloatTime()) + { + lastcputicks = FILETIME_TO_QWORD(SystemTimeAsFileTime); + lastrunticks = FILETIME_TO_QWORD(UserTime) + FILETIME_TO_QWORD(KernelTime); + lastAvg = last; + } + last = Sys_FloatTime(); + } + +#else // _WIN32 + + FILE *pFile; + int32 dummy; + int32 ctime; + int32 stime; + int32 start_time; + char statFile[4096]; + struct sysinfo infos; + + if (!startTime) + startTime = Sys_FloatTime(); + + if (Sys_FloatTime() > last + 1.0f) + { + time(NULL); + pid_t pid = getpid(); + Q_snprintf(statFile, sizeof(statFile), "/proc/%i/stat", pid); + pFile = fopen(statFile, "rt"); + if (!pFile) + { + last = Sys_FloatTime(); + return; + } + sysinfo(&infos); + fscanf(pFile, "%d %s %c %d %d %d %d %d %lu %lu \t\t\t%lu %lu %lu %ld %ld %ld %ld %ld %ld %lu \t\t\t%lu %ld %lu %lu %lu %lu %lu %lu %lu %lu \t\t\t%lu %lu %lu %lu %lu %lu", + &dummy, + statFile, + &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, + &ctime, + &stime, + &dummy, &dummy, &dummy, &dummy, &dummy, + &start_time, + &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, + &dummy, &dummy, &dummy, &dummy, &dummy,&dummy,&dummy,&dummy + ); + fclose(pFile); + + runticks = 100 * infos.uptime - start_time; + cputicks = ctime + stime; + + if (!lastcputicks) + lastcputicks = cputicks; + + if (lastrunticks) + cpuPercent = (cputicks - lastcputicks) / (runticks - lastrunticks); + else + lastrunticks = runticks; + + if (lastAvg + 5.0f < Sys_FloatTime()) + { + lastcputicks = cputicks; + lastrunticks = runticks; + lastAvg = Sys_FloatTime(); + } + if (cpuPercent > 0.999) + cpuPercent = 0.999; + if (cpuPercent < 0.1) + cpuPercent = 0.0; + last = Sys_FloatTime(); + } + +#endif // _WIN32 +} + +/* <3da03> ../engine/host_cmd.c:580 */ +void GetStatsString(char *buf, int bufSize) +{ + long double avgOut = 0.0; + long double avgIn = 0.0; + int players = 0; + + for (int i = 0; i < g_psvs.maxclients; i++) + { + host_client = &g_psvs.clients[i]; + if (!host_client->active && !host_client->connected && !host_client->spawned || host_client->fakeclient) + continue; + + players++; + avgIn = avgIn + host_client->netchan.flow[FLOW_INCOMING].avgkbytespersec; + avgOut = avgOut + host_client->netchan.flow[FLOW_OUTGOING].avgkbytespersec; + } + + Q_snprintf(buf, bufSize - 1, "%5.2f %5.2f %5.2f %7i %5i %7.2f %7i", + (float)(100.0 * cpuPercent), + (float)avgIn, + (float)avgOut, + (int)floor(Sys_FloatTime() - startTime) / 60, + g_userid - 1, + (float)(1.0 / host_frametime), + players); + buf[bufSize - 1] = 0; +} + +/* <3e059> ../engine/host_cmd.c:613 */ +void Host_Stats_f(void) +{ + char stats[512]; + GetStatsString(stats, sizeof(stats)); + Con_Printf("CPU In Out Uptime Users FPS Players\n%s\n", stats); +} + +/* <3d5c9> ../engine/host_cmd.c:626 */ +void Host_Quit_f(void) +{ + if (Cmd_Argc() == 1) + { + giActive = DLL_CLOSE; + g_iQuitCommandIssued = 1; + + if (g_pcls.state) + CL_Disconnect(); + + Host_ShutdownServer(FALSE); + Sys_Quit(); + } + else + { + giActive = DLL_PAUSED; + giStateInfo = 4; + } +} + +/* <3d5be> ../engine/host_cmd.c:651 */ +void Host_Quit_Restart_f(void) +{ + giActive = DLL_RESTART; + giStateInfo = 4; + + if (g_psv.active || (g_pcls.state == ca_active && g_pcls.trueaddress[0] && g_pPostRestartCmdLineArgs)) + { + strcat(g_pPostRestartCmdLineArgs, " +connect "); + strcat(g_pPostRestartCmdLineArgs, g_pcls.servername); + } + else + { + if (g_psvs.maxclients == 1 && g_pcls.state == ca_active) + { + if (g_pPostRestartCmdLineArgs) + { + Cbuf_AddText("save quick\n"); + Cbuf_Execute(); + + strcat(g_pPostRestartCmdLineArgs, " +load quick"); + } + } + + } +} +/* <3e511> ../engine/host_cmd.c:700 */ +void Host_Status_Printf(qboolean conprint, qboolean log, char *fmt, ...) +{ + va_list argptr; + char string[4096]; + char szfile[260]; + + va_start(argptr, fmt); + vsprintf(string, fmt, argptr); + va_end(argptr); + + if (conprint) + Con_Printf("%s", string); + + else SV_ClientPrintf("%s", string); + + if (log) + { + Q_snprintf(szfile, sizeof(szfile), "%s", "status.log"); + COM_Log(szfile, "%s", string); + } +} + +/* <3e666> ../engine/host_cmd.c:735 */ +void Host_Status_f(void) +{ + client_t *client; + int seconds; + int minutes; + int hltv_slots; + int hltv_specs; + int hltv_delay; + char *val; + int hours; + int j; + int nClients; + qboolean log = FALSE; + qboolean conprint = FALSE; + qboolean bIsSecure; + qboolean bWantsToBeSecure; + qboolean bConnectedToSteam3; + const char *pchConnectionString = ""; + const char *pchSteamUniverse = ""; + char szfile[260]; + + if (cmd_source == src_command) + { + conprint = TRUE; + + if (!g_psv.active) + { + Cmd_ForwardToServer(); + return; + } + } + + if (Cmd_Argc() == 2 && !Q_stricmp(Cmd_Argv(1), "log")) + { + log = TRUE; + Q_snprintf(szfile, sizeof(szfile), "%s", "status.log"); + _unlink(szfile); + } + + Host_Status_Printf(conprint, log, "hostname: %s\n", Cvar_VariableString("hostname")); + + bIsSecure = Steam_GSBSecure(); + bWantsToBeSecure = Steam_GSBSecurePreference(); + bConnectedToSteam3 = Steam_GSBLoggedOn(); + + if (!bIsSecure && bWantsToBeSecure) + { + pchConnectionString = "(secure mode enabled, connected to Steam3)"; + if (!bConnectedToSteam3) + { + pchConnectionString = "(secure mode enabled, disconnected from Steam3)"; + } + } + if (g_psv.active) + { + pchSteamUniverse = Steam_GetGSUniverse(); + } + + val = "insecure"; + if (bIsSecure) + val = "secure"; + + Host_Status_Printf(conprint, log, "version : %i/%s %d %s %s%s (%d)\n", PROTOCOL_VERSION, gpszVersionString, build_number(), val, pchConnectionString, pchSteamUniverse, GetGameAppID()); + if (!noip) + { + Host_Status_Printf(conprint, log, "tcp/ip : %s\n", NET_AdrToString(net_local_adr)); + } +#ifdef _WIN32 + if (!noipx) + { + Host_Status_Printf(conprint, log, "ipx : %s\n", NET_AdrToString(net_local_ipx_adr)); + } +#endif // _WIN32 + Host_Status_Printf(conprint, log, "map : %s at: %d x, %d y, %d z\n", g_psv.name, r_origin[0], r_origin[1], r_origin[2]); + SV_CountPlayers(&nClients); + Host_Status_Printf(conprint, log, "players : %i active (%i max)\n\n", nClients, g_psvs.maxclients); + Host_Status_Printf(conprint, log, "# name userid uniqueid frag time ping loss adr\n"); + + int count = 1; + client = g_psvs.clients; + for (j = 0; j < g_psvs.maxclients; j++, client++) + { + if (!client->active) + { + continue; + } + + hours = 0; + seconds = realtime - client->netchan.connect_time; + minutes = seconds / 60; + if (minutes) + { + seconds %= 60; + hours = minutes / 60; + if (hours) + minutes %= 60; + } + + if (!client->fakeclient) + val = SV_GetClientIDString(client); + else val = "BOT"; + + Host_Status_Printf(conprint, log, "#%2i %8s %i %s", count++, va("\"%s\"", client->name), client->userid, val); + if (client->proxy) + { + const char *userInfo = Info_ValueForKey(client->userinfo, "hspecs"); + if (Q_strlen(userInfo)) + hltv_specs = Q_atoi(userInfo); + + userInfo = Info_ValueForKey(client->userinfo, "hslots"); + if (Q_strlen(userInfo)) + hltv_slots = Q_atoi(userInfo); + + userInfo = Info_ValueForKey(client->userinfo, "hdelay"); + if (Q_strlen(userInfo)) + hltv_delay = Q_atoi(userInfo); + + Host_Status_Printf(conprint, log, " hltv:%u/%u delay:%u", hltv_specs, hltv_slots, hltv_delay); + } + else + Host_Status_Printf(conprint, log, " %3i", (int)client->edict->v.frags); + + if (hours) + Host_Status_Printf(conprint, log, " %2i:%02i:%02i", hours, minutes, seconds); + else Host_Status_Printf(conprint, log, " %02i:%02i", minutes, seconds); + + Host_Status_Printf(conprint, log, " %4i %3i", SV_CalcPing(client), (int)client->packet_loss); + if ((conprint || client->proxy) && client->netchan.remote_address.type == NA_IP) + { + Host_Status_Printf(conprint, log, " %s\n", NET_AdrToString(client->netchan.remote_address)); + } + else Host_Status_Printf(conprint, log, "\n"); + } + Host_Status_Printf(conprint, log, "%i users\n", nClients); +} + +/* <3e594> ../engine/host_cmd.c:923 */ +void Host_Status_Formatted_f(void) +{ + client_t *client; + int seconds; + int minutes; + int hours; + int j; + int nClients; + qboolean log = FALSE; + qboolean conprint = FALSE; + qboolean bIsSecure; + char sz[32]; + char szfile[MAX_PATH]; + char *szIDString; + + if (cmd_source == src_command) + { + conprint = TRUE; + if (!g_psv.active) + { + Cmd_ForwardToServer(); + return; + } + } + if (Cmd_Argc() == 2 && !Q_stricmp(Cmd_Argv(1), "log")) + { + Q_snprintf(szfile, sizeof(szfile), "%s", "status.log"); + _unlink(szfile); + log = TRUE; + } + + bIsSecure = Steam_GSBSecure(); + Host_Status_Printf(conprint, log, "hostname: %s\n", Cvar_VariableString("hostname")); + + char *szSecure = "insecure"; + if (bIsSecure) + szSecure = "secure"; + + Host_Status_Printf(conprint, log, "version : %i/%s %d %s\n", PROTOCOL_VERSION, gpszVersionString, build_number(), szSecure); + + if (!noip) + { + Host_Status_Printf(conprint, log, "tcp/ip : %s\n", NET_AdrToString(net_local_adr)); + } +#ifdef _WIN32 + if (!noipx) + { + Host_Status_Printf(conprint, log, "ipx : %s\n", NET_AdrToString(net_local_ipx_adr)); + } +#endif // _WIN32 + + Host_Status_Printf(conprint, log, "map : %s at: %d x, %d y, %d z\n", g_psv.name, r_origin[0], r_origin[1], r_origin[2]); + SV_CountPlayers(&nClients); + Host_Status_Printf(conprint, log, "players : %i active (%i max)\n\n", nClients, g_psvs.maxclients); + Host_Status_Printf(conprint, log, "%-2.2s\t%-9.9s\t%-7.7s\t%-20.20s\t%-4.4s\t%-8.8s\t%-4.4s\t%-4.4s\t%-21.21s\n","# ","name","userid ","uniqueid ","frag","time ","ping","loss","adr"); + + int count = 1; + char *szRemoteAddr; + client = g_psvs.clients; + for (j = 0; j < g_psvs.maxclients; j++, client++) + { + if (!client->active) + { + continue; + } + + seconds = realtime - client->netchan.connect_time; + minutes = seconds / 60; + hours = minutes / 60; + + if (minutes && hours) + Q_snprintf(sz, sizeof(sz), "%-2i:%02i:%02i", hours, minutes % 60, seconds % 60); + else + Q_snprintf(sz, sizeof(sz), "%02i:%02i", minutes, seconds % 60); + + if (conprint) + szRemoteAddr = NET_AdrToString(client->netchan.remote_address); + else szRemoteAddr = ""; + +#ifdef REHLDS_FIXES + //TODO: I think it would be better if do the formatting for fakeclient as in Host_Status_f (in the original it there is no) + if (client->fakeclient) + szIDString = "BOT"; + else +#endif // REHLDS_FIXES + szIDString = SV_GetClientIDString(client); + Host_Status_Printf(conprint, log, "%-2.2s\t%-9.9s\t%-7.7s\t%-20.20s\t%-4.4s\t%-8.8s\t%-4.4s\t%-4.4s\t%-21.21s\n", + va("%-2i", count++),va("\"%s\"", client->name),va("%-7i", client->userid),szIDString, + va("%-4i", (int)client->edict->v.frags),sz,va("%-4i", SV_CalcPing(client)),va("%-4i", (int)client->packet_loss),szRemoteAddr); + } + Host_Status_Printf(conprint, log, "%i users\n", nClients); +} + +/* <3dc0c> ../engine/host_cmd.c:1219 */ +void Host_Ping_f(void) +{ + int i; + client_t *client; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + return; + } + SV_ClientPrintf("Client ping times:\n"); + + client = g_psvs.clients; + for (i = 0; i < g_psvs.maxclients; i++, client++) + { + if (client->active) + SV_ClientPrintf("%4i %s\n", SV_CalcPing(client), client->name); + } +} + +/* <3fc89> ../engine/host_cmd.c:1249 */ +void Host_Map(qboolean bIsDemo, char *mapstring, char *mapName, qboolean loadGame) +{ + int i; + UserMsg *pMsg; + Host_ShutdownServer(FALSE); + key_dest = key_game; + SCR_BeginLoadingPlaque(FALSE); + if (!loadGame) + { + Host_ClearGameState(); + SV_InactivateClients(); + g_psvs.serverflags = 0; + } + Q_strncpy(g_pcls.mapstring, mapstring, sizeof(g_pcls.mapstring) - 1); + g_pcls.mapstring[sizeof(g_pcls.mapstring) - 1] = 0; + if (SV_SpawnServer(bIsDemo, mapName, NULL)) + { + ContinueLoadingProgressBar("Server", 7, 0.0); + if (loadGame) + { + if (!LoadGamestate(mapName, 1)) + SV_LoadEntities(); + g_psv.paused = TRUE; + g_psv.loadgame = TRUE; + SV_ActivateServer(0); + } + else + { + SV_LoadEntities(); + SV_ActivateServer(1); + if (!g_psv.active) + return; + + if (g_pcls.state != ca_dedicated) + { + Q_strcpy(g_pcls.spawnparms, ""); + for (i = 0; i < Cmd_Argc(); i++) + strncat(g_pcls.spawnparms, Cmd_Argv(i), sizeof(g_pcls.spawnparms) - strlen(g_pcls.spawnparms) - 1); + } + } + if (sv_gpNewUserMsgs) + { + pMsg = sv_gpUserMsgs; + if (pMsg) + { + while (pMsg->next) + pMsg = pMsg->next; + pMsg->next = sv_gpNewUserMsgs; + } + else + sv_gpUserMsgs = sv_gpNewUserMsgs; + + sv_gpNewUserMsgs = NULL; + } + if (g_pcls.state) + Cmd_ExecuteString("connect local", src_command); + } +} + +/* <3ff7f> ../engine/host_cmd.c:1339 */ +void Host_Map_f(void) +{ + int i; + char mapstring[64]; + char name[64]; + CareerStateType careerState = g_careerState; + if (cmd_source != src_command) + { + g_careerState = CAREER_NONE; + return; + } + if (Cmd_Argc() > 1 && Q_strlen(Cmd_Args()) > 54) + { + g_careerState = CAREER_NONE; + Con_Printf("map change failed: command string is too long.\n"); + return; + } + if (Cmd_Argc() < 2) + { + g_careerState = CAREER_NONE; + Con_Printf("map : changes server to specified map\n"); + return; + } + + CL_Disconnect(); + //TODO: what it? why is this? + if (careerState == CAREER_LOADING) + g_careerState = CAREER_LOADING; + + if (COM_CheckParm("-steam") && PF_IsDedicatedServer()) + g_bMajorMapChange = TRUE; + + FS_LogLevelLoadStarted("Map_Common"); + mapstring[0] = 0; + for (i = 0; i < Cmd_Argc(); i++) + { + strncat(mapstring, Cmd_Argv(i), 62 - Q_strlen(mapstring)); + strncat(mapstring, " ", 62 - Q_strlen(mapstring)); + } + Q_strcat(mapstring, "\n"); + Q_strncpy(name, Cmd_Argv(1), sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + + if (!g_psvs.dll_initialized) + Host_InitializeGameDLL(); + + int iLen = Q_strlen(name); + if (iLen > 4 && !Q_stricmp(&name[iLen - 4], ".bsp")) + name[iLen - 4] = 0; + + FS_LogLevelLoadStarted(name); + VGuiWrap2_LoadingStarted("level", name); + SCR_UpdateScreen(); + SCR_UpdateScreen(); + + if (!PF_IsMapValid_I(name)) + { + Con_Printf("map change failed: '%s' not found on server.\n", name); + if (COM_CheckParm("-steam")) + { + if (PF_IsDedicatedServer()) + { + g_bMajorMapChange = FALSE; + Sys_Printf("\n"); + } + } + return; + } + + StartLoadingProgressBar("Server", 24); + SetLoadingProgressBarStatusText("#GameUI_StartingServer"); + ContinueLoadingProgressBar("Server", 1, 0.0); + Cvar_Set("HostMap", name); + Host_Map(FALSE, mapstring, name, FALSE); + if (COM_CheckParm("-steam") && PF_IsDedicatedServer()) + { + g_bMajorMapChange = FALSE; + Sys_Printf("\n"); + } + ContinueLoadingProgressBar("Server", 11, 0.0); + NotifyDedicatedServerUI("UpdateMap"); + + if (g_careerState == CAREER_LOADING) + { + g_careerState = CAREER_PLAYING; + SetCareerAudioState(1); + } + else + SetCareerAudioState(0); +} + +/* <4004e> ../engine/host_cmd.c:1475 */ +void Host_Career_f(void) +{ + if (cmd_source == src_command) + { + g_careerState = CAREER_LOADING; + Host_Map_f(); + } +} + +/* <3d5a2> ../engine/host_cmd.c:1493 */ +void Host_Maps_f(void) +{ + char *pszSubString; + if (Cmd_Argc() != 2) + { + Con_Printf("Usage: maps \nmaps * for full listing\n"); + return; + } + pszSubString = (char *)Cmd_Argv(1); + if (pszSubString && *pszSubString) + { + if (*pszSubString == '*') + pszSubString = NULL; + COM_ListMaps(pszSubString); + } +} + +/* <3d56e> ../engine/host_cmd.c:1521 */ +void Host_Changelevel_f(void) +{ + char _level[64]; + char _startspot[64]; + + char *level = NULL; + char *startspot = NULL; + + if (Cmd_Argc() < 2) + { + Con_Printf("changelevel : continue game on a new level\n"); + return; + } + if (!g_psv.active || g_pcls.demoplayback) + { + Con_Printf("Only the server may changelevel\n"); + return; + } + level = (char *)Cmd_Argv(1); + if (!PF_IsMapValid_I(level)) + { + Con_Printf("changelevel failed: '%s' not found on server.\n", level); + return; + } + + Q_strncpy(_level, level, 63); + _level[63] = 0; + + if (Cmd_Argc() != 2) + { + startspot = &_startspot[0]; + Q_strncpy(_startspot, Cmd_Argv(2), 63); + _startspot[63] = 0; + } + else + _startspot[0] = 0; + + SCR_BeginLoadingPlaque(FALSE); + S_StopAllSounds(1); + SV_InactivateClients(); + SV_ServerShutdown(); + SV_SpawnServer(FALSE, _level, startspot); + SV_LoadEntities(); + SV_ActivateServer(1); +} + +/* <3e7c9> ../engine/host_cmd.c:1581 */ +const char *Host_FindRecentSave(char *pNameBuf) +{ + const char *findfn; + char basefilename[MAX_PATH]; + int found; + int32 newest; + int32 ft; + char szPath[MAX_PATH]; + + Q_sprintf(pNameBuf, "%s*.sav", Host_SaveGameDirectory()); + Q_snprintf(szPath, sizeof(szPath), "%s", Host_SaveGameDirectory()); + + found = 0; + findfn = Sys_FindFirst(pNameBuf,basefilename); + while (findfn != NULL) + { + if (Q_strlen(findfn) && Q_stricmp(findfn, "HLSave.sav")) + { + Q_snprintf(szPath, sizeof(szPath), "%s%s", Host_SaveGameDirectory(), findfn); + ft = FS_GetFileTime(szPath); + if (ft > 0 && (!ft || newest < ft)) + { + found = 1; + newest = ft; + Q_strcpy(pNameBuf, findfn); + } + } + findfn = Sys_FindNext(basefilename); + } + Sys_FindClose(); + return found != 0 ? pNameBuf : NULL; +} + +/* <3fc40> ../engine/host_cmd.c:1637 */ +void Host_Restart_f(void) +{ + char name[MAX_PATH]; + if (g_pcls.demoplayback || !g_psv.active || cmd_source != src_command) + return; + if (g_pcls.state) + g_pcls.state = ca_disconnected; + + Host_ClearGameState(); + SV_InactivateClients(); + Q_strncpy(name, g_psv.name, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + + SV_ServerShutdown(); + SV_SpawnServer(FALSE, name, NULL); + SV_LoadEntities(); + SV_ActivateServer(1); +} + +/* <3d784> ../engine/host_cmd.c:1681 */ +void Host_Reload_f(void) +{ + const char *pSaveName; + char name[MAX_PATH]; + if (g_pcls.demoplayback || !g_psv.active || cmd_source != src_command) + return; + + Host_ClearGameState(); + SV_InactivateClients(); + SV_ServerShutdown(); + + pSaveName = Host_FindRecentSave(name); + if (!pSaveName || !Host_Load(pSaveName)) + { + SV_SpawnServer(FALSE, gHostMap.string, NULL); + SV_LoadEntities(); + SV_ActivateServer(1); + } +} + +/* <3d552> ../engine/host_cmd.c:1730 */ +void Host_Reconnect_f(void) +{ + char cmdString[128]; + if (g_pcls.state < ca_connected) + return; + + if (g_pcls.passive) + { + Q_snprintf(cmdString, sizeof(cmdString), "listen %s\n", NET_AdrToString(g_pcls.connect_stream)); + Cbuf_AddText(cmdString); + return; + } + + SCR_BeginLoadingPlaque(FALSE); + g_pcls.signon = 0; + g_pcls.state = ca_connected; + sys_timescale.value = 1.0f; + + Netchan_Clear(&g_pcls.netchan); + SZ_Clear(&g_pcls.netchan.message); + MSG_WriteChar(&g_pcls.netchan.message, clc_stringcmd); + MSG_WriteString(&g_pcls.netchan.message, "new"); +} + +/* <3e7a9> ../engine/host_cmd.c:1780 */ +char *Host_SaveGameDirectory(void) +{ + static char szDirectory[MAX_PATH]; + Q_memset(szDirectory, 0, sizeof(szDirectory)); + Q_snprintf(szDirectory, sizeof(szDirectory), "SAVE/"); + return szDirectory; +} + +/* <3dba5> ../engine/host_cmd.c:1877 */ +void Host_SavegameComment(char *pszBuffer, int iSizeBuffer) +{ + int i; + const char *pszName = NULL; + const char *pszMapName = (const char *)&pr_strings[gGlobalVariables.mapname]; + + for (i = 0; i < ARRAYSIZE(gTitleComments) && !pszName; i++) + { + if (!Q_strnicmp(pszMapName, gTitleComments[i].pBSPName, Q_strlen(gTitleComments[i].pBSPName))) + pszName = gTitleComments[i].pTitleName; + } + if (!pszName) + { + if (!pszMapName || !pszMapName[0]) + { + pszName = pszMapName; + if (!Q_strlen(g_pcl.levelname)) + pszName = g_pcl.levelname; + } + } + Q_strncpy(pszBuffer, pszName, iSizeBuffer - 1); + pszBuffer[iSizeBuffer - 1] = 0; +} + +/* <3e8e9> ../engine/host_cmd.c:1909 */ +void Host_SaveAgeList(const char *pName, int count) +{ + char newName[MAX_PATH]; + char oldName[MAX_PATH]; + + Q_snprintf(newName, sizeof(newName), "%s%s%02d.sav", Host_SaveGameDirectory(), pName, count); + COM_FixSlashes(newName); + FS_RemoveFile(newName, "GAMECONFIG"); + + while (count > 0) + { + if (count == 1) + Q_snprintf(oldName, sizeof(oldName), "%s%s.sav", Host_SaveGameDirectory(), pName); + else + Q_snprintf(oldName, sizeof(oldName), "%s%s%02d.sav", Host_SaveGameDirectory(), pName, count - 1); + + COM_FixSlashes(oldName); + Q_snprintf(newName, sizeof(newName), "%s%s%02d.sav", Host_SaveGameDirectory(), pName, count); + COM_FixSlashes(newName); + FS_Rename(oldName, newName); + count--; + } +} + +/* <3e9ba> ../engine/host_cmd.c:1938 */ +int Host_ValidSave(void) +{ + if (cmd_source != src_command) + return 0; + + if (!g_psv.active) + { + Con_Printf("Not playing a local game.\n"); + return 0; + } + if (g_psvs.maxclients != 1) + { + Con_Printf("Can't save multiplayer games.\n"); + return 0; + } + if (g_pcls.state != ca_active || g_pcls.signon != 2) + { + Con_Printf("Can't save during transition.\n"); + return 0; + } + if (g_pcl.intermission) + { + Con_Printf("Can't save in intermission.\n"); + return 0; + } + if (g_psvs.clients->active && g_psvs.clients->edict->v.health <= 0.0) + { + Con_Printf("Can't savegame with a dead player\n"); + return 0; + } + return 1; +} + +/* <3da59> ../engine/host_cmd.c:1983 */ +SAVERESTOREDATA *SaveInit(int size) +{ + int i; + edict_t *pEdict; + SAVERESTOREDATA *pSaveData; + + if (size <= 0) + size = 0x80000; + + pSaveData = (SAVERESTOREDATA *)Mem_Calloc(sizeof(SAVERESTOREDATA) + (sizeof(ENTITYTABLE) * g_psv.num_edicts) + size, sizeof(char)); + pSaveData->pTable = (ENTITYTABLE *)(pSaveData + 1); + pSaveData->tokenSize = 0; + pSaveData->tokenCount = 0xFFF; + pSaveData->pTokens = (char **)Mem_Calloc(0xFFF, sizeof(char *)); + + for (i = 0; i < g_psv.num_edicts; i++) + { + pEdict = &g_psv.edicts[i]; + + pSaveData->pTable[i].id = i; + pSaveData->pTable[i].pent = pEdict; + pSaveData->pTable[i].flags = 0; + pSaveData->pTable[i].location = 0; + pSaveData->pTable[i].size = 0; + pSaveData->pTable[i].classname = 0; + } + + pSaveData->tableCount = g_psv.num_edicts; + pSaveData->connectionCount = 0; + pSaveData->size = 0; + pSaveData->bufferSize = size; + pSaveData->fUseLandmark = 0; + + pSaveData->pBaseData = (char *)(pSaveData->pTable + g_psv.num_edicts); + pSaveData->pCurrentData = (char *)(pSaveData->pTable + g_psv.num_edicts); + + gGlobalVariables.pSaveData = pSaveData; + pSaveData->time = gGlobalVariables.time; + + pSaveData->vecLandmarkOffset[0] = vec3_origin[0]; + pSaveData->vecLandmarkOffset[1] = vec3_origin[1]; + pSaveData->vecLandmarkOffset[2] = vec3_origin[2]; + + return pSaveData; +} + +/* <3e17e> ../engine/host_cmd.c:2029 */ +void SaveExit(SAVERESTOREDATA *save) +{ + if (save->pTokens) + { + Mem_Free(save->pTokens); + save->pTokens = NULL; + save->tokenCount = 0; + } + Mem_Free(save); + gGlobalVariables.pSaveData = NULL; +} + +/* <3f65f> ../engine/host_cmd.c:2044 */ +qboolean SaveGameSlot(const char *pSaveName, const char *pSaveComment) +{ + char hlPath[256]; + char name[256]; + char *pTokenData; + int tag; + int i; + FILE *pFile; + SAVERESTOREDATA *pSaveData; + GAME_HEADER gameHeader; + + FS_CreateDirHierarchy(Host_SaveGameDirectory(), "GAMECONFIG"); + pSaveData = SaveGamestate(); + if (!pSaveData) + return FALSE; + + SaveExit(pSaveData); + pSaveData = SaveInit(0); + + Q_snprintf(hlPath, sizeof(hlPath), "%s*.HL?", Host_SaveGameDirectory()); + COM_FixSlashes(hlPath); + gameHeader.mapCount = DirectoryCount(hlPath); + Q_strncpy(gameHeader.mapName, g_psv.name, 31); + gameHeader.mapName[31] = 0; + Q_strncpy(gameHeader.comment, pSaveComment, 79); + gameHeader.comment[79] = 0; + + gEntityInterface.pfnSaveWriteFields(pSaveData, "GameHeader", &gameHeader, gGameHeaderDescription, ARRAYSIZE(gGameHeaderDescription)); + gEntityInterface.pfnSaveGlobalState(pSaveData); + + pTokenData = NULL; + for (i = 0; i < pSaveData->tokenCount; i++) + { + if (pSaveData->pTokens[i]) + { + pSaveData->size += Q_strlen(pSaveData->pTokens[i]) + 1; + if (pSaveData->size > pSaveData->bufferSize) + { + Con_Printf("Token Table Save/Restore overflow!"); + pSaveData->size = pSaveData->bufferSize; + break; + } + pTokenData = pSaveData->pCurrentData; + do + { + *pTokenData++ = *pSaveData->pTokens[i]++; + } + while (*pSaveData->pTokens[i]); + pSaveData->pCurrentData = pTokenData; + } + else + { + if (pSaveData->size + 1 > pSaveData->bufferSize) + { + Con_Printf("Token Table Save/Restore overflow!"); + pSaveData->size = pSaveData->bufferSize; + break; + } + pTokenData = pSaveData->pCurrentData; + *pTokenData = 0; + pSaveData->pCurrentData = pTokenData + 1; + } + } + pSaveData->tokenSize = (int)(pSaveData->pCurrentData - pTokenData); + + if (pSaveData->size < pSaveData->bufferSize) + pSaveData->size -= pSaveData->tokenSize; + + Q_snprintf(name, 252, "%s%s", Host_SaveGameDirectory(), pSaveName); + COM_DefaultExtension(name, ".sav"); + COM_FixSlashes(name); + Con_DPrintf("Saving game to %s...\n", name); + + if (Q_stricmp(pSaveName, "quick") || Q_stricmp(pSaveName, "autosave")) + Host_SaveAgeList(pSaveName, 1); + + pFile = FS_OpenPathID(name, "wb", "GAMECONFIG"); + tag = MAKEID('J','S','A','V'); + FS_Write(&tag, sizeof(int), 1, pFile); + tag = SAVEGAME_VERSION; + FS_Write(&tag, sizeof(int), 1, pFile); + FS_Write(&pSaveData->size, sizeof(int), 1, pFile); + FS_Write(&pSaveData->tokenCount, sizeof(int), 1, pFile); + FS_Write(&pSaveData->tokenSize, sizeof(int), 1, pFile); + FS_Write(pSaveData->pCurrentData, pSaveData->tokenSize, 1, pFile); + FS_Write(pSaveData->pBaseData, pSaveData->size, 1, pFile); + DirectoryCopy(hlPath, pFile); + FS_Close(pFile); + SaveExit(pSaveData); + + return TRUE; +} + +/* <3dadd> ../engine/host_cmd.c:2150 */ +void Host_Savegame_f(void) +{ + char szComment[80]; + char szTemp[80]; + + if (!Host_ValidSave()) + return; + + if (Cmd_Argc() != 2) + { + Con_DPrintf("save : save a game\n"); + return; + } + if (Q_strstr(Cmd_Argv(1), "..")) + { + Con_DPrintf("Relative pathnames are not allowed.\n"); + return; + } + g_pSaveGameCommentFunc(szTemp, 80); + Q_snprintf(szComment, sizeof(szComment) - 1,"%-64.64s %02d:%02d", szTemp, (int)(g_psv.time / 60.0), (int)fmod(g_psv.time, 60.0)); + SaveGameSlot(Cmd_Argv(1), szComment); + CL_HudMessage("GAMESAVED"); +} + +/* <3d704> ../engine/host_cmd.c:2185 */ +void Host_AutoSave_f(void) +{ + char szComment[80]; + char szTemp[80]; + + if (Host_ValidSave()) + { + g_pSaveGameCommentFunc(szTemp, 80); + Q_snprintf(szComment, sizeof(szComment) - 1, "%-64.64s %02d:%02d", szTemp, (int)(g_psv.time / 60.0), (int)fmod(g_psv.time, 60.0)); + szComment[sizeof(szComment) - 1] = 0; + SaveGameSlot("autosave", szComment); + } +} + +/* <3f8d1> ../engine/host_cmd.c:2203 */ +qboolean SaveGame(const char *pszSlot, const char *pszComment) +{ + qboolean qret; + qboolean q; + + q = scr_skipupdate; + scr_skipupdate = TRUE; + qret = SaveGameSlot(pszSlot, pszComment); + scr_skipupdate = q; + return qret; +} + +/* <3d658> ../engine/host_cmd.c:2217 */ +int SaveReadHeader(FileHandle_t pFile, GAME_HEADER *pHeader, int readGlobalState) +{ + int i; + int tag; + int size; + int tokenCount; + int tokenSize; + char *pszTokenList; + SAVERESTOREDATA *pSaveData; + + FS_Read(&tag, sizeof(int), 1, pFile); + if (tag != MAKEID('J','S','A','V')) + { + FS_Close(pFile); + return 0; + } + FS_Read(&tag, sizeof(int), 1, pFile); + if (tag != SAVEGAME_VERSION) + { + FS_Close(pFile); + return 0; + } + FS_Read(&size, sizeof(int), 1, pFile); + FS_Read(&tokenCount, sizeof(int), 1, pFile); + FS_Read(&tokenSize, sizeof(int), 1, pFile); + + pSaveData = (SAVERESTOREDATA *)Mem_Calloc(sizeof(SAVERESTOREDATA) + tokenSize + size, sizeof(char)); + pSaveData->tableCount = 0; + pSaveData->pTable = NULL; + pSaveData->connectionCount = 0; + + pszTokenList = (char *)(pSaveData + 1); + if (tokenSize > 0) + { + pSaveData->tokenCount = tokenCount; + pSaveData->tokenSize = tokenSize; + + FS_Read(pszTokenList, tokenSize, 1, pFile); + + if (!pSaveData->pTokens) + pSaveData->pTokens = (char **)Mem_Calloc(tokenCount, sizeof(char *)); + + for (i = 0; i < tokenCount; i++) + { + if (*pszTokenList) + pSaveData->pTokens[i] = pszTokenList; + else + pSaveData->pTokens[i] = NULL; + while (*pszTokenList++); + } + } + pSaveData->size = 0; + pSaveData->bufferSize = size; + pSaveData->fUseLandmark = 0; + pSaveData->time = 0.0f; + + pSaveData->pCurrentData = pszTokenList; + pSaveData->pBaseData = pszTokenList; + + FS_Read(pSaveData->pBaseData, size, 1, pFile); + gEntityInterface.pfnSaveReadFields(pSaveData, "GameHeader", pHeader, gGameHeaderDescription, ARRAYSIZE(gGameHeaderDescription)); + if (readGlobalState) + gEntityInterface.pfnRestoreGlobalState(pSaveData); + SaveExit(pSaveData); + return 1; +} + +/* <3ea80> ../engine/host_cmd.c:2289 */ +void SaveReadComment(FileHandle_t f, char *name) +{ + GAME_HEADER gameHeader; + if (SaveReadHeader(f, &gameHeader, 0)) + Q_strcpy(name, gameHeader.comment); +} + +/* <3d97a> ../engine/host_cmd.c:2302 */ +void Host_Loadgame_f(void) +{ + if (cmd_source != src_command) + return; + + if (Cmd_Argc() != 2) + { + Con_Printf("load : load a game\n"); + return; + } + if (!Host_Load(Cmd_Argv(1))) + Con_Printf("Error loading saved game\n"); +} + +/* <3fe89> ../engine/host_cmd.c:2323 */ +int LoadGame(const char *pName) +{ + int iRet; + qboolean q; + + q = scr_skipupdate; + scr_skipupdate = TRUE; + iRet = Host_Load(pName); + scr_skipupdate = q; + return iRet; +} + +/* <3fccf> ../engine/host_cmd.c:2334 */ +int Host_Load(const char *pName) +{ + FILE *pFile; + GAME_HEADER gameHeader; + char name[256]; + int nSlot; + + if (!pName || !pName[0]) + return 0; + + if (Q_strstr(pName, "..")) + { + Con_Printf("Relative pathnames are not allowed.\n"); + return 0; + } + + if (*pName == '_' && COM_TokenWaiting((char *)&pName[1])) + { + nSlot = Q_atoi(pName); + if (nSlot < 1 || nSlot > 12) + return 0; + + Q_snprintf(name, 252, "%sHalf-Life-%i", Host_SaveGameDirectory(), nSlot); + } + else + Q_snprintf(name, 252, "%s%s", Host_SaveGameDirectory(), pName); + name[251] = 0; + + if (!g_psvs.dll_initialized) + Host_InitializeGameDLL(); + + COM_DefaultExtension(name, ".sav"); + COM_FixSlashes(name); + name[255] = 0; + + Con_Printf("Loading game from %s...\n", name); + pFile = FS_OpenPathID(name, "rb", "GAMECONFIG"); + if (!pFile) + return 0; + Host_ClearGameState(); + if (!SaveReadHeader(pFile, &gameHeader, 1)) + { + giStateInfo = 1; + Cbuf_AddText("\ndisconnect\n"); + return 0; + } + + g_pcls.demonum = -1; + SV_InactivateClients(); + SCR_BeginLoadingPlaque(FALSE); + DirectoryExtract(pFile, gameHeader.mapCount); + FS_Close(pFile); + + Cvar_SetValue("deathmatch", 0.0); + Cvar_SetValue("coop", 0.0); + + if (!Q_stricmp(com_gamedir,"valve") + || !Q_stricmp(com_gamedir,"bshift") + || !Q_stricmp(com_gamedir,"gearbox")) + { + g_psvs.maxclients = 1; + Cvar_SetValue("maxplayers", 1.0); + } + + Q_snprintf(name, sizeof(name), "map %s\n", gameHeader.mapName); + CL_Disconnect(); + Host_Map(FALSE, name, gameHeader.mapName, TRUE); + return 1; +} + +/* <3ed7d> ../engine/host_cmd.c:2439 */ +SAVERESTOREDATA *SaveGamestate(void) +{ + char name[256]; + char *pTableData; + char *pTokenData; + FILE *pFile; + int i; + int dataSize; + int tableSize; + edict_t *pent; + SAVE_HEADER header; + SAVERESTOREDATA *pSaveData; + SAVELIGHTSTYLE light; + + if (!gEntityInterface.pfnParmsChangeLevel) + return NULL; + +#ifdef REHLDS_FIXES + Q_memset(&header, 0, sizeof(SAVE_HEADER)); +#endif // REHLDS_FIXES + + FS_CreateDirHierarchy(Host_SaveGameDirectory(), "GAMECONFIG"); + pSaveData = SaveInit(0); + Q_snprintf(name, sizeof(name), "%s%s.HL1", Host_SaveGameDirectory(), g_psv.name); + COM_FixSlashes(name); + gEntityInterface.pfnParmsChangeLevel(); + header.version = build_number(); + header.skillLevel = (int)skill.value; + header.entityCount = pSaveData->tableCount; + header.time = g_psv.time; + header.connectionCount = pSaveData->connectionCount; + Q_strncpy(header.skyName, sv_skyname.string, sizeof(header.skyName) - 1); + header.skyName[sizeof(header.skyName) - 1] = 0; + pSaveData->time = 0.0f; + + header.skyColor_r = (int)sv_skycolor_r.value; + header.skyColor_g = (int)sv_skycolor_g.value; + header.skyColor_b = (int)sv_skycolor_b.value; + header.skyVec_x = sv_skyvec_x.value; + header.skyVec_y = sv_skyvec_y.value; + header.skyVec_z = sv_skyvec_z.value; + + Q_strncpy(header.mapName, g_psv.name, sizeof(header.mapName) - 1); + header.mapName[sizeof(header.mapName) - 1] = 0; + + for (i = 0; i < MAX_LIGHTSTYLES; i++) + { + if (g_psv.lightstyles[i]) + header.lightStyleCount++; + } + gEntityInterface.pfnSaveWriteFields(pSaveData, "Save Header", &header, gSaveHeaderDescription, ARRAYSIZE(gSaveHeaderDescription)); + pSaveData->time = header.time; + + for (i = 0; i < pSaveData->connectionCount; i++) + gEntityInterface.pfnSaveWriteFields(pSaveData, "ADJACENCY", &pSaveData->levelList[i], gAdjacencyDescription, ARRAYSIZE(gAdjacencyDescription)); + + for (i = 0; i < MAX_LIGHTSTYLES; i++) + { + if (g_psv.lightstyles[i]) + { + light.index = i; + Q_strncpy(light.style, g_psv.lightstyles[i], 63); + light.style[63] = 0; + gEntityInterface.pfnSaveWriteFields(pSaveData, "LIGHTSTYLE", &light, gLightstyleDescription, ARRAYSIZE(gLightstyleDescription)); + } + } + + dataSize = pSaveData->size; + pTableData = pSaveData->pCurrentData; + tableSize = 0; + + for (i = 0; i < g_psv.num_edicts; i++) + { + pent = &g_psv.edicts[i]; + pSaveData->currentIndex = i; + pSaveData->pTable[i].location = pSaveData->size; + if (!pent->free) + { + gEntityInterface.pfnSave(pent, pSaveData); + if (SV_IsPlayerIndex(i)) + pSaveData->pTable[i].flags |= FENTTABLE_PLAYER; + } + } + for (i = 0; i < g_psv.num_edicts; i++) + gEntityInterface.pfnSaveWriteFields(pSaveData, "ETABLE", &pSaveData->pTable[i], gEntityTableDescription, ARRAYSIZE(gEntityTableDescription)); + + pTokenData = NULL; + for (i = 0; i < pSaveData->tokenCount; i++) + { + if (pSaveData->pTokens[i]) + { + pTokenData = pSaveData->pCurrentData; + do + { + *pTokenData++ = *pSaveData->pTokens[i]++; + } + while (*pSaveData->pTokens[i]); + pSaveData->pCurrentData = pTokenData; + } + else + { + pTokenData = pSaveData->pCurrentData; + *pTokenData = 0; + pSaveData->pCurrentData = pTokenData + 1; + } + } + pSaveData->tokenSize = (int)(pSaveData->pCurrentData - pTokenData); + + COM_CreatePath(name); + pFile = FS_OpenPathID(name, "wb", "GAMECONFIG"); + if (!pFile) + { + Con_Printf("Unable to open save game file %s.", name); + return NULL; + } + + i = SAVEFILE_HEADER; + FS_Write(&i, sizeof(int), 1, pFile); + i = SAVEGAME_VERSION; + FS_Write(&i, sizeof(int), 1, pFile); + FS_Write(&pSaveData->size, sizeof(int), 1, pFile); + FS_Write(&pSaveData->tableCount, sizeof(int), 1, pFile); + FS_Write(&pSaveData->tokenCount, sizeof(int), 1, pFile); + FS_Write(&pSaveData->tokenSize, sizeof(int), 1, pFile); + FS_Write(pSaveData->pCurrentData, pSaveData->tokenSize, 1, pFile); + FS_Write(pTableData, tableSize, 1, pFile); + FS_Write(pSaveData->pBaseData, dataSize, 1, pFile); + FS_Close(pFile); + EntityPatchWrite(pSaveData, g_psv.name); + + Q_snprintf(name, sizeof(name), "%s%s.HL2", Host_SaveGameDirectory(), g_psv.name); + COM_FixSlashes(name); + CL_Save(name); + + return pSaveData; +} + +/* <3d6e8> ../engine/host_cmd.c:2592 */ +void CL_Save(const char *name) +{ +} + +/* <3eb39> ../engine/host_cmd.c:2623 */ +void EntityInit(edict_t *pEdict, int className) +{ + ENTITYINIT pEntityInit; + if (!className) + Sys_Error("Bad class!!\n"); + + ReleaseEntityDLLFields(pEdict); + InitEntityDLLFields(pEdict); + pEdict->v.classname = className; + pEntityInit = GetEntityInit(&pr_strings[className]); + if (pEntityInit) + pEntityInit(&pEdict->v); +} + +/* <3eb9c> ../engine/host_cmd.c:2640 */ +SAVERESTOREDATA *LoadSaveData(const char *level) +{ + char name[MAX_PATH]; + char *pszTokenList; + FILE *pFile; + int i; + int size; + int tokenCount; + int tokenSize; + int tableCount; + SAVERESTOREDATA *pSaveData; + + Q_snprintf(name, sizeof(name), "%s%s.HL1", Host_SaveGameDirectory(), level); + COM_FixSlashes(name); + Con_Printf("Loading game from %s...\n", name); + pFile = FS_OpenPathID(name, "rb", "GAMECONFIG"); + if (!pFile) + { + Con_Printf("ERROR: couldn't open.\n"); + return NULL; + } + FS_Read(&i, sizeof(int), 1, pFile); + if (i != SAVEFILE_HEADER) + { + FS_Close(pFile); + return NULL; + } + FS_Read(&i, sizeof(int), 1, pFile); + if (i != SAVEGAME_VERSION) + { + FS_Close(pFile); + return NULL; + } + + FS_Read(&size, sizeof(int), 1, pFile); + FS_Read(&tableCount, sizeof(int), 1, pFile); + FS_Read(&tokenCount, sizeof(int), 1, pFile); + FS_Read(&tokenSize, sizeof(int), 1, pFile); + + pSaveData = (SAVERESTOREDATA *)Mem_Calloc(size + tokenSize + sizeof(ENTITYTABLE) * tableCount + sizeof(SAVERESTOREDATA), 1u); + pSaveData->tableCount = tableCount; + pSaveData->tokenCount = tokenCount; + pSaveData->tokenSize = tokenSize; + Q_strncpy(pSaveData->szCurrentMapName, level, sizeof(pSaveData->szCurrentMapName) - 1); + pSaveData->szCurrentMapName[sizeof(pSaveData->szCurrentMapName) - 1] = 0; + + pszTokenList = (char *)(pSaveData + 1); + if (tokenSize > 0) + { + FS_Read(pszTokenList, tokenSize, 1, pFile); + if (!pSaveData->pTokens) + { + pSaveData->pTokens = (char **)Mem_Calloc(tokenCount, sizeof(char *)); + } + for (i = 0; i < tokenCount; i++) + { + if (*pszTokenList) + pSaveData->pTokens[i] = pszTokenList; + else + pSaveData->pTokens[i] = NULL; + while (*pszTokenList++); + } + } + + pSaveData->pTable = (ENTITYTABLE *)pszTokenList; + pSaveData->connectionCount = 0; + pSaveData->size = 0; + + pSaveData->pBaseData = pszTokenList; + pSaveData->pCurrentData = pszTokenList; + + pSaveData->fUseLandmark = 1; + pSaveData->bufferSize = size; + pSaveData->time = 0.0f; + pSaveData->vecLandmarkOffset[0] = 0.0f; + pSaveData->vecLandmarkOffset[1] = 0.0f; + pSaveData->vecLandmarkOffset[2] = 0.0f; + gGlobalVariables.pSaveData = pSaveData; + + FS_Read(pSaveData->pBaseData, size, 1, pFile); + FS_Close(pFile); + + return pSaveData; +} + +/* <3ec7a> ../engine/host_cmd.c:2724 */ +void ParseSaveTables(SAVERESTOREDATA *pSaveData, SAVE_HEADER *pHeader, int updateGlobals) +{ + int i; + SAVELIGHTSTYLE light; + for (i = 0; i < pSaveData->tableCount; i++) + { + gEntityInterface.pfnSaveReadFields(pSaveData, "ETABLE", &(pSaveData->pTable[i]), gEntityTableDescription, ARRAYSIZE(gEntityTableDescription)); + pSaveData->pTable[i].pent = NULL; + } + + pSaveData->size = 0; + pSaveData->pBaseData = pSaveData->pCurrentData; + gEntityInterface.pfnSaveReadFields(pSaveData, "Save Header", pHeader, gSaveHeaderDescription, ARRAYSIZE(gSaveHeaderDescription)); + pSaveData->connectionCount = pHeader->connectionCount; + pSaveData->fUseLandmark = 1; + pSaveData->time = pHeader->time; + pSaveData->vecLandmarkOffset[0] = 0; + pSaveData->vecLandmarkOffset[1] = 0; + pSaveData->vecLandmarkOffset[2] = 0; + + for (i = 0; i < pSaveData->connectionCount; i++) + { + gEntityInterface.pfnSaveReadFields(pSaveData, "ADJACENCY", &(pSaveData->levelList[i]), gAdjacencyDescription, ARRAYSIZE(gAdjacencyDescription)); + } + for (i = 0; i < pHeader->lightStyleCount; i++) + { + gEntityInterface.pfnSaveReadFields(pSaveData, "LIGHTSTYLE", &light, gLightstyleDescription, ARRAYSIZE(gLightstyleDescription)); + if (updateGlobals) + { + g_psv.lightstyles[light.index] = (char *)Hunk_Alloc(Q_strlen(light.style) + 1); + Q_strncpy(g_psv.lightstyles[light.index], light.style, 3); + g_psv.lightstyles[light.index][3] = 0; + } + } +} + +/* <3ece6> ../engine/host_cmd.c:2770 */ +void EntityPatchWrite(SAVERESTOREDATA *pSaveData, const char *level) +{ + char name[MAX_PATH]; + FILE *pFile; + int i; + int size = 0; + + Q_snprintf(name, sizeof(name), "%s%s.HL3", Host_SaveGameDirectory(), level); + COM_FixSlashes(name); + pFile = FS_OpenPathID(name, "wb", "GAMECONFIG"); + if (!pFile) + return; + + for (i = 0; i < pSaveData->tableCount; i++) + { + if (pSaveData->pTable[i].flags & FENTTABLE_REMOVED) + size++; + } + FS_Write(&size, sizeof(int), 1, pFile); + for (i = 0; i < pSaveData->tableCount; i++) + { + if (pSaveData->pTable[i].flags & FENTTABLE_REMOVED) + FS_Write(&i, sizeof(int), 1, pFile); + } + FS_Close(pFile); +} + +/* <3eed5> ../engine/host_cmd.c:2802 */ +void EntityPatchRead(SAVERESTOREDATA *pSaveData, const char *level) +{ + char name[MAX_PATH]; + FILE *pFile; + int i; + int size; + int entityId; + + Q_snprintf(name, sizeof(name), "%s%s.HL3", Host_SaveGameDirectory(), level); + COM_FixSlashes(name); + pFile = FS_OpenPathID(name, "rb", "GAMECONFIG"); + if (!pFile) + return; + + FS_Read(&size, 4, 1, pFile); + for (i = 0; i < size; i++) + { + FS_Read(&entityId, 4, 1, pFile); + pSaveData->pTable[entityId].flags = FENTTABLE_REMOVED; + } +} + +/* <3ef7c> ../engine/host_cmd.c:2826 */ +int LoadGamestate(char *level, int createPlayers) +{ + int i; + edict_t *pent; + SAVE_HEADER header; + SAVERESTOREDATA *pSaveData; + ENTITYTABLE *pEntInfo; + + pSaveData = LoadSaveData(level); + if (!pSaveData) + return 0; + + ParseSaveTables(pSaveData, &header, 1); + EntityPatchRead(pSaveData, level); + + Q_strncpy(g_psv.name, header.mapName, sizeof(g_psv.name) - 1); + g_psv.name[sizeof(g_psv.name) - 1] = 0; + + Cvar_Set("sv_skyname", header.skyName); + Cvar_SetValue("skill", header.skillLevel); + Cvar_SetValue("sv_skycolor_r", header.skyColor_r); + Cvar_SetValue("sv_skycolor_g", header.skyColor_g); + Cvar_SetValue("sv_skycolor_b", header.skyColor_b); + Cvar_SetValue("sv_skyvec_x", header.skyVec_x); + Cvar_SetValue("sv_skyvec_y", header.skyVec_y); + Cvar_SetValue("sv_skyvec_z", header.skyVec_z); + + for (i = 0; i < pSaveData->tableCount; i++) + { + pent = NULL; + pEntInfo = &pSaveData->pTable[i]; + if (pEntInfo->classname && pEntInfo->size && !(pEntInfo->flags & FENTTABLE_REMOVED)) + { + if (pEntInfo->id) + { + if (pEntInfo->id > g_psvs.maxclients) + pEntInfo->pent = CreateNamedEntity(pEntInfo->classname); + else + { + if (!(pEntInfo->flags & FENTTABLE_PLAYER)) + Sys_Error("ENTITY IS NOT A PLAYER: %d\n", i); + + pent = g_psvs.clients[pEntInfo->id - 1].edict; + if (createPlayers && pent) + EntityInit(pent, pEntInfo->classname); + else + pent = NULL; + } + } + else + { + pent = g_psv.edicts; + EntityInit(pent, pEntInfo->classname); + } + } + pEntInfo->pent = pent; + } + for (i = 0; i < pSaveData->tableCount; i++) + { + pEntInfo = &pSaveData->pTable[i]; + pent = pEntInfo->pent; + + pSaveData->size = pEntInfo->location; + pSaveData->pCurrentData = &pSaveData->pBaseData[pEntInfo->location]; + + if (pent) + { + if (gEntityInterface.pfnRestore(pent, pSaveData, 0) < 0) + { + ED_Free(pent); + pEntInfo->pent = NULL; + } + else + SV_LinkEdict(pent, FALSE); + } + } + SaveExit(pSaveData); + g_psv.time = header.time; + return 1; +} + +/* <3da9b> ../engine/host_cmd.c:2911 */ +int EntryInTable(SAVERESTOREDATA *pSaveData, const char *pMapName, int index) +{ + int i; + for (i = index + 1; i < pSaveData->connectionCount; i++) + { + if ( !Q_strcmp(pSaveData->levelList[i].mapName, pMapName)) + return i; + } + return -1; +} + +/* <3f117> ../engine/host_cmd.c:2926 */ +void LandmarkOrigin(SAVERESTOREDATA *pSaveData, vec_t *output, const char *pLandmarkName) +{ + int i; + for (i = 0; i < pSaveData->connectionCount; i++) + { + if (!Q_strcmp(pSaveData->levelList[i].landmarkName, pLandmarkName)) + { + output[0] = pSaveData->levelList[i].vecLandmarkOrigin[0]; + output[1] = pSaveData->levelList[i].vecLandmarkOrigin[1]; + output[2] = pSaveData->levelList[i].vecLandmarkOrigin[2]; + return; + } + } + output[0] = 0.0f; + output[1] = 0.0f; + output[2] = 0.0f; +} + +/* <3f18c> ../engine/host_cmd.c:2945 */ +int EntityInSolid(edict_t *pent) +{ + vec3_t point; + if (pent->v.movetype == MOVETYPE_FOLLOW) + { + edict_t *pAimEnt = pent->v.aiment; + if (pAimEnt && pAimEnt->v.flags & FL_CLIENT) + return 0; + } + g_groupmask = pent->v.groupinfo; + point[0] = (pent->v.absmin[0] + pent->v.absmax[0]) * 0.5f; + point[1] = (pent->v.absmin[1] + pent->v.absmax[1]) * 0.5f; + point[2] = (pent->v.absmin[2] + pent->v.absmax[2]) * 0.5f; + return (SV_PointContents(point) == CONTENTS_SOLID); +} + +/* <3f1de> ../engine/host_cmd.c:2965 */ +int CreateEntityList(SAVERESTOREDATA *pSaveData, int levelMask) +{ + int i; + int movedCount = 0; + int active; + edict_t *pent; + ENTITYTABLE *pEntInfo; + + if (pSaveData->tableCount < 1) + return 0; + + for (i = 0; i < pSaveData->tableCount; i++) + { + pent = NULL; + pEntInfo = &pSaveData->pTable[i]; + if (pEntInfo->classname && pEntInfo->size && pEntInfo->id) + { + active = !!(pEntInfo->flags & levelMask); + if (SV_IsPlayerIndex(pEntInfo->id)) + { + client_t *cl = &g_psvs.clients[pEntInfo->id - 1]; + if (active && cl) + { + pent = cl->edict; + if (pent && !pent->free) + { + if (!(pEntInfo->flags & FENTTABLE_PLAYER)) + Sys_Error("ENTITY IS NOT A PLAYER: %d\n", i); + + if (cl->active) + EntityInit(pent, pEntInfo->classname); + } + } + } + else if (active) + pent = CreateNamedEntity(pEntInfo->classname); + } + pEntInfo->pent = pent; + } + for (i = 0; i < pSaveData->tableCount; i++) + { + pEntInfo = &pSaveData->pTable[i]; + pent = pEntInfo->pent; + pSaveData->currentIndex = i; + pSaveData->size = pEntInfo->location; + pSaveData->pCurrentData = &pSaveData->pBaseData[pEntInfo->location]; + + if (pent && (pEntInfo->flags & levelMask)) + { + if (pEntInfo->flags & FENTTABLE_GLOBAL) + { + Con_DPrintf("Merging changes for global: %s\n", &pr_strings[pEntInfo->classname]); + gEntityInterface.pfnRestore(pent, pSaveData, 1); + ED_Free(pent); + } + else + { + Con_DPrintf("Transferring %s (%d)\n", &pr_strings[pEntInfo->classname], NUM_FOR_EDICT(pent)); + if (gEntityInterface.pfnRestore(pent, pSaveData, 0) < 0) + ED_Free(pent); + else + { + SV_LinkEdict(pent, FALSE); + if (!(pEntInfo->flags & FENTTABLE_PLAYER) && EntityInSolid(pent)) + { + Con_DPrintf("Suppressing %s\n", &pr_strings[pEntInfo->classname]); + ED_Free(pent); + } + else + { + movedCount++; + pEntInfo->flags = FENTTABLE_REMOVED; + } + } + } + } + } + return movedCount; +} + +/* <3f2b7> ../engine/host_cmd.c:3047 */ +void LoadAdjacentEntities(const char *pOldLevel, const char *pLandmarkName) +{ + int i; + int test; + int flags; + int index; + int movedCount = 0; + SAVE_HEADER header; + vec3_t landmarkOrigin; + SAVERESTOREDATA *pSaveData; + SAVERESTOREDATA currentLevelData; + + Q_memset(¤tLevelData, 0, sizeof(SAVERESTOREDATA)); + gGlobalVariables.pSaveData = ¤tLevelData; + gEntityInterface.pfnParmsChangeLevel(); + + for (i = 0; i < currentLevelData.connectionCount; i++) + { + for (test = 0; test < i; test++) + { + // Only do maps once + if ( !Q_strcmp(currentLevelData.levelList[i].mapName, currentLevelData.levelList[test].mapName)) + break; + } + // Map was already in the list + if (test < i) + continue; + + pSaveData = LoadSaveData(currentLevelData.levelList[i].mapName); + if (pSaveData) + { + ParseSaveTables(pSaveData, &header, 0); + EntityPatchRead(pSaveData, currentLevelData.levelList[i].mapName); + pSaveData->time = g_psv.time; + pSaveData->fUseLandmark = 1; + flags = 0; + + LandmarkOrigin(¤tLevelData, landmarkOrigin, pLandmarkName); + LandmarkOrigin(pSaveData, pSaveData->vecLandmarkOffset, pLandmarkName); + + pSaveData->vecLandmarkOffset[0] -= landmarkOrigin[0]; + pSaveData->vecLandmarkOffset[1] -= landmarkOrigin[1]; + pSaveData->vecLandmarkOffset[2] -= landmarkOrigin[2]; + + if (!Q_strcmp(currentLevelData.levelList[i].mapName, pOldLevel)) + flags |= FENTTABLE_PLAYER; + + index = -1; + while (1) + { + index = EntryInTable(pSaveData, g_psv.name, index); + if (index < 0) + break; + + flags |= (1< ../engine/host_cmd.c:3111 */ +int FileSize(FileHandle_t pFile) +{ + if (!pFile) + return 0; + return FS_Size(pFile); +} + +/* <3f482> ../engine/host_cmd.c:3121 */ +void FileCopy(FileHandle_t pOutput, FileHandle_t pInput, int fileSize) +{ + char buf[1024]; + int size; + while (fileSize > 0) + { + if (fileSize > sizeof(buf)) + size = sizeof(buf); + else + size = fileSize; + + FS_Read(buf, size, 1, pInput); + FS_Write(buf, size, 1, pOutput); + fileSize -= size; + } +} + +/* <3f50f> ../engine/host_cmd.c:3140 */ +void DirectoryCopy(const char *pPath, FileHandle_t pFile) +{ + const char *findfn; + char basefindfn[MAX_PATH]; + int fileSize; + FILE *pCopy; + char szName[MAX_PATH]; + + findfn = Sys_FindFirst(pPath, basefindfn); + while (findfn != NULL) + { + Q_snprintf(szName, sizeof(szName), "%s%s", Host_SaveGameDirectory(), findfn); + COM_FixSlashes(szName); + pCopy = FS_OpenPathID(szName, "rb", "GAMECONFIG"); + fileSize = FS_Size(pCopy); + FS_Write(findfn, MAX_PATH, 1, pFile); + FS_Write(&fileSize, sizeof(int), 1, pFile); + FileCopy(pFile, pCopy, fileSize); + FS_Close(pCopy); + findfn = Sys_FindNext(basefindfn); + } + Sys_FindClose(); +} + +/* <3f973> ../engine/host_cmd.c:3167 */ +void DirectoryExtract(FileHandle_t pFile, int fileCount) +{ + int i; + int fileSize; + FILE *pCopy; + char szName[MAX_PATH]; + char fileName[MAX_PATH]; + + for (i = 0; i < fileCount; i++) + { + FS_Read(fileName, sizeof(fileName), 1, pFile); + FS_Read(&fileSize, sizeof(int), 1, pFile); + Q_snprintf(szName, sizeof(szName), "%s%s", Host_SaveGameDirectory(), fileName); + COM_FixSlashes(szName); + pCopy = FS_OpenPathID(szName, "wb", "GAMECONFIG"); + FileCopy(pCopy, pFile, fileCount); + FS_Close(pCopy); + } +} + +/* <3f627> ../engine/host_cmd.c:3187 */ +int DirectoryCount(const char *pPath) +{ + int count; + const char *findfn; + + count = 0; + findfn = Sys_FindFirstPathID(pPath, "GAMECONFIG"); + + while (findfn != NULL) + { + findfn = Sys_FindNext(NULL); + count++; + } + Sys_FindClose(); + return count; +} + +/* <3fa97> ../engine/host_cmd.c:3209 */ +void Host_ClearSaveDirectory(void) +{ + char szName[MAX_PATH]; + const char *pfn; + + Q_snprintf(szName, sizeof(szName), "%s", Host_SaveGameDirectory()); + strncat(szName, "*.HL?", sizeof(szName) - strlen(szName) - 1); + COM_FixSlashes(szName); + + if (Sys_FindFirstPathID(szName, "GAMECONFIG") != NULL) + { + Sys_FindClose(); + Q_snprintf(szName, sizeof(szName), "%s", Host_SaveGameDirectory()); + COM_FixSlashes(szName); + FS_CreateDirHierarchy(szName, "GAMECONFIG"); + strncat(szName, "*.HL?", sizeof(szName) - strlen(szName) - 1); + + for (pfn = Sys_FindFirstPathID(szName, "GAMECONFIG"); pfn; pfn = Sys_FindNext(NULL)) + { + Q_snprintf(szName, sizeof(szName), "%s%s", Host_SaveGameDirectory(), pfn); + FS_RemoveFile(szName, "GAMECONFIG"); + } + } + Sys_FindClose(); +} + +/* <3fbe0> ../engine/host_cmd.c:3250 */ +void Host_ClearGameState(void) +{ + S_StopAllSounds(TRUE); + Host_ClearSaveDirectory(); + if (gEntityInterface.pfnResetGlobalState) + gEntityInterface.pfnResetGlobalState(); +} + +/* <3d72c> ../engine/host_cmd.c:3262 */ +void Host_Changelevel2_f(void) +{ + char level[64]; + char oldlevel[64]; + char _startspot[64]; + char *startspot; + + SAVERESTOREDATA *pSaveData; + qboolean newUnit; + + giActive = DLL_TRANS; + + if (Cmd_Argc() < 2) + { + Con_Printf("changelevel2 : continue game on a new level in the unit\n"); + return; + } + if (!g_psv.active || g_pcls.demoplayback || g_psv.paused) + { + Con_Printf("Only the server may changelevel\n"); + return; + } + if (g_psvs.maxclients > 1) + { + Con_Printf("changelevel2 : not for use with multiplayer games\n"); + return; + } + + SCR_BeginLoadingPlaque(FALSE); + S_StopAllSounds(TRUE); + + Q_strncpy(level, Cmd_Argv(1), sizeof(level) - 1); + level[sizeof(level) - 1] = 0; + + if (Cmd_Argc() != 2) + { + startspot = &_startspot[0]; + Q_strncpy(_startspot, Cmd_Argv(2), sizeof(_startspot) - 1); + _startspot[sizeof(_startspot) - 1] = 0; + } + else + startspot = NULL; + + Q_strncpy(oldlevel, g_psv.name, sizeof(oldlevel) - 1); + oldlevel[sizeof(oldlevel) - 1] = 0; + + pSaveData = SaveGamestate(); + SV_ServerShutdown(); + FS_LogLevelLoadStarted(level); + + if (!SV_SpawnServer(FALSE, level, startspot)) + Sys_Error("Host_Changelevel2: Couldn't load map %s\n", level); + + if (pSaveData) + SaveExit(pSaveData); + + newUnit = FALSE; + if (!LoadGamestate(level, 0)) + { + newUnit = TRUE; + SV_LoadEntities(); + } + + LoadAdjacentEntities(oldlevel, startspot); + gGlobalVariables.time = g_psv.time; + + g_psv.paused = TRUE; + g_psv.loadgame = TRUE; + + if (newUnit && sv_newunit.value != 0.0f) + Host_ClearSaveDirectory(); + + SV_ActivateServer(0); +} + +/* <3db8f> ../engine/host_cmd.c:3369 */ +void Host_Version_f(void) +{ + Con_Printf("Protocol version %i\nExe version %s (%s)\n", PROTOCOL_VERSION, gpszVersionString, gpszProductString); +#ifdef REHLDS_FIXES + Con_Printf("Exe build: " __TIME__ " " __DATE__ " (%i)\n", build_number()); +#else // REHLDS_FIXES + #ifdef _WIN32 + Con_Printf("Exe build: 11:17:24 Aug 8 2013 (%i)\n", build_number()); + #else // _WIN32 + Con_Printf("Exe build: 10:03:21 Aug 8 2013 (%i)\n", build_number()); + #endif // _WIN32 +#endif // REHLDS_FIXES +} + +/* <3d516> ../engine/host_cmd.c:3382 */ +void Host_FullInfo_f(void) +{ + char key[512]; + char value[512]; + char *o; + char *s; + + if (Cmd_Argc() != 2) + { + Con_Printf("fullinfo \n"); + return; + } + + s = (char *)Cmd_Argv(1); + if (*s == '\\') + s++; + + while (*s) + { + o = key; + while (*s && *s != '\\') + *o++ = *s++; + *o = 0; + + if (!*s) + { + Con_Printf("MISSING VALUE\n"); + return; + } + + o = value; + s++; + while (*s && *s != '\\') + *o++ = *s++; + *o = 0; + if (*s) + s++; + + if (cmd_source == src_command) + { + Info_SetValueForKey(g_pcls.userinfo, key, value, MAX_INFO_STRING); + Cmd_ForwardToServer(); + return; + } + Info_SetValueForKey(host_client->userinfo, key, value, MAX_INFO_STRING); + host_client->sendinfo = TRUE; + } +} + +/* <400a6> ../engine/host_cmd.c:3433 */ +NOXREF void Host_KillVoice_f(void) +{ + Voice_Deinit(); +} + +/* <3d50b> ../engine/host_cmd.c:3447 */ +void Host_SetInfo_f(void) +{ + if (Cmd_Argc() == 1) + { + Info_Print(g_pcls.userinfo); + return; + } + if (Cmd_Argc() != 3) + { + Con_Printf("usage: setinfo [ ]\n"); + return; + } + if (cmd_source == src_command) + { + Info_SetValueForKey(g_pcls.userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING); + Cmd_ForwardToServer(); + return; + } + Info_SetValueForKey(host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING); + host_client->sendinfo = TRUE; +} + +/* <3d82c> ../engine/host_cmd.c:3471 */ +void Host_Say(qboolean teamonly) +{ + client_t *client; + client_t *save; + int j; + char *p; + char text[128]; + //qboolean fromServer;//unsued? + + if (g_pcls.state != ca_dedicated) + { + if (cmd_source != src_command) + return; + + Cmd_ForwardToServer(); + return; + } + + if (Cmd_Argc () < 2) + return; + + p = (char *)Cmd_Args(); + if (!p) + return; + + save = host_client; + if (*p == '"') + { + p++; + p[Q_strlen(p) - 1] = 0; + } + + Q_snprintf(text, sizeof(text), "%c<%s> ", 1, Cvar_VariableString("hostname")); + + if (Q_strlen(p) > 63) + p[63] = 0; + + j = sizeof(text) - 2 - Q_strlen(text); + if (Q_strlen(p) > (unsigned int)j) + p[j] = 0; + + Q_strcat(text, p); + Q_strcat(text, "\n"); + + for (j = 0, client = g_psvs.clients; j < g_psvs.maxclients; j++, client++) + { + if (!client || !client->active || !client->spawned || client->fakeclient) + continue; + + host_client = client; + + PF_MessageBegin_I(MSG_ONE, RegUserMsg("SayText", -1), NULL, &g_psv.edicts[j + 1]); + PF_WriteByte_I(0); + PF_WriteString_I(text); + PF_MessageEnd_I(); + } + + host_client = save; + Sys_Printf("%s", &text[1]); + Log_Printf("Server say \"%s\"\n", p); +} + +/* <3e127> ../engine/host_cmd.c:3541 */ +void Host_Say_f(void) +{ + Host_Say(FALSE); +} + +/* <3e0d0> ../engine/host_cmd.c:3547 */ +void Host_Say_Team_f(void) +{ + Host_Say(TRUE); +} + +/* <3d4b1> ../engine/host_cmd.c:3553 */ +void Host_Tell_f(void) +{ + client_t *client; + client_t *save; + int j; + char *p; + char text[64]; + char *tellmsg; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + return; + } + if (Cmd_Argc() < 3) + return; + + p = (char *)Cmd_Args(); + if (!p) + return; + + Q_snprintf(text, sizeof(text), "%s TELL: ", host_client->name); + + if (*p == '"') + { + p++; + p[Q_strlen(p) - 1] = 0; + } + + j = sizeof(text) - 2 - Q_strlen(text); + if (Q_strlen(p) > (unsigned int)j) + p[j] = 0; + + tellmsg = Q_strstr(p, Cmd_Argv(1)); + if (tellmsg != NULL) + Q_strcat(text, &tellmsg[Q_strlen(Cmd_Argv(1))]); + else + Q_strcat(text, p); + + Q_strcat(text, "\n"); + save = host_client; + + for (j = 0, client = g_psvs.clients; j < g_psvs.maxclients; j++, client++) + { + if (!client->active || !client->spawned || client->fakeclient) + continue; + if (Q_stricmp(client->name,Cmd_Argv(1))) + continue; + + host_client = client; + + PF_MessageBegin_I(MSG_ONE, RegUserMsg("SayText", -1), NULL, &g_psv.edicts[j + 1]); + PF_WriteByte_I(0); + PF_WriteString_I(text); + PF_MessageEnd_I(); + break; + } + host_client = save; +} + +/* <3d4a6> ../engine/host_cmd.c:3625 */ +void Host_Kill_f(void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + return; + } + if (sv_player->v.health <= 0.0f) + { + SV_ClientPrintf("Can't suicide -- already dead!\n"); + return; + } + gGlobalVariables.time = g_psv.time; + gEntityInterface.pfnClientKill(sv_player); +} + +/* <3db79> ../engine/host_cmd.c:3647 */ +void Host_TogglePause_f(void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + return; + } + if (!pausable.value) + { + SV_ClientPrintf("Pause not allowed.\n"); + return; + } + g_psv.paused ^= TRUE; + if (g_psv.paused) + SV_BroadcastPrintf("%s paused the game\n", &pr_strings[sv_player->v.netname]); + else + SV_BroadcastPrintf("%s unpaused the game\n", &pr_strings[sv_player->v.netname]); + + MSG_WriteByte(&g_psv.reliable_datagram, svc_setpause); + MSG_WriteByte(&g_psv.reliable_datagram, g_psv.paused); +} + +/* <3d49b> ../engine/host_cmd.c:3679 */ +void Host_Pause_f(void) +{ + // pause only singleplayer when console or main menu opens + if (!g_pcl.levelname[0]) + return; + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + return; + } + if (!pausable.value) + return; + + g_psv.paused = TRUE; + MSG_WriteByte(&g_psv.reliable_datagram, svc_setpause); + MSG_WriteByte(&g_psv.reliable_datagram, g_psv.paused); +} + +/* <3d490> ../engine/host_cmd.c:3707 */ +void Host_Unpause_f(void) +{ + // unpause only singleplayer when console or main menu opens + if (!g_pcl.levelname[0]) + return; + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + return; + } + if (!pausable.value) + return; + + g_psv.paused = FALSE; + MSG_WriteByte(&g_psv.reliable_datagram, svc_setpause); + MSG_WriteByte(&g_psv.reliable_datagram, g_psv.paused); +} + +/* <3db08> ../engine/host_cmd.c:3873 */ +void Host_Interp_f(void) +{ + r_dointerp ^= 1; + if(!r_dointerp) + Con_Printf("Frame Interpolation OFF\n"); + else + Con_Printf("Frame Interpolation ON\n"); +} + +/* <400f8> ../engine/host_cmd.c:3898 */ +void Host_NextDemo(void) +{ + char str[1024]; + if (g_pcls.demonum == -1) + return; + + SCR_BeginLoadingPlaque(FALSE); + if (g_pcls.demos[g_pcls.demonum][0]) + { +#ifdef REHLDS_FIXES + if (g_pcls.demonum >= MAX_DEMOS) +#else + if (g_pcls.demonum == MAX_DEMOS) +#endif // REHLDS_FIXES + g_pcls.demonum = 0; + + Q_snprintf(str, sizeof(str), "playdemo %s\n", g_pcls.demos[g_pcls.demonum]); + Cbuf_InsertText(str); + ++g_pcls.demonum; + } + Con_Printf("No demos listed with startdemos\n"); + g_pcls.demonum = -1; +} + +/* <3d8c4> ../engine/host_cmd.c:3929 */ +void Host_Startdemos_f(void) +{ + int i; + int c; + + if (g_pcls.state == ca_dedicated) + { + if (!g_psv.active) + Con_Printf("Cannot play demos on a dedicated server.\n"); + return; + } + c = Cmd_Argc() - 1; + if (c > MAX_DEMOS) + { + c = MAX_DEMOS; + Con_Printf("Max %i demos in demoloop\n", MAX_DEMOS); + Con_Printf("%i demo(s) in loop\n", MAX_DEMOS); + } + Con_Printf("%i demo(s) in loop\n", c); + for (i = 1; i < c + 1; i++) + { + Q_strncpy(g_pcls.demos[i - 1], Cmd_Argv(i), 15); + g_pcls.demos[i - 1][15] = 0; + } + if (g_psv.active || g_pcls.demonum == -1 || g_pcls.demoplayback) + g_pcls.demonum = -1; + else + { + g_pcls.demonum = 0; + Host_NextDemo(); + } +} + +/* <3d8b9> ../engine/host_cmd.c:3972 */ +void Host_Demos_f(void) +{ + if (g_pcls.state != ca_dedicated) + { + if (g_pcls.demonum == -1) + g_pcls.demonum = 0; + CL_Disconnect_f(); + Host_NextDemo(); + } +} + +/* <3d485> ../engine/host_cmd.c:3989 */ +void Host_Stopdemo_f(void) +{ + if (g_pcls.state != ca_dedicated) + { + if (g_pcls.demoplayback) + { + CL_StopPlayback(); + CL_Disconnect(); + } + } +} + +/* <401a6> ../engine/host_cmd.c:4009 */ +NOXREF void Host_EndSection(const char *pszSection) +{ + giActive = DLL_PAUSED; + giSubState = 1; + giStateInfo = 1; + + if (!pszSection || !*pszSection) + Con_Printf(" endsection with no arguments\n"); + else + { + if (!Q_stricmp(pszSection, "_oem_end_training")) + giStateInfo = 1; + else if (!Q_stricmp(pszSection, "_oem_end_logo")) + giStateInfo = 2; + else if (!Q_stricmp(pszSection, "_oem_end_demo")) + giStateInfo = 3; + else + Con_DPrintf(" endsection with unknown Section keyvalue\n"); + } + Cbuf_AddText("\ndisconnect\n"); +} + +/* <3db1e> ../engine/host_cmd.c:4050 */ +void Host_Soundfade_f(void) +{ + int percent; + int inTime; + int holdTime; + int outTime; + + if (Cmd_Argc() != 3 && Cmd_Argc() != 5) + { + Con_Printf("soundfade [ ]\n"); + return; + } + + percent = Q_atoi(Cmd_Argv(1)); + + if (percent > 100) + percent = 100; + if (percent < 0) + percent = 0; + + holdTime = Q_atoi(Cmd_Argv(2)); + if (holdTime > 255) + holdTime = 255; + + if (Cmd_Argc() == 5) + { + outTime = Q_atoi(Cmd_Argv(3)); + if (outTime > 255) + outTime = 255; + + inTime = Q_atoi(Cmd_Argv(4)); + if (inTime > 255) + inTime = 255; + } + else + { + outTime = 0; + inTime = 0; + } + + g_pcls.soundfade.nStartPercent = percent; + g_pcls.soundfade.soundFadeStartTime = realtime; + g_pcls.soundfade.soundFadeOutTime = outTime; + g_pcls.soundfade.soundFadeHoldTime = holdTime; + g_pcls.soundfade.soundFadeInTime = inTime; +} + +/* <3daf2> ../engine/host_cmd.c:4095 */ +void Host_KillServer_f(void) +{ + if (g_pcls.state != ca_dedicated) + CL_Disconnect_f(); + + else if (g_psv.active) + { + Host_ShutdownServer(FALSE); + + if (g_pcls.state != ca_dedicated) + NET_Config(FALSE); + } +} + +/* <401d0> ../engine/host_cmd.c:4110 */ +void Host_VoiceRecordStart_f(void) +{ + const char *pUncompressedFile = NULL; + const char *pDecompressedFile = NULL; + const char *pInputFile = NULL; + + if (g_pcls.state != ca_active) + return; + + if (voice_recordtofile.value) + { + pDecompressedFile = "voice_decompressed.wav"; + pUncompressedFile = "voice_micdata.wav"; + } + if (voice_inputfromfile.value) + pInputFile = "voice_input.wav"; + Voice_RecordStart(pUncompressedFile, pDecompressedFile, pInputFile); +} + +/* <40225> ../engine/host_cmd.c:4136 */ +void Host_VoiceRecordStop_f(void) +{ + if (g_pcls.state != ca_active) + return; + + if (Voice_IsRecording()) + { + CL_AddVoiceToDatagram(TRUE); + Voice_RecordStop(); + } +} + +/* <4023b> ../engine/host_cmd.c:4230 */ +void Host_Crash_f(void) +{ + int *p = NULL; + *p = 0xffffffff; +} + +/* <40260> ../engine/host_cmd.c:4242 */ +void Host_InitCommands(void) +{ +#ifdef HOOK_ENGINE + Cmd_AddCommand("shutdownserver", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_KillServer_f", (void *)Host_KillServer_f)); + Cmd_AddCommand("soundfade", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Soundfade_f", (void *)Host_Soundfade_f)); + Cmd_AddCommand("status", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Status_f", (void *)Host_Status_f)); + Cmd_AddCommand("stat", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Status_Formatted_f", (void *)Host_Status_Formatted_f)); + Cmd_AddCommand("quit", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Quit_f", (void *)Host_Quit_f)); + Cmd_AddCommand("_restart", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Quit_Restart_f", (void *)Host_Quit_Restart_f)); + Cmd_AddCommand("exit", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Quit_f", (void *)Host_Quit_f)); + Cmd_AddCommand("map", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Map_f", (void *)Host_Map_f)); + Cmd_AddCommand("career", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Career_f", (void *)Host_Career_f)); + Cmd_AddCommand("maps", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Maps_f", (void *)Host_Maps_f)); + Cmd_AddCommand("restart", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Restart_f", (void *)Host_Restart_f)); + Cmd_AddCommand("reload", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Reload_f", (void *)Host_Reload_f)); + Cmd_AddCommand("changelevel", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Changelevel_f", (void *)Host_Changelevel_f)); + Cmd_AddCommand("changelevel2", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Changelevel2_f", (void *)Host_Changelevel2_f)); + Cmd_AddCommand("reconnect", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Reconnect_f", (void *)Host_Reconnect_f)); + Cmd_AddCommand("version", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Version_f", (void *)Host_Version_f)); + Cmd_AddCommand("say", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Say_f", (void *)Host_Say_f)); + Cmd_AddCommand("say_team", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Say_Team_f", (void *)Host_Say_Team_f)); + Cmd_AddCommand("tell", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Tell_f", (void *)Host_Tell_f)); + Cmd_AddCommand("kill", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Kill_f", (void *)Host_Kill_f)); + Cmd_AddCommand("pause", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_TogglePause_f", (void *)Host_TogglePause_f)); + Cmd_AddCommand("setpause", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Pause_f", (void *)Host_Pause_f)); + Cmd_AddCommand("unpause", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Unpause_f", (void *)Host_Unpause_f)); + Cmd_AddCommand("kick", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Kick_f", (void *)Host_Kick_f)); + Cmd_AddCommand("ping", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Ping_f", (void *)Host_Ping_f)); + Cmd_AddCommand("motd", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Motd_f", (void *)Host_Motd_f)); + Cmd_AddCommand("motd_write", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Motd_Write_f", (void *)Host_Motd_Write_f)); + Cmd_AddCommand("stats", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Stats_f", (void *)Host_Stats_f)); + Cmd_AddCommand("load", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Loadgame_f", (void *)Host_Loadgame_f)); + Cmd_AddCommand("save", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Savegame_f", (void *)Host_Savegame_f)); + Cmd_AddCommand("autosave", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_AutoSave_f", (void *)Host_AutoSave_f)); + Cmd_AddCommand("writecfg", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_WriteCustomConfig", (void *)Host_WriteCustomConfig)); + Cmd_AddCommand("startdemos", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Startdemos_f", (void *)Host_Startdemos_f)); + Cmd_AddCommand("demos", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Demos_f", (void *)Host_Demos_f)); + Cmd_AddCommand("stopdemo", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Stopdemo_f", (void *)Host_Stopdemo_f)); + Cmd_AddCommand("setinfo", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_SetInfo_f", (void *)Host_SetInfo_f)); + Cmd_AddCommand("fullinfo", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_FullInfo_f", (void *)Host_FullInfo_f)); + Cmd_AddCommand("mcache", (xcommand_t)GetOriginalFuncAddrOrDefault("Mod_Print", (void *)Mod_Print)); + Cmd_AddCommand("interp", (xcommand_t)GetOriginalFuncAddrOrDefault("Host_Interp_f", (void *)Host_Interp_f)); + Cmd_AddCommand("setmaster", (xcommand_t)GetOriginalFuncAddrOrDefault("Master_SetMaster_f", (void *)Master_SetMaster_f)); + Cmd_AddCommand("heartbeat", (xcommand_t)GetOriginalFuncAddrOrDefault("Master_Heartbeat_f", (void *)Master_Heartbeat_f)); +#else // HOOK_ENGINE +#ifndef SWDS + Cmd_AddCommand("cd", CD_Command_f); + Cmd_AddCommand("mp3", MP3_Command_f); + Cmd_AddCommand("_careeraudio", CareerAudio_Command_f); +#endif // SWDS + Cmd_AddCommand("shutdownserver", Host_KillServer_f); + Cmd_AddCommand("soundfade", Host_Soundfade_f); + Cmd_AddCommand("status", Host_Status_f); + Cmd_AddCommand("stat", Host_Status_Formatted_f); + Cmd_AddCommand("quit", Host_Quit_f); + Cmd_AddCommand("_restart", Host_Quit_Restart_f); +#ifndef SWDS + Cmd_AddCommand("_setrenderer", Host_SetRenderer_f); + Cmd_AddCommand("_setvideomode", Host_SetVideoMode_f); + Cmd_AddCommand("_setgamedir", Host_SetGameDir_f); + Cmd_AddCommand("_sethdmodels", Host_SetHDModels_f); + Cmd_AddCommand("_setaddons_folder", Host_SetAddonsFolder_f); + Cmd_AddCommand("_set_vid_level", Host_SetVideoLevel_f); +#endif // SWDS + Cmd_AddCommand("exit", Host_Quit_f); + Cmd_AddCommand("map", Host_Map_f); + Cmd_AddCommand("career", Host_Career_f); + Cmd_AddCommand("maps", Host_Maps_f); + Cmd_AddCommand("restart", Host_Restart_f); + Cmd_AddCommand("reload", Host_Reload_f); + Cmd_AddCommand("changelevel", Host_Changelevel_f); + Cmd_AddCommand("changelevel2", Host_Changelevel2_f); + Cmd_AddCommand("reconnect", Host_Reconnect_f); + Cmd_AddCommand("version", Host_Version_f); + Cmd_AddCommand("say", Host_Say_f); + Cmd_AddCommand("say_team", Host_Say_Team_f); + Cmd_AddCommand("tell", Host_Tell_f); + Cmd_AddCommand("kill", Host_Kill_f); + Cmd_AddCommand("pause", Host_TogglePause_f); + Cmd_AddCommand("setpause", Host_Pause_f); + Cmd_AddCommand("unpause", Host_Unpause_f); + Cmd_AddCommand("kick", Host_Kick_f); + Cmd_AddCommand("ping", Host_Ping_f); + Cmd_AddCommand("motd", Host_Motd_f); + Cmd_AddCommand("motd_write", Host_Motd_Write_f); + Cmd_AddCommand("stats", Host_Stats_f); + Cmd_AddCommand("load", Host_Loadgame_f); + Cmd_AddCommand("save", Host_Savegame_f); + Cmd_AddCommand("autosave", Host_AutoSave_f); + Cmd_AddCommand("writecfg", Host_WriteCustomConfig); +#ifndef SWDS + Cmd_AddCommand("+voicerecord", Host_VoiceRecordStart_f); + Cmd_AddCommand("-voicerecord", Host_VoiceRecordStop_f); +#endif // SWDS + Cmd_AddCommand("startdemos", Host_Startdemos_f); + Cmd_AddCommand("demos", Host_Demos_f); + Cmd_AddCommand("stopdemo", Host_Stopdemo_f); + Cmd_AddCommand("setinfo", Host_SetInfo_f); + Cmd_AddCommand("fullinfo", Host_FullInfo_f); +#ifndef SWDS + Cmd_AddCommand("god", Host_God_f); + Cmd_AddCommand("notarget", Host_Notarget_f); + Cmd_AddCommand("fly", Host_Fly_f); + Cmd_AddCommand("noclip", Host_Noclip_f); + Cmd_AddCommand("viewmodel", Host_Viewmodel_f); + Cmd_AddCommand("viewframe", Host_Viewframe_f); + Cmd_AddCommand("viewnext", Host_Viewnext_f); + Cmd_AddCommand("viewprev", Host_Viewprev_f); +#endif // SWDS + Cmd_AddCommand("mcache", Mod_Print); + Cmd_AddCommand("interp", Host_Interp_f); + Cmd_AddCommand("setmaster", Master_SetMaster_f); + Cmd_AddCommand("heartbeat", Master_Heartbeat_f); +#endif // HOOK_ENGINE + + Cvar_RegisterVariable(&gHostMap); + Cvar_RegisterVariable(&voice_recordtofile); + Cvar_RegisterVariable(&voice_inputfromfile); +} + +/* <40276> ../engine/host_cmd.c:4388 */ +void SV_CheckBlendingInterface(void) +{ + int i; + SV_BLENDING_INTERFACE_FUNC studio_interface; + + R_ResetSvBlending(); + for (i = 0; i < g_iextdllMac; i++) + { +#ifdef _WIN32 + studio_interface = (SV_BLENDING_INTERFACE_FUNC)GetProcAddress((HMODULE)g_rgextdll[i].lDLLHandle, "Server_GetBlendingInterface"); +#else + studio_interface = (SV_BLENDING_INTERFACE_FUNC)dlsym(g_rgextdll[i].lDLLHandle, "Server_GetBlendingInterface"); +#endif // _WIN32 + if (studio_interface) + { + if (studio_interface(SV_BLENDING_INTERFACE_VERSION, &g_pSvBlendingAPI, &server_studio_api, (float *)rotationmatrix, (float *)bonetransform)) + return; + + Con_DPrintf("Couldn't get server .dll studio model blending interface. Version mismatch?\n"); + R_ResetSvBlending(); + } + } +} + +/* <3e266> ../engine/host_cmd.c:4431 */ +void SV_CheckSaveGameCommentInterface(void) +{ + int i; + SV_SAVEGAMECOMMENT_FUNC pTemp = NULL; + for (i = 0; i < g_iextdllMac; i++) + { +#ifdef _WIN32 + pTemp = (SV_SAVEGAMECOMMENT_FUNC)GetProcAddress((HMODULE)g_rgextdll[i].lDLLHandle, "SV_SaveGameComment"); +#else + pTemp = (SV_SAVEGAMECOMMENT_FUNC)dlsym(g_rgextdll[i].lDLLHandle, "SV_SaveGameComment"); +#endif // _WIN32 + if (pTemp) + break; + } + g_pSaveGameCommentFunc = pTemp; +} diff --git a/rehlds/engine/host_cmd.h b/rehlds/engine/host_cmd.h new file mode 100644 index 0000000..1c53ba2 --- /dev/null +++ b/rehlds/engine/host_cmd.h @@ -0,0 +1,215 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef HOST_CMD_H +#define HOST_CMD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "eiface.h" +#include "FileSystem.h" + +/* <3d22f> ../engine/host_cmd.c:83 */ +typedef void (*SV_SAVEGAMECOMMENT_FUNC)(char *, int); + +/* <3c2b9> ../engine/host_cmd.h:40 */ +typedef struct GAME_HEADER_s +{ + char mapName[32]; + char comment[80]; + int mapCount; +} GAME_HEADER; + +/* <3c307> ../engine/host_cmd.h:47 */ +typedef struct SAVE_HEADER_s +{ + int saveId; + int version; + int skillLevel; + int entityCount; + int connectionCount; + int lightStyleCount; + float time; + char mapName[32]; + char skyName[32]; + int skyColor_r; + int skyColor_g; + int skyColor_b; + float skyVec_x; + float skyVec_y; + float skyVec_z; +} SAVE_HEADER; + +/* <3c3ed> ../engine/host_cmd.h:67 */ +typedef struct SAVELIGHTSTYLE_s +{ + int index; + char style[64]; +} SAVELIGHTSTYLE; + +/* <3d29e> ../engine/host_cmd.c:1792 */ +typedef struct TITLECOMMENT_s +{ + char *pBSPName; + char *pTitleName; +} TITLECOMMENT; + +#ifdef HOOK_ENGINE + +#define r_dointerp (*pr_dointerp) +#define r_origin (*pr_origin) +#define cpuPercent (*pcpuPercent) +#define startTime (*pstartTime) +#define current_skill (*pcurrent_skill) +#define gHostSpawnCount (*pgHostSpawnCount) +#define g_careerState (*pg_careerState) +#define g_pSaveGameCommentFunc (*pg_pSaveGameCommentFunc) +#define g_bMajorMapChange (*pg_bMajorMapChange) +#define voice_recordtofile (*pvoice_recordtofile) +#define voice_inputfromfile (*pvoice_inputfromfile) +#define gTitleComments (*pgTitleComments) +#define gGameHeaderDescription (*pgGameHeaderDescription) +#define gSaveHeaderDescription (*pgSaveHeaderDescription) +#define gAdjacencyDescription (*pgAdjacencyDescription) +#define gEntityTableDescription (*pgEntityTableDescription) +#define gLightstyleDescription (*pgLightstyleDescription) +#define gHostMap (*pgHostMap) +#define g_iQuitCommandIssued (*pg_iQuitCommandIssued) +#define g_pPostRestartCmdLineArgs pg_pPostRestartCmdLineArgs + +#endif //HOOK_ENGINE + +extern int r_dointerp; +extern vec3_t r_origin; +extern double cpuPercent; +extern int32 startTime; +extern int current_skill; +extern int gHostSpawnCount; +extern CareerStateType g_careerState; +extern SV_SAVEGAMECOMMENT_FUNC g_pSaveGameCommentFunc; +extern qboolean g_bMajorMapChange; +extern cvar_t voice_recordtofile; +extern cvar_t voice_inputfromfile; +extern TITLECOMMENT gTitleComments[66]; +extern TYPEDESCRIPTION gGameHeaderDescription[3]; +extern TYPEDESCRIPTION gSaveHeaderDescription[13]; +extern TYPEDESCRIPTION gAdjacencyDescription[4]; +extern TYPEDESCRIPTION gEntityTableDescription[5]; +extern TYPEDESCRIPTION gLightstyleDescription[2]; +extern cvar_t gHostMap; +extern int g_iQuitCommandIssued; +extern char *g_pPostRestartCmdLineArgs; + +void SV_GetPlayerHulls(void); +void Host_InitializeGameDLL(void); +void Host_Motd_f(void); +void Host_Motd_Write_f(void); +int Host_GetStartTime(void); +void Host_UpdateStats(void); +void GetStatsString(char *buf, int bufSize); +void Host_Stats_f(void); +void Host_Quit_f(void); +void Host_Quit_Restart_f(void); +void Host_Status_Printf(qboolean conprint, qboolean log, char *fmt, ...); +void Host_Status_f(void); +void Host_Status_Formatted_f(void); +void Host_Ping_f(void); +void Host_Map(qboolean bIsDemo, char *mapstring, char *mapName, qboolean loadGame); +void Host_Map_f(void); +void Host_Career_f(void); +void Host_Maps_f(void); +void Host_Changelevel_f(void); +const char *Host_FindRecentSave(char *pNameBuf); +void Host_Restart_f(void); +void Host_Reload_f(void); +void Host_Reconnect_f(void); +char *Host_SaveGameDirectory(void); +void Host_SavegameComment(char *pszBuffer, int iSizeBuffer); +void Host_SaveAgeList(const char *pName, int count); +int Host_ValidSave(void); +SAVERESTOREDATA *SaveInit(int size); +void SaveExit(SAVERESTOREDATA *save); +qboolean SaveGameSlot(const char *pSaveName, const char *pSaveComment); +void Host_Savegame_f(void); +void Host_AutoSave_f(void); +qboolean SaveGame(const char *pszSlot, const char *pszComment); +int SaveReadHeader(FileHandle_t pFile, GAME_HEADER *pHeader, int readGlobalState); +void SaveReadComment(FileHandle_t f, char *name); +void Host_Loadgame_f(void); +int LoadGame(const char *pName); +int Host_Load(const char *pName); +SAVERESTOREDATA *SaveGamestate(void); +void EntityInit(edict_t *pEdict, int className); +SAVERESTOREDATA *LoadSaveData(const char *level); +void ParseSaveTables(SAVERESTOREDATA *pSaveData, SAVE_HEADER *pHeader, int updateGlobals); +void EntityPatchWrite(SAVERESTOREDATA *pSaveData, const char *level); +void EntityPatchRead(SAVERESTOREDATA *pSaveData, const char *level); +int LoadGamestate(char *level, int createPlayers); +int EntryInTable(SAVERESTOREDATA *pSaveData, const char *pMapName, int index); +void LandmarkOrigin(SAVERESTOREDATA *pSaveData, vec_t *output, const char *pLandmarkName); +int EntityInSolid(edict_t *pent); +int CreateEntityList(SAVERESTOREDATA *pSaveData, int levelMask); +void LoadAdjacentEntities(const char *pOldLevel, const char *pLandmarkName); +int FileSize(FileHandle_t pFile); +void FileCopy(FileHandle_t pOutput, FileHandle_t pInput, int fileSize); +void DirectoryCopy(const char *pPath, FileHandle_t pFile); +void DirectoryExtract(FileHandle_t pFile, int fileCount); +int DirectoryCount(const char *pPath); +void Host_ClearSaveDirectory(void); +void Host_ClearGameState(void); +void Host_Changelevel2_f(void); +void Host_Version_f(void); +void Host_FullInfo_f(void); +NOXREF void Host_KillVoice_f(void); +void Host_SetInfo_f(void); +void Host_Say(qboolean teamonly); +void Host_Say_f(void); +void Host_Say_Team_f(void); +void Host_Tell_f(void); +void Host_Kill_f(void); +void Host_TogglePause_f(void); +void Host_Pause_f(void); +void Host_Unpause_f(void); +void Host_Interp_f(void); +void Host_NextDemo(void); +void Host_Startdemos_f(void); +void Host_Demos_f(void); +void Host_Stopdemo_f(void); +NOXREF void Host_EndSection(const char *pszSection); +void Host_Soundfade_f(void); +void Host_KillServer_f(void); +void Host_VoiceRecordStart_f(void); +void Host_VoiceRecordStop_f(void); +void Host_Crash_f(void); +void Host_InitCommands(void); +void SV_CheckBlendingInterface(void); +void SV_CheckSaveGameCommentInterface(void); + +#endif // HOST_CMD_H diff --git a/rehlds/engine/iengine.h b/rehlds/engine/iengine.h new file mode 100644 index 0000000..767c44a --- /dev/null +++ b/rehlds/engine/iengine.h @@ -0,0 +1,181 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef IENGINE_H +#define IENGINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + + +class IEngine +{ +public: + enum + { + QUIT_NOTQUITTING = 0, + QUIT_TODESKTOP, + QUIT_RESTART + }; + + virtual ~IEngine(void) { } + + virtual bool Load(bool dedicated, char *basedir, char *cmdline) = 0; + virtual void Unload(void) = 0; + virtual void SetState(int iState) = 0; + virtual int GetState(void) = 0; + virtual void SetSubState(int iSubState) = 0; + virtual int GetSubState(void) = 0; + + virtual int Frame(void) = 0; + virtual double GetFrameTime(void) = 0; + virtual double GetCurTime(void) = 0; + + virtual void TrapKey_Event(int key, bool down) = 0; + virtual void TrapMouse_Event(int buttons, bool down) = 0; + + virtual void StartTrapMode(void) = 0; + virtual bool IsTrapping(void) = 0; + virtual bool CheckDoneTrapping(int& buttons, int& key) = 0; + + virtual int GetQuitting(void) = 0; + virtual void SetQuitting(int quittype) = 0; +}; + +extern IEngine *eng; + +///* <8f12e> ../engine/iengine.h:39 */ +//virtual void ~IEngine(class IEngine *, int) +//{ +//} /* size: 165463000 */ +// +///* <8f151> ../engine/iengine.h:41 */ +//virtual bool Load(class IEngine *, bool, char *, char *) /* linkage=_ZN7IEngine4LoadEbPcS0_ */ +//{ +//} /* size: 1 */ +// +///* <8f188> ../engine/iengine.h:42 */ +//virtual void Unload(class IEngine *) /* linkage=_ZN7IEngine6UnloadEv */ +//{ +//} /* size: 0 */ +// +///* <8f1ac> ../engine/iengine.h:43 */ +//virtual void SetState(class IEngine *, int) /* linkage=_ZN7IEngine8SetStateEi */ +//{ +//} /* size: 165479164 */ +// +///* <8f1d5> ../engine/iengine.h:44 */ +//virtual int GetState(class IEngine *) /* linkage=_ZN7IEngine8GetStateEv */ +//{ +//} /* size: 4 */ +// +///* <8f1fd> ../engine/iengine.h:45 */ +//virtual void SetSubState(class IEngine *, int) /* linkage=_ZN7IEngine11SetSubStateEi */ +//{ +//} /* size: 165463956 */ +// +///* <8f226> ../engine/iengine.h:46 */ +//virtual int GetSubState(class IEngine *) /* linkage=_ZN7IEngine11GetSubStateEv */ +//{ +//} /* size: 4 */ +// +///* <8f24e> ../engine/iengine.h:47 */ +//virtual int Frame(class IEngine *) /* linkage=_ZN7IEngine5FrameEv */ +//{ +//} /* size: 4 */ +// +///* <8f276> ../engine/iengine.h:49 */ +//virtual double GetFrameTime(class IEngine *) /* linkage=_ZN7IEngine12GetFrameTimeEv */ +//{ +//} /* size: 8 */ +// +///* <8f29e> ../engine/iengine.h:50 */ +//virtual double GetCurTime(class IEngine *) /* linkage=_ZN7IEngine10GetCurTimeEv */ +//{ +//} /* size: 8 */ +// +///* <8f2c6> ../engine/iengine.h:52 */ +//virtual void TrapKey_Event(class IEngine *, int, bool) /* linkage=_ZN7IEngine13TrapKey_EventEib */ +//{ +//} /* size: 0 */ +// +///* <8f2f4> ../engine/iengine.h:53 */ +//virtual void TrapMouse_Event(class IEngine *, int, bool) /* linkage=_ZN7IEngine15TrapMouse_EventEib */ +//{ +//} /* size: 773 */ +// +///* <8f322> ../engine/iengine.h:55 */ +//virtual void StartTrapMode(class IEngine *) /* linkage=_ZN7IEngine13StartTrapModeEv */ +//{ +//} /* size: 2865 */ +// +///* <8f346> ../engine/iengine.h:56 */ +//virtual bool IsTrapping(class IEngine *) /* linkage=_ZN7IEngine10IsTrappingEv */ +//{ +//} /* size: 1 */ +// +///* <8f36e> ../engine/iengine.h:57 */ +//virtual bool CheckDoneTrapping(class IEngine *, int &, int &) /* linkage=_ZN7IEngine17CheckDoneTrappingERiS0_ */ +//{ +//} /* size: 1 */ +// +///* <8f3a0> ../engine/iengine.h:59 */ +//virtual int GetQuitting(class IEngine *) /* linkage=_ZN7IEngine11GetQuittingEv */ +//{ +//} /* size: 4 */ +// +///* <8f3c8> ../engine/iengine.h:60 */ +//virtual void SetQuitting(class IEngine *, int) /* linkage=_ZN7IEngine11SetQuittingEi */ +//{ +//} /* size: 165481496 */ +// +///* <961fe> ../engine/iengine.h:29 */ +//inline void IEngine(class IEngine *const this) +//{ +//} /* size: 167122024 */ +// +///* <8fcbf> ../engine/iengine.h:39 */ +//inline void ~IEngine(class IEngine *const this, intconst __in_chrg) +//{ +//} /* size: 768 */ +// +///* <96256> ../engine/iengine.h:39 */ +//void ~IEngine(class IEngine *const this) +//{ +//} /* size: 167122528 */ +// +///* <965c9> ../engine/iengine.h:39 */ +//void ~IEngine(class IEngine *const this) +//{ +// ~IEngine(class IEngine *const this, +// intconst __in_chrg); /* size=167350372, low_pc=0 */ // 39 +//} /* size: 167350468 */ + +#endif // IENGINE_H diff --git a/rehlds/engine/igame.h b/rehlds/engine/igame.h new file mode 100644 index 0000000..45ece3b --- /dev/null +++ b/rehlds/engine/igame.h @@ -0,0 +1,102 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + + +#include "maintypes.h" + +//Restored params names from hl2beta https://github.com/RaisingTheDerp/raisingthebar/ +/* <8f8da> ../engine/igame.h:26 */ +class IGame { +public: + + /* <8f8f7> ../engine/igame.h:29 */ + virtual ~IGame() { } + + /* <8f91a> ../engine/igame.h:31 */ + virtual bool Init(void *pvInstance) = 0; + + /* <8f947> ../engine/igame.h:32 */ + virtual bool Shutdown() = 0; + + /* <8f96f> ../engine/igame.h:34 */ + virtual bool CreateGameWindow() = 0; + + /* <8f997> ../engine/igame.h:36 */ + virtual void SleepUntilInput(int time) = 0; + + /* <8f9c0> ../engine/igame.h:38 */ + virtual HWND GetMainWindow() = 0; + + /* <8f9e8> ../engine/igame.h:39 */ + virtual HWND * GetMainWindowAddress() = 0; + + /* <8fa10> ../engine/igame.h:41 */ + virtual void SetWindowXY(int x, int y) = 0; + + /* <8fa3e> ../engine/igame.h:42 */ + virtual void SetWindowSize(int w, int h) = 0; + + /* <8fa6c> ../engine/igame.h:44 */ + virtual void GetWindowRect(int *x, int *y, int *w, int *h) = 0; + + /* <8faa4> ../engine/igame.h:47 */ + virtual bool IsActiveApp() = 0; + + /* <8facc> ../engine/igame.h:49 */ + virtual bool IsMultiplayer() = 0; + + /* <8faf4> ../engine/igame.h:51 */ + virtual void PlayStartupVideos() = 0; + + /* <8fb18> ../engine/igame.h:52 */ + virtual void PlayAVIAndWait(const char *aviFile) = 0; + + /* <8fb41> ../engine/igame.h:54 */ + virtual void SetCursorVisible(bool vis) = 0; + + /* vtable has 14 entries: { + [2] = Init(_ZN5IGame4InitEPv), + [3] = Shutdown(_ZN5IGame8ShutdownEv), + [4] = CreateGameWindow(_ZN5IGame16CreateGameWindowEv), + [5] = SleepUntilInput(_ZN5IGame15SleepUntilInputEi), + [6] = GetMainWindow(_ZN5IGame13GetMainWindowEv), + [7] = GetMainWindowAddress(_ZN5IGame20GetMainWindowAddressEv), + [8] = SetWindowXY(_ZN5IGame11SetWindowXYEii), + [9] = SetWindowSize(_ZN5IGame13SetWindowSizeEii), + [10] = GetWindowRect(_ZN5IGame13GetWindowRectEPiS0_S0_S0_), + [11] = IsActiveApp(_ZN5IGame11IsActiveAppEv), + [12] = IsMultiplayer(_ZN5IGame13IsMultiplayerEv), + [13] = PlayStartupVideos(_ZN5IGame17PlayStartupVideosEv), + [14] = PlayAVIAndWait(_ZN5IGame14PlayAVIAndWaitEPKc), + [15] = SetCursorVisible(_ZN5IGame16SetCursorVisibleEb), + } */ + /* size: 4, cachelines: 1, members: 1 */ + /* last cacheline: 4 bytes */ +}; /* size: 4 */ diff --git a/rehlds/engine/info.cpp b/rehlds/engine/info.cpp new file mode 100644 index 0000000..8e06f29 --- /dev/null +++ b/rehlds/engine/info.cpp @@ -0,0 +1,618 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +// NOTE: This file contains a lot of fixes that are not covered by REHLDS_FIXES define. +// TODO: Most of the Info_ functions can be speedup via removing unneded copy of key and values. +// TODO: We have a problem with Q_strcpy, because it maps to strcpy which have undefined behavior when strings overlaps (possibly we need to use memmove solution here) + +/* +=============== +Info_ValueForKey + +Searches the string for the given +key and returns the associated value, or an empty string. +=============== +*/ +/* <40d86> ../engine/info.c:23 */ +const char *Info_ValueForKey(const char *s, const char *key) +{ + // use few (two?) buffers so compares work without stomping on each other + static char value[INFO_MAX_BUFFER_VALUES][MAX_KV_LEN]; + static int valueindex; + char pkey[MAX_KV_LEN]; + char *c; + int nCount; + + while (*s) + { + if (*s == '\\') + { + s++; // skip the slash + } + + // Copy a key + nCount = 0; + c = pkey; + while (*s != '\\') + { + if (!*s) + { + return ""; // key should end with a \, not a NULL, but suppose its value as absent + } + if (nCount >= MAX_KV_LEN) + { + s++; + continue; // skip oversized key chars till the slash or EOL + } + *c++ = *s++; + nCount++; + } + *c = 0; + s++; // skip the slash + + // Copy a value + nCount = 0; + c = value[valueindex]; + while (*s != '\\') + { + if (!*s) + { + break; // allow value to be ended with NULL + } + if (nCount >= MAX_KV_LEN) + { + s++; + continue; // skip oversized value chars till the slash or EOL + } + *c++ = *s++; + nCount++; + } + *c = 0; + + if (!Q_strcmp(key, pkey)) + { + c = value[valueindex]; + valueindex = (valueindex + 1) % INFO_MAX_BUFFER_VALUES; + return c; + } + } + + return ""; +} + +/* <40e38> ../engine/info.c:72 */ +void Info_RemoveKey(char *s, const char *key) +{ + char pkey[MAX_KV_LEN]; + char value[MAX_KV_LEN]; + char *start; + char *c; + int cmpsize; + int nCount; + + if (Q_strstr(key, "\\")) + { + Con_Printf("Can't use a key with a \\\n"); + return; + } + + cmpsize = Q_strlen(key); + if (cmpsize > MAX_KV_LEN - 1) + cmpsize = MAX_KV_LEN - 1; + + while (*s) + { + start = s; + + if (*s == '\\') + { + s++; // skip the slash + } + + // Copy a key + nCount = 0; + c = pkey; + while (*s != '\\') + { + if (!*s) + { + break; // key should end with a \, not a NULL, but allow to remove it + } + if (nCount >= MAX_KV_LEN) + { + s++; + continue; // skip oversized key chars till the slash or EOL + } + *c++ = *s++; + nCount++; + } + *c = 0; + if (*s) + s++; // skip the slash + + // Copy a value + nCount = 0; + c = value; + while (*s != '\\') + { + if (!*s) + { + break; // allow value to be ended with NULL + } + if (nCount >= MAX_KV_LEN) + { + s++; + continue; // skip oversized value chars till the slash or EOL + } + *c++ = *s++; + nCount++; + } + *c = 0; + + // Compare keys + if (!Q_strncmp(key, pkey, cmpsize)) + { + Q_strcpy(start, s); // remove this part + s = start; // continue searching + } + } +} + +/* <40ecf> ../engine/info.c:136 */ +void Info_RemovePrefixedKeys(char *s, const char prefix) +{ + char pkey[MAX_KV_LEN]; + char value[MAX_KV_LEN]; + char *start; + char *c; + int nCount; + + while (*s) + { + start = s; + + if (*s == '\\') + { + s++; // skip the slash + } + + // Copy a key + nCount = 0; + c = pkey; + while (*s != '\\') + { + if (!*s) + { + break; // key should end with a \, not a NULL, but allow to remove it + } + if (nCount >= MAX_KV_LEN) + { + s++; + continue; // skip oversized key chars till the slash or EOL + } + *c++ = *s++; + nCount++; + } + *c = 0; + if (*s) + s++; // skip the slash + + // Copy a value + nCount = 0; + c = value; + while (*s != '\\') + { + if (!*s) + { + break; // allow value to be ended with NULL + } + if (nCount >= MAX_KV_LEN) + { + s++; + continue; // skip oversized value chars till the slash or EOL + } + *c++ = *s++; + nCount++; + } + *c = 0; + + if (pkey[0] == prefix) + { + Q_strcpy(start, s); // remove this part + s = start; // continue searching + } + } +} + +/* <40d4a> ../engine/info.c:188 */ +qboolean Info_IsKeyImportant(const char *key) +{ + if (key[0] == '*') + return true; + if (!Q_strcmp(key, "name")) + return true; + if (!Q_strcmp(key, "model")) + return true; + if (!Q_strcmp(key, "rate")) + return true; + if (!Q_strcmp(key, "topcolor")) + return true; + if (!Q_strcmp(key, "botomcolor")) + return true; + if (!Q_strcmp(key, "cl_updaterate")) + return true; + if (!Q_strcmp(key, "cl_lw")) + return true; + if (!Q_strcmp(key, "cl_lc")) + return true; + if (!Q_strcmp(key, "*hltv")) + return true; + if (!Q_strcmp(key, "*sid")) + return true; + + return false; +} + +/* <40f88> ../engine/info.c:216 */ +char *Info_FindLargestKey(char *s, int maxsize) +{ + static char largest_key[MAX_KV_LEN]; + char key[MAX_KV_LEN]; + char value[MAX_KV_LEN]; + char *c; + int nCount; + int largest_size = 0; + + largest_key[0] = 0; + + while (*s) + { + if (*s == '\\') + { + s++; // skip the slash + } + + // Copy a key + nCount = 0; + c = key; + while (*s != '\\') + { + if (!*s) // key should end with a \, not a NULL, return this key, so it will be deleted as wrong + { + *c = 0; + Q_strcpy(largest_key, key); + return largest_key; + } + if (nCount >= MAX_KV_LEN) // oversized key, return this key, so it will be deleted as wrong + { + *c = 0; + Q_strcpy(largest_key, key); + return largest_key; + } + *c++ = *s++; + nCount++; + } + *c = 0; + s++; // skip the slash + + // Get length + int size = c - key; + + // Copy a value + nCount = 0; + c = value; + while (*s != '\\') + { + if (!*s) + { + break; // allow value to be ended with NULL + } + if (nCount >= MAX_KV_LEN) // oversized value, return this key, so it will be deleted as wrong + { + *c = 0; + Q_strcpy(largest_key, key); + return largest_key; + } + *c++ = *s++; + nCount++; + } + *c = 0; + + // Add length + size += c - value; + + if (size > largest_size && !Info_IsKeyImportant(key)) + { + largest_size = size; + Q_strcpy(largest_key, key); + } + } + + return largest_key; +} + +/* <41063> ../engine/info.c:275 */ +void Info_SetValueForStarKey(char *s, const char *key, const char *value, int maxsize) +{ + char newArray[MAX_INFO_STRING]; + char *v; + int c; + + if (!key || !value) + { + Con_Printf("Keys and values can't be null\n"); + return; + } + + if (key[0] == 0) + { + Con_Printf("Keys can't be an empty string\n"); + return; + } + + if (Q_strstr(key, "\\") || Q_strstr(value, "\\")) + { + Con_Printf("Can't use keys or values with a \\\n"); + return; + } + + if (Q_strstr(key, "..") || Q_strstr(value, "..")) + { + // TODO: Why silently return? + //Con_Printf("Can't use keys or values with a ..\n"); + return; + } + + if (Q_strstr(key, "\"") || Q_strstr(value, "\"")) + { + Con_Printf("Can't use keys or values with a \"\n"); + return; + } + + int keyLen = Q_strlen(key); + int valueLan = Q_strlen(value); + + if (keyLen >= MAX_KV_LEN || valueLan >= MAX_KV_LEN) + { + Con_Printf("Keys and values must be < %i characters\n", MAX_KV_LEN); + return; + } + + if (!Q_UnicodeValidate(key) || !Q_UnicodeValidate(value)) + { + Con_Printf("Keys and values must be valid utf8 text\n"); + return; + } + + // Remove current key/value and return if we doesn't specified to set a value + Info_RemoveKey(s, key); + if (value[0] == 0) + { + return; + } + + // Create key/value pair + Q_snprintf(newArray, MAX_INFO_STRING - 1, "\\%s\\%s", key, value); + newArray[MAX_INFO_STRING - 1] = 0; + + int neededLength = Q_strlen(newArray); + if ((int)Q_strlen(s) + neededLength >= maxsize) + { + // no more room in the buffer to add key/value + if (!Info_IsKeyImportant(key)) + { + // no room to add setting + Con_Printf("Info string length exceeded\n"); + return; + } + + // keep removing the largest key/values until we have a room + char *largekey; + do + { + largekey = Info_FindLargestKey(s, maxsize); + if (largekey[0] == 0) + { + // no room to add setting + Con_Printf("Info string length exceeded\n"); + return; + } + Info_RemoveKey(s, largekey); + } while ((int)Q_strlen(s) + neededLength >= maxsize); + } + + // auto lowercase team + bool lowerCaseValue = Q_stricmp(key, "team") == 0; + s += Q_strlen(s); + v = newArray; + while (*v) + { + c = (unsigned char)*v++; + if (lowerCaseValue) + { + c = tolower(c); + } + *s++ = c; + } + *s = 0; +} + +/* <4113e> ../engine/info.c:361 */ +void Info_SetValueForKey(char *s, const char *key, const char *value, int maxsize) +{ + if (key[0] == '*') + { + Con_Printf("Can't set * keys\n"); + return; + } + + Info_SetValueForStarKey(s, key, value, maxsize); +} + +/* <41193> ../engine/info.c:372 */ +void Info_Print(const char *s) +{ + char key[MAX_KV_LEN]; + char value[MAX_KV_LEN]; + char *c; + int l; + int nCount; + + while (*s) + { + if (*s == '\\') + { + s++; // skip the slash + } + + // Copy a key + nCount = 0; + c = key; + while (*s != '\\') + { + if (!*s) + { + break; // key should end with a \, not a NULL, but allow to print it + } + if (nCount >= MAX_KV_LEN) + { + s++; + continue; // skip oversized key chars till the slash or EOL + } + *c++ = *s++; + nCount++; + } + *c = 0; + if (*s) + s++; // skip the slash + + // Pad and print a key + l = c - key; + if (l < 20) + { + Q_memset(c, ' ', 20 - l); + key[20] = 0; + } + Con_Printf("%s", key); + + if (!*s) + { + Con_Printf("MISSING VALUE\n"); + return; + } + + // Copy a value + nCount = 0; + c = value; + while (*s != '\\') + { + if (!*s) + { + break; // allow value to be ended with NULL + } + if (nCount >= MAX_KV_LEN) + { + s++; + continue; // skip oversized value chars till the slash or EOL + } + *c++ = *s++; + nCount++; + } + *c = 0; + + Con_Printf("%s\n", value); + } +} + +/* <4120e> ../engine/info.c:426 */ +qboolean Info_IsValid(const char *s) +{ + char key[MAX_KV_LEN]; + char value[MAX_KV_LEN]; + char *c; + int nCount; + + while (*s) + { + if (*s == '\\') + { + s++; // skip the slash + } + + // Copy a key + nCount = 0; + c = key; + while (*s != '\\') + { + if (!*s) + { + return FALSE; // key should end with a \, not a NULL + } + if (nCount >= MAX_KV_LEN) + { + return FALSE; // key length should be less then MAX_KV_LEN + } + *c++ = *s++; + nCount++; + } + *c = 0; + s++; // skip the slash + + // Copy a value + nCount = 0; + c = value; + while (*s != '\\') + { + if (!*s) + { + break; // allow value to be ended with NULL + } + if (nCount >= MAX_KV_LEN) + { + return FALSE; // value length should be less then MAX_KV_LEN + } + *c++ = *s++; + nCount++; + } + *c = 0; + + if (value[0] == 0) + { + return FALSE; // empty values are not valid + } + + if (!*s) + { + return TRUE; // EOL, info is valid + } + } + + return FALSE; +} diff --git a/rehlds/engine/info.h b/rehlds/engine/info.h new file mode 100644 index 0000000..d726392 --- /dev/null +++ b/rehlds/engine/info.h @@ -0,0 +1,56 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef INFO__H +#define INFO__H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + + +// Max key/value length (with a NULL char) +#define MAX_KV_LEN 127 +// Key + value + 2 x slash + NULL +#define MAX_INFO_STRING 256 + +#define INFO_MAX_BUFFER_VALUES 4 + + +const char *Info_ValueForKey(const char *s, const char *key); +void Info_RemoveKey(char *s, const char *key); +void Info_RemovePrefixedKeys(char *s, const char prefix); +qboolean Info_IsKeyImportant(const char *key); +char *Info_FindLargestKey(char *s, int maxsize); +void Info_SetValueForStarKey(char *s, const char *key, const char *value, int maxsize); +void Info_SetValueForKey(char *s, const char *key, const char *value, int maxsize); +void Info_Print(const char *s); +qboolean Info_IsValid(const char *s); + +#endif // INFO__H diff --git a/rehlds/engine/inst_baseline.h b/rehlds/engine/inst_baseline.h new file mode 100644 index 0000000..3a398ab --- /dev/null +++ b/rehlds/engine/inst_baseline.h @@ -0,0 +1,47 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef INST_BASELINE_H +#define INST_BASELINE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "entity_state.h" + +#define NUM_BASELINES 64 + +/* <7469c> ../engine/inst_baseline.h:9 */ +typedef struct extra_baselines_s +{ + int number; + int classname[NUM_BASELINES]; + entity_state_t baseline[NUM_BASELINES]; +} extra_baselines_t; + +#endif // INST_BASELINE_H diff --git a/rehlds/engine/ipratelimit.cpp b/rehlds/engine/ipratelimit.cpp new file mode 100644 index 0000000..466ab05 --- /dev/null +++ b/rehlds/engine/ipratelimit.cpp @@ -0,0 +1,80 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +//bool (__fastcall *pCIPRateLimit__CheckIP)(CIPRateLimit *obj, int none, netadr_t adr); + + +/* ../engine/ipratelimit.cpp:27 */ +bool CIPRateLimit::CheckIP(netadr_t adr) +{ + // TODO: Reverse me + //{ + // long int curTime; // 29 + // ip_t clientIP; // 32 + // class iprate_s findEntry; // 56 + // ip_t entry; // 57 + // { + // ip_t tmp; // 37 + // int i; // 38 + // LastInorder(const class CUtlRBTree *const this); /* size=169106148, low_pc=0 */ // 37 + // IsValidIndex(const class CUtlRBTree *const this, + // int i); /* size=524288, low_pc=0 */ // 41 + // operator[](class CUtlRBTree *const this, + // int i); /* size=169107280, low_pc=0 */ // 42 + // { + // ip_t removeIPT; // 45 + // PrevInorder(const class CUtlRBTree *const this, + // int i); /* size=0, low_pc=0 */ // 46 + // } + // PrevInorder(const class CUtlRBTree *const this, + // int i); /* size=2019913216, low_pc=0 */ // 51 + // } + // Find(const class CUtlRBTree *const this, + // const class iprate_s &const search); /* size=1967350639, low_pc=0 */ // 57 + // IsValidIndex(const class CUtlRBTree *const this, + // int i); /* size=7626612, low_pc=0 */ // 59 + // operator[](class CUtlRBTree *const this, + // int i); /* size=1936875856, low_pc=0 */ // 61 + // operator[](class CUtlRBTree *const this, + // int i); /* size=1869898597, low_pc=0 */ // 63 + // { + // float query_rate; // 70 + // } + // { + // class iprate_s newEntry; // 80 + // Insert(class CUtlRBTree *const this, + // const class iprate_s &const insert); /* size=1399744112, low_pc=0 */ // 84 + // } + // { + // float query_rate; // 97 + // } + //} + return true; +} diff --git a/rehlds/engine/ipratelimit.h b/rehlds/engine/ipratelimit.h new file mode 100644 index 0000000..a809f01 --- /dev/null +++ b/rehlds/engine/ipratelimit.h @@ -0,0 +1,87 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef IPRATELIMIT_H +#define IPRATELIMIT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "net.h" +#include "utlrbtree.h" + + +/* ../engine/ipratelimit.h:5 */ +class CIPRateLimit +{ +public: + /* ../engine/ipratelimit.h:8 */ + CIPRateLimit() { } + + /* ../engine/ipratelimit.h:9 */ + ~CIPRateLimit() { } + + /* ../engine/ipratelimit.h:12 */ + bool CheckIP(netadr_t adr); /* linkage=_ZN12CIPRateLimit7CheckIPE8netadr_s */ + +private: + + /* ../engine/ipratelimit.h:15 */ + enum + { + MAX_TREE_SIZE = 512, + START_TREE_SIZE = 256, + FLUSH_TIMEOUT = 120, + }; + + /* ../engine/ipratelimit.h:18 */ + typedef struct iprate_s + { + /* ../engine/ipratelimit.h:17 */ + typedef int ip_t; + + ip_t ip;/* 0 4 */ + long int lastTime;/* 4 4 */ + int count;/* 8 4 */ + } iprate_t;/* size: 12 */ + +private: + + class CUtlRBTree m_IPTree;/* 0 32 */ + int m_iGlobalCount;/* 32 4 */ + long int m_lLastTime;/* 36 4 */ + + /* ../engine/ipratelimit.h:25 */ + bool LessIP(const struct iprate_s &, const struct iprate_s &); /* linkage=_ZN12CIPRateLimit6LessIPERKNS_8iprate_sES2_ */ +};/* size: 40 */ + + +//extern bool (__fastcall *pCIPRateLimit__CheckIP)(CIPRateLimit *obj, int none, netadr_t adr); + +#endif // IPRATELIMIT_H diff --git a/rehlds/engine/ipratelimitWrapper.cpp b/rehlds/engine/ipratelimitWrapper.cpp new file mode 100644 index 0000000..fb4a56b --- /dev/null +++ b/rehlds/engine/ipratelimitWrapper.cpp @@ -0,0 +1,53 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +#ifdef HOOK_ENGINE +int (*pCheckIP)(netadr_t adr); +#endif //HOOK_ENGINE + +class CIPRateLimit rateChecker; + + +/* ../engine/ipratelimitWrapper.cpp:6 */ +int CheckIP(netadr_t adr) +{ +#ifdef HOOK_ENGINE + int res = pCheckIP(adr); + if (res != 1) + { + rehlds_syserror("CheckIP() is expected to return 1"); + } + return res; +#else + CRehldsPlatformHolder::get()->time(NULL); //time() is called inside IpRateLimiter + return 1; +#endif +} diff --git a/rehlds/engine/ipratelimitWrapper.h b/rehlds/engine/ipratelimitWrapper.h new file mode 100644 index 0000000..065d6d2 --- /dev/null +++ b/rehlds/engine/ipratelimitWrapper.h @@ -0,0 +1,46 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "maintypes.h" +#include "net.h" +#include "ipratelimit.h" + +#ifdef HOOK_ENGINE +#define rateChecker (*prateChecker) + +extern int(*pCheckIP)(netadr_t adr); +#endif //HOOK_ENGINE + +extern class CIPRateLimit rateChecker; + + +int CheckIP(netadr_t adr); + + + diff --git a/rehlds/engine/keys.h b/rehlds/engine/keys.h new file mode 100644 index 0000000..c8d48c6 --- /dev/null +++ b/rehlds/engine/keys.h @@ -0,0 +1,7 @@ +#pragma once + +typedef enum { + key_game = 0, + key_message = 1, + key_menu = 2, +} keydest_t; /* size: 4 */ diff --git a/rehlds/engine/l_studio.cpp b/rehlds/engine/l_studio.cpp new file mode 100644 index 0000000..29cf5e9 --- /dev/null +++ b/rehlds/engine/l_studio.cpp @@ -0,0 +1,92 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +//int giTextureSize; + + +/* <42900> ../engine/l_studio.c:31 */ +void Mod_LoadStudioModel_internal(model_t * mod, void * buffer) +{ + uint8_t *poutdata; + uint8_t *pindata; + mstudiotexture_t *ptexture; + int size; + int i; + uint8_t *pout; + + studiohdr_t * phdr = (studiohdr_t *)buffer; + i = LittleLong(phdr->version); + if (i != STUDIO_VERSION) + { + Q_memset(phdr, 0, 244u); + Q_strcpy(phdr->name, "bogus"); + phdr->length = 244; + phdr->texturedataindex = 244; + } + + mod->type = mod_studio; + mod->flags = phdr->flags; + Cache_Alloc(&mod->cache, phdr->length + 1280 * phdr->numtextures, mod->name); + pout = (uint8_t *)mod->cache.data; + if (pout) + { + if (phdr->textureindex) + { + Q_memcpy(pout, buffer, phdr->texturedataindex); + poutdata = pout + phdr->texturedataindex; + pindata = (uint8_t*)buffer + phdr->texturedataindex; + ptexture = (mstudiotexture_t *)(pout + phdr->textureindex); + for (i = 0; i < phdr->numtextures; i++, ptexture++) + { + size = ptexture->height * ptexture->width; + ptexture->index = poutdata - pout; + Q_memcpy(poutdata, pindata, size); + poutdata += size; + pindata += size; + + for (int j = 0; j < 256; j++, pindata += 3, poutdata += 8) + { + ((uint16_t*)poutdata)[0] = texgammatable[pindata[0]]; + ((uint16_t*)poutdata)[1] = texgammatable[pindata[1]]; + ((uint16_t*)poutdata)[2] = texgammatable[pindata[2]]; + ((uint16_t*)poutdata)[3] = 0; + } + } + } + else + { + Q_memcpy(pout, buffer, phdr->length); + } + } +} + +void Mod_LoadStudioModel(model_t * mod, void * buffer) { + g_RehldsHookchains.m_Mod_LoadStudioModel.callChain(&Mod_LoadStudioModel_internal, mod, buffer); +} diff --git a/rehlds/engine/l_studio.h b/rehlds/engine/l_studio.h new file mode 100644 index 0000000..95935e4 --- /dev/null +++ b/rehlds/engine/l_studio.h @@ -0,0 +1,49 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef L_STUDIO_H +#define L_STUDIO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "studio_rehlds.h" + +#define STUDIO_VERSION 10 + +#ifdef HOOK_ENGINE +//#define giTextureSize (*pgiTextureSize) +#endif //HOOK_ENGINE + +//extern int giTextureSize; + + +void Mod_LoadStudioModel(model_t * mod, void * buffer); + +#endif // L_STUDIO_H diff --git a/rehlds/engine/mathlib.cpp b/rehlds/engine/mathlib.cpp new file mode 100644 index 0000000..83dd6ce --- /dev/null +++ b/rehlds/engine/mathlib.cpp @@ -0,0 +1,467 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + + +vec3_t vec3_origin; +//int nanmask; +//short int new_cw; +//short int old_cw; +//DLONG dlong; + + +/* <46ebf> ../engine/mathlib.c:14 */ +float anglemod(float a) +{ + return (360.0 / 65536) * ((int)(a*(65536 / 360.0)) & 65535); +} + +/* <46eea> ../engine/mathlib.c:33 */ +void BOPS_Error(void) +{ + Sys_Error("BoxOnPlaneSide: Bad signbits"); +} + +/* <46f05> ../engine/mathlib.c:48 */ +int BoxOnPlaneSide(vec_t *emins, vec_t *emaxs, mplane_t *p) +{ +#if (1) + // Engine actual types + double dist1, dist2; +#else + // From sources + float dist1, dist2; +#endif + int sides = 0; + + // general case + switch (p->signbits) + { + case 0: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; + break; + case 1: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; + break; + case 2: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; + break; + case 3: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; + break; + case 4: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; + break; + case 5: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emaxs[2]; + break; + case 6: + dist1 = p->normal[0] * emaxs[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emins[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; + break; + case 7: + dist1 = p->normal[0] * emins[0] + p->normal[1] * emins[1] + p->normal[2] * emins[2]; + dist2 = p->normal[0] * emaxs[0] + p->normal[1] * emaxs[1] + p->normal[2] * emaxs[2]; + break; + default: + BOPS_Error(); + dist1 = dist2 = 0.0; + break; + } + + if (dist1 >= p->dist) + sides = 1; + if (dist2 < p->dist) + sides |= 2; + + return sides; +} + +/* <46f8d> ../engine/mathlib.c:157 */ +NOBODY int InvertMatrix(const float *m, float *out); +//{ +// float wtmp; // 159 +// float m0; // 160 +// float m1; // 160 +// float m2; // 160 +// float m3; // 160 +// float s; // 160 +// float *r0; // 161 +// float *r1; // 161 +// float *r2; // 161 +// float *r3; // 161 +//} + +/* <47067> ../engine/mathlib.c:267 */ +void AngleVectors(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + +#ifndef SWDS + g_engdstAddrs.pfnAngleVectors(&angles, &forward, &right, &up); +#endif // SWDS + + angle = (float)(angles[YAW] * (M_PI * 2 / 360)); + sy = sin(angle); + cy = cos(angle); + angle = (float)(angles[PITCH] * (M_PI * 2 / 360)); + sp = sin(angle); + cp = cos(angle); + angle = (float)(angles[ROLL] * (M_PI * 2 / 360)); + sr = sin(angle); + cr = cos(angle); + + if (forward) + { + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + } + if (right) + { + right[0] = (-1 * sr*sp*cy + -1 * cr*-sy); + right[1] = (-1 * sr*sp*sy + -1 * cr*cy); + right[2] = -1 * sr*cp; + } + if (up) + { + up[0] = (cr*sp*cy + -sr*-sy); + up[1] = (cr*sp*sy + -sr*cy); + up[2] = cr*cp; + } +} + +/* <4712e> ../engine/mathlib.c:304 */ +void AngleVectorsTranspose(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = (float)(angles[YAW] * (M_PI * 2 / 360)); + sy = sin(angle); + cy = cos(angle); + angle = (float)(angles[PITCH] * (M_PI * 2 / 360)); + sp = sin(angle); + cp = cos(angle); + angle = (float)(angles[ROLL] * (M_PI * 2 / 360)); + sr = sin(angle); + cr = cos(angle); + + if (forward) + { + forward[0] = cp*cy; + forward[1] = (sr*sp*cy + cr*-sy); + forward[2] = (cr*sp*cy + -sr*-sy); + } + if (right) + { + right[0] = cp*sy; + right[1] = (sr*sp*sy + cr*cy); + right[2] = (cr*sp*sy + -sr*cy); + } + if (up) + { + up[0] = -sp; + up[1] = sr*cp; + up[2] = cr*cp; + } +} + +/* <471e9> ../engine/mathlib.c:340 */ +void AngleMatrix(const vec_t *angles, float(*matrix)[4]) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = (float)(angles[2] * (M_PI * 2 / 360)); + sy = sin(angle); + cy = cos(angle); + angle = (float)(angles[1] * (M_PI * 2 / 360)); + sp = sin(angle); + cp = cos(angle); + angle = (float)(angles[0] * (M_PI * 2 / 360)); + sr = sin(angle); + cr = cos(angle); + + float tmp1, tmp2; + + matrix[0][0] = cr * cp; + matrix[1][0] = cr * sp; + matrix[2][0] = -sr; + + tmp1 = sy * sr; + matrix[0][1] = tmp1 * cp - cy * sp; + matrix[1][1] = tmp1 * sp + cy * cp; + matrix[2][1] = sy * cr; + + tmp2 = cy * sr; + matrix[0][2] = tmp2 * cp + sy * sp; + matrix[1][2] = tmp2 * sp - sy * cp; + matrix[2][2] = cy * cr; + + matrix[0][3] = 0.0f; + matrix[1][3] = 0.0f; + matrix[2][3] = 0.0f; + +} + +/* <4729e> ../engine/mathlib.c:370 */ +NOBODY void AngleIMatrix(const vec_t *angles, float *matrix); +//{ +// float angle; // 372 +// float sr; // 373 +// float sp; // 373 +// float sy; // 373 +// float cr; // 373 +// float cp; // 373 +// float cy; // 373 +//} + +/* <4733d> ../engine/mathlib.c:400 */ +NOBODY void NormalizeAngles(float *angles); +//{ +// int i; // 402 +//} + +/* <47389> ../engine/mathlib.c:426 */ +NOBODY void InterpolateAngles(float *start, float *end, float *output, float frac); +//{ +// int i; // 428 +// float ang1; // 429 +// float ang2; // 429 +// float d; // 430 +// NormalizeAngles(float *angles); /* size=0, low_pc=0 */ // 432 +// NormalizeAngles(float *angles); /* size=0, low_pc=0 */ // 433 +// NormalizeAngles(float *angles); /* size=0, low_pc=0 */ // 453 +//} + +/* <47495> ../engine/mathlib.c:457 */ +void VectorTransform(const vec_t *in1, float *in2, vec_t *out) +{ + out[0] = in2[1] * in1[1] + in2[2] * in1[2] + in1[0] * in2[0] + in2[3]; + out[1] = in2[4] * in1[0] + in2[5] * in1[1] + in2[6] * in1[2] + in2[7]; + out[2] = in2[8] * in1[0] + in2[9] * in1[1] + in2[10] * in1[2] + in2[11]; +} + +/* <474dc> ../engine/mathlib.c:465 */ +int VectorCompare(const vec_t *v1, const vec_t *v2) +{ + for (int i = 0; i < 3; i++) + { + if (v1[i] != v2[i]) return 0; + } + + return 1; +} + +/* <47524> ../engine/mathlib.c:476 */ +void VectorMA(const vec_t *veca, float scale, const vec_t *vecb, vec_t *vecc) +{ + vecc[0] = scale * vecb[0] + veca[0]; + vecc[1] = scale * vecb[1] + veca[1]; + vecc[2] = scale * vecb[2] + veca[2]; +} + +/* <4757a> ../engine/mathlib.c:484 */ +float _DotProduct(vec_t *v1, vec_t *v2) +{ + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} + +/* <475b4> ../engine/mathlib.c:489 */ +NOBODY void _VectorSubtract(vec_t *veca, vec_t *vecb, vec_t *out); +//{ +//} + +/* <475fb> ../engine/mathlib.c:496 */ +void _VectorAdd(vec_t *veca, vec_t *vecb, vec_t *out) +{ + for (int i = 0; i < 3; i++) { + out[i] = veca[i] + vecb[i]; + } +} + +/* <47642> ../engine/mathlib.c:503 */ +NOBODY void _VectorCopy(vec_t *in, vec_t *out); +//{ +//} + +/* <47679> ../engine/mathlib.c:510 */ +void CrossProduct(const vec_t *v1, const vec_t *v2, vec_t *cross) +{ + cross[0] = v2[2] * v1[1] - v1[2] * v2[1]; + cross[1] = v1[2] * v2[0] - v1[0] * v2[2]; + cross[2] = v1[0] * v2[1] - v2[0] * v1[1]; +} + +/* <476d8> ../engine/mathlib.c:519 */ +float Length(const vec_t *v) +{ + float length; + + length = 0.0f; + for (int i = 0; i < 3; i++) + { + length = v[i] * v[i] + length; + } + return sqrt(length); +} + +/* <47722> ../engine/mathlib.c:532 */ +float VectorNormalize(vec3_t v) +{ + float length, ilength; + + length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; + length = sqrt(length); // FIXME + + if (length) + { + ilength = 1 / length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; +} + +/* <47788> ../engine/mathlib.c:551 */ +NOBODY void VectorInverse(vec_t *v); +//{ +//} + +/* <477af> ../engine/mathlib.c:558 */ +void VectorScale(const vec_t *in, float scale, vec_t *out) +{ + out[0] = scale * in[0]; + out[1] = scale * in[1]; + out[2] = scale * in[2]; +} + +/* <477f5> ../engine/mathlib.c:566 */ +NOBODY int Q_log2(int val); +//{ +// int answer; // 568 +//} + +/* <47833> ../engine/mathlib.c:574 */ +NOBODY void VectorMatrix(vec_t *forward, vec_t *right, vec_t *up); +//{ +// vec3_t tmp; // 576 +// CrossProduct(const vec_t *v1, +// const vec_t *v2, +// vec_t *cross); /* size=0, low_pc=0 */ // 590 +// VectorNormalize(vec_t *v); /* size=0, low_pc=0 */ // 591 +// CrossProduct(const vec_t *v1, +// const vec_t *v2, +// vec_t *cross); /* size=0, low_pc=0 */ // 592 +// VectorNormalize(vec_t *v); /* size=0, low_pc=0 */ // 593 +//} + +/* <4794e> ../engine/mathlib.c:597 */ +void VectorAngles(const vec_t *forward, vec_t *angles) +{ + float tmp, yaw, pitch; + + if (forward[1] == 0 && forward[0] == 0) + { + yaw = 0; + if (forward[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (atan2((double)forward[1], (double)forward[0]) * 180.0 / M_PI); + if (yaw < 0) + yaw += 360; + + tmp = sqrt((double)(forward[0] * forward[0] + forward[1] * forward[1])); + pitch = (atan2((double)forward[2], (double)tmp) * 180.0 / M_PI); + if (pitch < 0) + pitch += 360; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = 0; +} + +/* <479b7> ../engine/mathlib.c:632 */ +NOBODY void R_ConcatRotations(float *in1, float *in2, float *out); +//{ +// +//} + +/* <47a04> ../engine/mathlib.c:660 */ +void R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3]; +} + +/* <47a4b> ../engine/mathlib.c:699 */ +NOBODY void FloorDivMod(double numer, double denom, int *quotient, int *rem); +//{ +// int q; // 702 +// int r; // 702 +// double x; // 703 +// floor(double __x); /* size=0, low_pc=0 */ // 726 +// floor(double __x); /* size=0, low_pc=0 */ // 717 +//} + +/* <47b4c> ../engine/mathlib.c:746 */ +NOBODY int GreatestCommonDivisor(int i1, int i2); +//{ +//} + +/* <47b87> ../engine/mathlib.c:775 */ +NOBODY fixed16_t Invert24To16(fixed16_t val); +//{ +//} diff --git a/rehlds/engine/mathlib_e.h b/rehlds/engine/mathlib_e.h new file mode 100644 index 0000000..8df6f1a --- /dev/null +++ b/rehlds/engine/mathlib_e.h @@ -0,0 +1,90 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef MATHLIB_E_H +#define MATHLIB_E_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "model.h" + +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 + +#ifdef HOOK_ENGINE +#define vec3_origin (*pvec3_origin) + +#endif // HOOK_ENGINE + + +extern vec3_t vec3_origin; + +static const int nanmask = 0x7F800000; + +#define IS_NAN(fvar) ((*reinterpret_cast(&(fvar)) & nanmask) == nanmask) + + +float anglemod(float a); +void BOPS_Error(void); + +int BoxOnPlaneSide(vec_t *emins, vec_t *emaxs, mplane_t *p); +NOBODY int InvertMatrix(const float *m, float *out); +void AngleVectors(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up); +void AngleVectorsTranspose(const vec_t *angles, vec_t *forward, vec_t *right, vec_t *up); +void AngleMatrix(const vec_t *angles, float(*matrix)[4]); +NOBODY void AngleIMatrix(const vec_t *angles, float *matrix); +NOBODY void NormalizeAngles(float *angles); +NOBODY void InterpolateAngles(float *start, float *end, float *output, float frac); +void VectorTransform(const vec_t *in1, float *in2, vec_t *out); +int VectorCompare(const vec_t *v1, const vec_t *v2); +void VectorMA(const vec_t *veca, float scale, const vec_t *vecb, vec_t *vecc); +NOBODY float _DotProduct(vec_t *v1, vec_t *v2); +NOBODY void _VectorSubtract(vec_t *veca, vec_t *vecb, vec_t *out); +void _VectorAdd(vec_t *veca, vec_t *vecb, vec_t *out); +NOBODY void _VectorCopy(vec_t *in, vec_t *out); +void CrossProduct(const vec_t *v1, const vec_t *v2, vec_t *cross); +float Length(const vec_t *v); +float VectorNormalize(vec_t *v); +NOBODY void VectorInverse(vec_t *v); +void VectorScale(const vec_t *in, float scale, vec_t *out); +NOBODY int Q_log2(int val); +NOBODY void VectorMatrix(vec_t *forward, vec_t *right, vec_t *up); +void VectorAngles(const vec_t *forward, vec_t *angles); +NOBODY void R_ConcatRotations(float *in1, float *in2, float *out); +void R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4]); +NOBODY void FloorDivMod(double numer, double denom, int *quotient, int *rem); +NOBODY int GreatestCommonDivisor(int i1, int i2); +NOBODY fixed16_t Invert24To16(fixed16_t val); + +#endif // MATHLIB_E_H diff --git a/rehlds/engine/mem.cpp b/rehlds/engine/mem.cpp new file mode 100644 index 0000000..fed81d3 --- /dev/null +++ b/rehlds/engine/mem.cpp @@ -0,0 +1,68 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +/* <47cf1> ../engine/mem.c:8 */ +void *Mem_Malloc(size_t size) +{ + return malloc(size); +} + +/* <47d1c> ../engine/mem.c:13 */ +void *Mem_ZeroMalloc(size_t size) +{ + void *p = malloc(size); + memset(p, 0, size); + return p; +} + +/* <47d55> ../engine/mem.c:23 */ +void *Mem_Realloc(void *memblock, size_t size) +{ + return realloc(memblock, size); +} + +/* <47d8e> ../engine/mem.c:28 */ +void *Mem_Calloc(int num, size_t size) +{ + return calloc(num, size); +} + +/* <47dc7> ../engine/mem.c:33 */ +char *Mem_Strdup(const char *strSource) +{ + return _strdup(strSource); +} + +/* <47df2> ../engine/mem.c:38 */ +void Mem_Free(void *p) +{ + free(p); +} diff --git a/rehlds/engine/mem.h b/rehlds/engine/mem.h new file mode 100644 index 0000000..65b40a9 --- /dev/null +++ b/rehlds/engine/mem.h @@ -0,0 +1,43 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef MEM__H +#define MEM__H +#ifdef _WIN32 +#pragma once +#endif + + +void *Mem_Malloc(size_t size); +void *Mem_ZeroMalloc(size_t size); +void *Mem_Realloc(void *memblock, size_t size); +void *Mem_Calloc(int num, size_t size); +char *Mem_Strdup(const char *strSource); +void Mem_Free(void *p); + +#endif // MEM__H diff --git a/rehlds/engine/model.cpp b/rehlds/engine/model.cpp new file mode 100644 index 0000000..e15d455 --- /dev/null +++ b/rehlds/engine/model.cpp @@ -0,0 +1,1903 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +model_t *loadmodel; +char loadname[32]; +model_t mod_known[MAX_KNOWN_MODELS]; +int mod_numknown; +unsigned char* mod_base; +char *wadpath; +int tested; +int ad_enabled; +cachewad_t ad_wad; +mod_known_info_t mod_known_info[MAX_KNOWN_MODELS]; + +// values for model_t's needload +#define NL_PRESENT 0 +#define NL_NEEDS_LOADED 1 +#define NL_UNREFERENCED 2 + + +/* <51468> ../engine/model.c:147 */ +void SW_Mod_Init(void) +{ +#ifndef SWDS + // TODO: Add client-side code +#endif +} + +/* <52f8d> ../engine/model.c:164 */ +void *Mod_Extradata(model_t *mod) +{ + void *r; + + if (!mod) + { + return NULL; + } + + r = Cache_Check(&mod->cache); + if (r) + { + return r; + } + + if (mod->type == mod_brush) + { + Sys_Error(__FUNCTION__ ": called with mod_brush!\n"); + } + + Mod_LoadModel(mod, 1, 0); + + if (mod->cache.data == NULL) + { + Sys_Error(__FUNCTION__ ": caching failed"); + } + + return mod->cache.data; +} + +/* <5147c> ../engine/model.c:190 */ +mleaf_t *Mod_PointInLeaf(vec_t *p, model_t *model) +{ + mnode_t *node; // 192 + float d; // 193 + mplane_t *plane; // 194 + + if (!model || !model->nodes) + Sys_Error(__FUNCTION__ ": bad model"); + + node = model->nodes; + while (node->contents >= 0) + { + plane = node->plane; + if (plane->type >= 3u) + d = plane->normal[2] * p[2] + plane->normal[1] * p[1] + plane->normal[0] * p[0] - plane->dist; + else + d = p[plane->type] - plane->dist; + + if (d <= 0.0) + node = node->children[1]; + else + node = node->children[0]; + } + return (mleaf_t *)node; +} + +/* <514e5> ../engine/model.c:226 */ +void Mod_ClearAll(void) +{ + int i; + model_t *mod; + for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) + { + if (mod->type != mod_alias && mod->needload != (NL_NEEDS_LOADED | NL_UNREFERENCED)) + { + mod->needload = NL_UNREFERENCED; + if (mod->type == mod_sprite) + mod->cache.data = NULL; + } + } +} + +/* <5151a> ../engine/model.c:248 */ +void Mod_FillInCRCInfo(qboolean trackCRC, int model_number) +{ + mod_known_info_t *p; + + p = &mod_known_info[model_number]; + p->shouldCRC = trackCRC; + p->firstCRCDone = 0; + p->initialCRC = 0; +} + +/* <51546> ../engine/model.c:264 */ +model_t *Mod_FindName(qboolean trackCRC, const char *name) +{ + model_t *avail; + int i; + model_t *mod; + + avail = NULL; + if (!name[0]) + Sys_Error("Mod_ForName: NULL name"); + + for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) + { + if (!Q_stricmp(mod->name, name)) + break; + + if (mod->needload == NL_UNREFERENCED) + { + if (!avail || mod->type != mod_alias && mod->type != mod_studio) + avail = mod; + } + } + + if (i == mod_numknown) + { + if (mod_numknown < MAX_KNOWN_MODELS) + { + Mod_FillInCRCInfo(trackCRC, mod_numknown); + ++mod_numknown; + } + else + { + if (!avail) + Sys_Error("mod_numknown >= MAX_KNOWN_MODELS"); + mod = avail; + Mod_FillInCRCInfo(trackCRC, avail - mod_known); + } + Q_strncpy(mod->name, name, 63); + mod->name[63] = 0; + + if (mod->needload != (NL_NEEDS_LOADED | NL_UNREFERENCED)) + mod->needload = NL_NEEDS_LOADED; + } + + return mod; +} + +/* <51615> ../engine/model.c:329 */ +NOXREF qboolean Mod_ValidateCRC(const char *name, CRC32_t crc) +{ + model_t *mod; + mod_known_info_t *p; + + mod = Mod_FindName(TRUE, name); + p = &mod_known_info[mod - mod_known]; + + if (p->firstCRCDone) + { + if (p->initialCRC != crc) + return FALSE; + } + return TRUE; +} + +/* <5166e> ../engine/model.c:362 */ +NOXREF void Mod_NeedCRC(const char *name, qboolean needCRC) +{ + model_t *mod; + mod_known_info_t *p; + + mod = Mod_FindName(FALSE, name); + p = &mod_known_info[mod - mod_known]; + + p->shouldCRC = needCRC; +} + + +//TODO: move to czmodelcheck.cpp +qboolean IsCZPlayerModel(uint32 crc, const char * filename) +{ + if (crc == 0x27FB4D2F) + return Q_stricmp(filename, "models/player/spetsnaz/spetsnaz.mdl") ? 0 : 1; + + if (crc == 0xEC43F76D || crc == 0x270FB2D7) + return Q_stricmp(filename, "models/player/terror/terror.mdl") ? 0 : 1; + + if (crc == 0x1AAA3360 || crc == 0x35AC6FED) + return Q_stricmp(filename, "models/player/gign/gign.mdl") ? 0 : 1; + + if (crc == 0x02B95E5F || crc == 0x72DB74E4) + return Q_stricmp(filename, "models/player/vip/vip.mdl") ? 0 : 1; + + if (crc == 0x1F3CD80B || crc == 0x1B6C4115) + return Q_stricmp(filename, "models/player/guerilla/guerilla.mdl") ? 0 : 1; + + if (crc == 0x3BCAA016) + return Q_stricmp(filename, "models/player/militia/militia.mdl") ? 0 : 1; + + if (crc == 0x43E67FF3 || crc == 0xF141AE3F) + return Q_stricmp(filename, "models/player/sas/sas.mdl") ? 0 : 1; + + if (crc == 0xDA8922A || crc == 0x56DD2D02) + return Q_stricmp(filename, "models/player/gsg9/gsg9.mdl") ? 0 : 1; + + if (crc == 0xA37D8680 || crc == 0x4986827B) + return Q_stricmp(filename, "models/player/arctic/arctic.mdl") ? 0 : 1; + + if (crc == 0xC37369F6 || crc == 0x29FE156C) + return Q_stricmp(filename, "models/player/leet/leet.mdl") ? 0 : 1; + + if (crc == 0xC7F0DBF3 || crc == 0x068168DB) + return Q_stricmp(filename, "models/player/urban/urban.mdl") ? 0 : 1; + + return 0; +} + +/* <513ce> ../engine/model.c:394 */ +model_t *Mod_LoadModel(model_t *mod, qboolean crash, qboolean trackCRC) +{ + unsigned char *buf; + char tmpName[260]; + int length; + CRC32_t currentCRC; + + if (mod->type == mod_alias || mod->type == mod_studio) + { + if (Cache_Check(&mod->cache)) + { + mod->needload = NL_PRESENT; + return mod; + } + } + else + { + if (mod->needload == NL_PRESENT || mod->needload == (NL_NEEDS_LOADED | NL_UNREFERENCED)) + return mod; + } + + if (COM_CheckParm("-steam") && mod->name[0] == '/') + { + char* p = mod->name; + while (*(p++) == '/') + ; + + strncpy(tmpName, p, 259); + tmpName[259] = 0; + + strncpy(mod->name, tmpName, 63); + mod->name[63] = 0; + } + + buf = COM_LoadFileForMe(mod->name, &length); + if (!buf) + { + if (crash) + Sys_Error("Mod_NumForName: %s not found", mod->name); + return 0; + } + + + if (trackCRC) + { + mod_known_info_t *p = &mod_known_info[mod - mod_known]; + if (p->shouldCRC) + { + CRC32_Init(¤tCRC); + CRC32_ProcessBuffer(¤tCRC, buf, length); + currentCRC = CRC32_Final(currentCRC); + if (p->firstCRCDone) + { + if (currentCRC != p->initialCRC) + { + Sys_Error("%s has been modified since starting the engine. Consider running system diagnostics to check for faulty hardware.\n", mod->name); + } + } + else + { + p->firstCRCDone = 1; + p->initialCRC = currentCRC; + SetCStrikeFlags(); + + if (!IsGameSubscribed("czero") && g_bIsCStrike && IsCZPlayerModel(currentCRC, mod->name) && g_pcls.state) + { + COM_ExplainDisconnection(TRUE, "Cannot continue with altered model %s, disconnecting.", mod->name); + CL_Disconnect(); + return 0; + } + } + } + } + + if (developer.value > 1.0) + Con_DPrintf("loading %s\n", mod->name); + + COM_FileBase(mod->name, loadname); + loadmodel = mod; + mod->needload = NL_PRESENT; + + switch (LittleLong(*(uint32_t *)buf)) + { + case 'OPDI': + Sys_Error(__FUNCTION__ "Alias models are not supported"); + break; + case 'PSDI': + Mod_LoadSpriteModel(mod, (dsprite_t *)buf); + break; + case 'TSDI': + Mod_LoadStudioModel(mod, (studiohdr_t *)buf); + break; + default: + Mod_LoadBrushModel(mod, (dheader_t *)buf); + break; + } + + if (g_modfuncs.m_pfnModelLoad) + g_modfuncs.m_pfnModelLoad(mod, buf); + + Mem_Free(buf); + + return mod; +} + +/* <516c5> ../engine/model.c:540 */ +NOXREF void Mod_MarkClient(model_t *pModel) +{ + pModel->needload = (NL_NEEDS_LOADED | NL_UNREFERENCED); +} + +/* <52edc> ../engine/model.c:552 */ +model_t *Mod_ForName(const char *name, qboolean crash, qboolean trackCRC) +{ + model_t *mod; + + mod = Mod_FindName(trackCRC, name); + if (!mod) + return NULL; + + return Mod_LoadModel(mod, crash, trackCRC); +} + +/* <516ee> ../engine/model.c:589 */ +void Mod_AdInit(void) +{ + int i; + char *s; + static char filename[260]; + + tested = 1; + i = COM_CheckParm("-ad"); + if (i) + { + s = com_argv[i + 1]; + if (s && *s) + { + _snprintf(filename, 0x104u, "%s", s); + if (FS_FileSize(filename) > 0) + { + Sys_Error("Mod_Init(): reverse me"); + /* + Draw_CacheWadInit(filename, 16, &ad_wad); + sub_1D34290(&ad_wad, (void(__cdecl *)(cachewad_t *, unsigned __int8 *))sub_1D3A830, 24); + ad_enabled = 1; + */ + } + else + { + Con_Printf("No -ad file specified, skipping\n"); + } + } + } +} + +/* <51751> ../engine/model.c:621 */ +void Mod_AdSwap(texture_t *src, int pixels, int entries) +{ +// int j; // 623 +// unsigned char *mippal; // 624 +// short unsigned int *texpal; // 625 +// texture_t *tex; // 626 + Sys_Error(__FUNCTION__ ": Reverse me"); +} + +/* <51803> ../engine/model.c:656 */ +void Mod_LoadTextures(lump_t *l) +{ + dmiptexlump_t *m; + miptex_t *mt; + int palette; + int pixels; + uint8_t *mippal; + uint16_t *texpal; + int max; + texture_t *tx2; + int num; + char dtexdata[348996]; + texture_t *anims[10]; + texture_t *altanims[10]; + double starttime; + qboolean wads_parsed; + texture_t *tx; + + wads_parsed = 0; + starttime = Sys_FloatTime(); + if (!tested) + Mod_AdInit(); + + if (!l->filelen) + { + loadmodel->textures = 0; + return; + } + m = (dmiptexlump_t *)(mod_base + l->fileofs); + + m->_nummiptex = LittleLong(m->_nummiptex); + loadmodel->numtextures = m->_nummiptex; + loadmodel->textures = (texture_t **)Hunk_AllocName(4 * loadmodel->numtextures, loadname); + + for (int i = 0; i < m->_nummiptex; i++) + { + m->dataofs[i] = LittleLong(m->dataofs[i]); + if (m->dataofs[i] == -1) + continue; + + mt = (miptex_t *)((char *)m + m->dataofs[i]); + if (r_wadtextures.value != 0.0 || !LittleLong(mt->offsets[0])) + { + if (!wads_parsed) + { + TEX_InitFromWad(wadpath); + TEX_AddAnimatingTextures(); + wads_parsed = 1; + } + if (!TEX_LoadLump(mt->name, (unsigned char *)dtexdata)) + { + m->dataofs[i] = -1; + continue; + } + mt = (miptex_t *)dtexdata; + } + + for (int j = 0; j < MIPLEVELS; j++) + mt->offsets[j] = LittleLong(mt->offsets[j]); + + mt->width = LittleLong(mt->width); + mt->height = LittleLong(mt->height); + if (mt->width & 0xF || mt->height & 0xF) + Sys_Error("Texture %s is not 16 aligned", mt); + + pixels = 85 * mt->height * mt->width / 64; + palette = *(uint16_t*)((char*)mt + sizeof(miptex_t) + pixels); + + tx = (texture_t *)Hunk_AllocName(2 + 8 * palette + pixels + sizeof(texture_t), loadname); + loadmodel->textures[i] = tx; + + Q_memcpy(tx->name, mt->name, sizeof(tx->name)); + if (strchr(tx->name, '~')) + tx->name[2] = ' '; + + tx->width = mt->width; + tx->height = mt->height; + + for (int j = 0; j < MIPLEVELS; j++) + tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); + + tx->paloffset = sizeof(texture_t) + pixels + 2; + Q_memcpy(&tx[1], &mt[1], pixels + 2); //copy pixels & palette size (2) + + if (!Q_strncmp(mt->name, "sky", 3)) + { + //R_InitSky(); + } + + mippal = (uint8_t *)&mt[1] + pixels + 2; + texpal = (uint16_t *)((char*)&tx[1] + pixels + 2); + for (int j = 0; j < palette; j++, mippal += 3, texpal += 4) + { + texpal[0] = texgammatable[mippal[2]]; + texpal[1] = texgammatable[mippal[1]]; + texpal[2] = texgammatable[mippal[0]]; + texpal[3] = 0; + } + + if (ad_enabled && !Q_stricmp(tx->name, "DEFAULT")) + Mod_AdSwap(tx, pixels, palette); + } + + if (wads_parsed) + TEX_CleanupWadInfo(); + + for (int i = 0; i < m->_nummiptex; i++) + { + tx = loadmodel->textures[i]; + if (!tx) + continue; + + if (tx->name[0] != '+' && tx->name[0] != '-') + continue; + + if (tx->anim_next) + continue; + + Q_memset(anims, 0, sizeof(anims)); + Q_memset(altanims, 0, sizeof(altanims)); + max = tx->name[1]; + int altmax = 0; + if (max >= 'a' && max <= 'z') + max -= 32; + if (max < '0' || max > '9') + { + if (max < 'A' || max > 'J') + Sys_Error("Bad animating texture %s", tx); + altmax = max - 'A'; + max = 0; + altanims[altmax] = tx; + altmax++; + } + else + { + max -= '0'; + altmax = 0; + anims[max] = tx; + max++; + } + + for (int j = i + 1; j < m->_nummiptex; j++) + { + tx2 = loadmodel->textures[j]; + if (!tx2) + continue; + + if (tx2->name[0] != '+' && tx2->name[0] != '-') + continue; + + if (Q_strcmp(&tx2->name[2], &tx->name[2])) + continue; + + num = tx2->name[1]; + if (num >= 'a' && num <= 'z') + num -= 'a' - 'A'; + + if (num < '0' || num > '9') + { + if (num < 'A' || num > 'J') + Sys_Error("Bad animating texture %s", tx); + + num -= 'A'; + altanims[num] = tx2; + if ((num + 1) > altmax) + altmax = num + 1; + } + else + { + num -= '0'; + anims[num] = tx2; + if ((num + 1) > max) + max = num + 1; + } + + } + + for (int j = 0; j < max; j++) + { + tx2 = anims[j]; + if (!tx2) + Sys_Error("Missing frame %i of %s", j, tx); + tx2->anim_min = j; + tx2->anim_total = max; + tx2->anim_max = j + 1; + tx2->anim_next = anims[(j + 1) % max]; + if (altmax) + tx2->alternate_anims = altanims[0]; + } + + for (int j = 0; j < altmax; j++) + { + tx2 = altanims[j]; + if (!tx2) + Sys_Error("Missing frame %i of %s", j, tx); + + tx2->anim_min = j; + tx2->anim_total = altmax; + tx2->anim_max = j + 1; + tx2->anim_next = altanims[(j + 1) % altmax]; + if (max) + tx2->alternate_anims = anims[0]; + } + } + + Con_DPrintf("Texture load: %6.1fms\n", (Sys_FloatTime() - starttime) * 1000.0); +} + +/* <51386> ../engine/model.c:878 */ +void Mod_LoadLighting(lump_t *l) +{ + if (l->filelen) + { + loadmodel->lightdata = (color24 *)Hunk_AllocName(l->filelen, loadname); + Q_memcpy(loadmodel->lightdata, (const void *)(mod_base + l->fileofs), l->filelen); + } + else + { + loadmodel->lightdata = 0; + } +} + +/* <519f8> ../engine/model.c:895 */ +void Mod_LoadVisibility(lump_t *l) +{ + if (!l->filelen) + { + loadmodel->visdata = NULL; + return; + } + loadmodel->visdata = (byte*) Hunk_AllocName(l->filelen, loadname); + memcpy(loadmodel->visdata, mod_base + l->fileofs, l->filelen); +} + +/* <513a6> ../engine/model.c:913 */ +void Mod_LoadEntities(lump_t *l) +{ + if (!l->filelen) + { + loadmodel->entities = NULL; + return; + } + + loadmodel->entities = (char *)Hunk_AllocName(l->filelen, loadname); + Q_memcpy(loadmodel->entities, (const void *)(mod_base + l->fileofs), l->filelen); + if (loadmodel->entities) + { + char *pszInputStream = COM_Parse(loadmodel->entities); + if (*pszInputStream) + { + while (com_token[0] != '}') + { + if (!Q_strcmp(com_token, "wad")) + { + COM_Parse(pszInputStream); + if (wadpath) + Mem_Free(wadpath); + wadpath = Mem_Strdup(com_token); + return; + } + pszInputStream = COM_Parse(pszInputStream); + if (!*pszInputStream) + return; + } + } + } + +} + +/* <51a67> ../engine/model.c:950 */ +void Mod_LoadVertexes(lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; + + in = (dvertex_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (mvertex_t*) Hunk_AllocName(count * sizeof(*out), loadname); + + loadmodel->vertexes = out; + loadmodel->numvertexes = count; + + for (i = 0; i < count; i++, in++, out++) + { + out->position[0] = LittleFloat(in->point[0]); + out->position[1] = LittleFloat(in->point[1]); + out->position[2] = LittleFloat(in->point[2]); + } +} + +/* <51ad2> ../engine/model.c:978 */ +void Mod_LoadSubmodels(lump_t *l) +{ + dmodel_t *in; + dmodel_t *out; + int i, j, count; + + in = (dmodel_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (dmodel_t *)Hunk_AllocName(count*sizeof(*out), loadname); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for (i = 0; i < count; i++, in++, out++) + { + for (j = 0; j < 3; j++) + { // spread the mins / maxs by a pixel + out->mins[j] = LittleFloat(in->mins[j]) - 1; + out->maxs[j] = LittleFloat(in->maxs[j]) + 1; + out->origin[j] = LittleFloat(in->origin[j]); + } + for (j = 0; j < MAX_MAP_HULLS; j++) + out->headnode[j] = LittleLong(in->headnode[j]); + out->visleafs = LittleLong(in->visleafs); + out->firstface = LittleLong(in->firstface); + out->numfaces = LittleLong(in->numfaces); + } +} + +/* <51b45> ../engine/model.c:1014 */ +void Mod_LoadEdges(lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (dedge_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (medge_t*) Hunk_AllocName((count + 1) * sizeof(*out), loadname); + + loadmodel->edges = out; + loadmodel->numedges = count; + + for (i = 0; i < count; i++, in++, out++) + { + out->v[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + } +} + +/* <51bb0> ../engine/model.c:1041 */ +void Mod_LoadTexinfo(lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out; + int i, j, count; + int _miptex; + float len1, len2; + + in = (texinfo_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (mtexinfo_t*) Hunk_AllocName(count*sizeof(*out), loadname); + + loadmodel->texinfo = out; + loadmodel->numtexinfo = count; + + for (i = 0; i < count; i++, in++, out++) + { +#ifdef REHLDS_FIXES + + for (j = 0; j < 4; j++) + { + out->vecs[0][j] = LittleFloat(in->vecs[0][j]); + out->vecs[1][j] = LittleFloat(in->vecs[1][j]); + } + +#else + for (j = 0; j < 8; j++) + out->vecs[0][j] = LittleFloat(in->vecs[0][j]); +#endif // REHLDS_FIXES + + len1 = Length(out->vecs[0]); + len2 = Length(out->vecs[1]); + len1 = (len1 + len2) / 2; + if (len1 < 0.32) + out->mipadjust = 4; + else if (len1 < 0.49) + out->mipadjust = 3; + else if (len1 < 0.99) + out->mipadjust = 2; + else + out->mipadjust = 1; + + _miptex = LittleLong(in->_miptex); + out->flags = LittleLong(in->flags); + + if (!loadmodel->textures) + { + out->texture = r_notexture_mip; // checkerboard texture + out->flags = 0; + } + else + { + if (_miptex >= loadmodel->numtextures) + Sys_Error("miptex >= loadmodel->numtextures"); + out->texture = loadmodel->textures[_miptex]; + if (!out->texture) + { + out->texture = r_notexture_mip; // texture not found + out->flags = 0; + } + } + } +} + +/* <51c59> ../engine/model.c:1109 */ +void CalcSurfaceExtents(msurface_t *s) +{ + float mins[2], maxs[2], val; + int i, j, e; + mvertex_t *v; + mtexinfo_t *tex; + int bmins[2], bmaxs[2]; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = s->texinfo; + + for (i = 0; i < s->numedges; i++) + { + e = loadmodel->surfedges[s->firstedge + i]; + if (e >= 0) + v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + + for (j = 0; j < 2; j++) + { + val = v->position[0] * tex->vecs[j][0] + + v->position[1] * tex->vecs[j][1] + + v->position[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i = 0; i < 2; i++) + { + bmins[i] = (int) floor(mins[i] / 16); + bmaxs[i] = (int) ceil(maxs[i] / 16); + + s->texturemins[i] = bmins[i] * 16; + s->extents[i] = (bmaxs[i] - bmins[i]) * 16; + if (!(tex->flags & TEX_SPECIAL) && s->extents[i] > 256) + Sys_Error("Bad surface extents"); + } +} + +/* <51d09> ../engine/model.c:1161 */ +void Mod_LoadFaces(lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum, side; + + in = (dface_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (msurface_t *) Hunk_AllocName(count*sizeof(*out), loadname); + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + for (surfnum = 0; surfnum < count; surfnum++, in++, out++) + { + out->firstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + out->flags = 0; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodel->planes + planenum; + + out->texinfo = loadmodel->texinfo + LittleShort(in->texinfo); + + CalcSurfaceExtents(out); + + // lighting info + + for (i = 0; i < MAXLIGHTMAPS; i++) + out->styles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else + out->samples = loadmodel->lightdata + i; + + // set the drawing flags flag + const char* texName = out->texinfo->texture->name; + + if (!Q_strncmp(texName, "sky", 3)) // sky + { + out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); + continue; + } + + if (!Q_strncmp(texName, "scroll", 6)) + { + out->flags |= SURF_DRAWTILED; + out->extents[0] = out->texinfo->texture->width; + out->extents[1] = out->texinfo->texture->height; + continue; + } + + if (texName[0] == '!' || !Q_strnicmp(texName, "laser", 5) || !Q_strnicmp(texName, "water", 5)) // turbulent + { + out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); + for (i = 0; i < 2; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + out->texinfo->flags |= TEX_SPECIAL; + } + continue; + } + + if (out->texinfo->flags & TEX_SPECIAL) + { + out->flags |= SURF_DRAWTILED; + out->extents[0] = out->texinfo->texture->width; + out->extents[1] = out->texinfo->texture->height; + continue; + } + } +} + +/* <51dcc> ../engine/model.c:1262 */ +void Mod_SetParent(mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents < 0) + return; + Mod_SetParent(node->children[0], node); + Mod_SetParent(node->children[1], node); +} + +/* <51f0a> ../engine/model.c:1276 */ +void Mod_LoadNodes(lump_t *l) +{ + int i, j, count, p; + dnode_t *in; + mnode_t *out; + + in = (dnode_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (mnode_t*) Hunk_AllocName(count*sizeof(*out), loadname); + + loadmodel->nodes = out; + loadmodel->numnodes = count; + + for (i = 0; i < count; i++, in++, out++) + { + for (j = 0; j < 3; j++) + { + out->minmaxs[j] = LittleShort(in->mins[j]); + out->minmaxs[3 + j] = LittleShort(in->maxs[j]); + } + + p = LittleLong(in->planenum); + out->plane = loadmodel->planes + p; + + out->firstsurface = LittleShort(in->firstface); + out->numsurfaces = LittleShort(in->numfaces); + + for (j = 0; j < 2; j++) + { + p = LittleShort(in->children[j]); + if (p >= 0) + out->children[j] = loadmodel->nodes + p; + else + out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); + } + } + + Mod_SetParent(loadmodel->nodes, NULL); // sets nodes and leafs +} + +/* <51f91> ../engine/model.c:1324 */ +void Mod_LoadLeafs(lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count, p; + + in = (dleaf_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (mleaf_t*) Hunk_AllocName(count*sizeof(*out), loadname); + + loadmodel->leafs = out; + loadmodel->numleafs = count; + + for (i = 0; i < count; i++, in++, out++) + { + for (j = 0; j < 3; j++) + { + out->minmaxs[j] = LittleShort(in->mins[j]); + out->minmaxs[3 + j] = LittleShort(in->maxs[j]); + } + + p = LittleLong(in->contents); + out->contents = p; + + out->firstmarksurface = loadmodel->marksurfaces + + LittleShort(in->firstmarksurface); + out->nummarksurfaces = LittleShort(in->nummarksurfaces); + + p = LittleLong(in->visofs); + if (p == -1) + out->compressed_vis = NULL; + else + out->compressed_vis = loadmodel->visdata + p; + out->efrags = NULL; + + for (j = 0; j < 4; j++) + out->ambient_sound_level[j] = in->ambient_level[j]; + } +} + +/* <52018> ../engine/model.c:1373 */ +void Mod_LoadClipnodes(lump_t *l) +{ + dclipnode_t *in, *out; + int i, count; + hull_t *hull; + + in = (dclipnode_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (dclipnode_t*) Hunk_AllocName(count*sizeof(*out), loadname); + + loadmodel->clipnodes = out; + loadmodel->numclipnodes = count; + + hull = &loadmodel->hulls[1]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count - 1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -36; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 36; + + hull = &loadmodel->hulls[2]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count - 1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -32; + hull->clip_mins[1] = -32; + hull->clip_mins[2] = -32; + hull->clip_maxs[0] = 32; + hull->clip_maxs[1] = 32; + hull->clip_maxs[2] = 32; + + hull = &loadmodel->hulls[3]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count - 1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -18; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 18; + + for (i = 0; i < count; i++, out++, in++) + { + out->planenum = LittleLong(in->planenum); + out->children[0] = LittleShort(in->children[0]); + out->children[1] = LittleShort(in->children[1]); + } +} + +/* <52093> ../engine/model.c:1439 */ +void Mod_MakeHull0(void) +{ + mnode_t *in, *child; + dclipnode_t *out; + int i, j, count; + hull_t *hull; + + hull = &loadmodel->hulls[0]; + + in = loadmodel->nodes; + count = loadmodel->numnodes; + out = (dclipnode_t*) Hunk_AllocName(count * sizeof(*out), loadname); + + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count - 1; + hull->planes = loadmodel->planes; + + for (i = 0; i < count; i++, out++, in++) + { + out->planenum = in->plane - loadmodel->planes; + for (j = 0; j < 2; j++) + { + child = in->children[j]; + if (child->contents < 0) + out->children[j] = child->contents; + else + out->children[j] = child - loadmodel->nodes; + } + } +} + +/* <52119> ../engine/model.c:1476 */ +void Mod_LoadMarksurfaces(lump_t *l) +{ + int i, j, count; + short *in; + msurface_t **out; + + in = (short *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (msurface_t **) Hunk_AllocName(count * sizeof(*out), loadname); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + for (i = 0; i < count; i++) + { + j = LittleShort(in[i]); + if (j >= loadmodel->numsurfaces) + Sys_Error("Mod_ParseMarksurfaces: bad surface number"); + out[i] = loadmodel->surfaces + j; + } +} + +/* <5218c> ../engine/model.c:1505 */ +void Mod_LoadSurfedges(lump_t *l) +{ + int i, count; + int *in, *out; + + in = (int *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (int*) Hunk_AllocName(count * sizeof(*out), loadname); + + loadmodel->surfedges = out; + loadmodel->numsurfedges = count; + + for (i = 0; i < count; i++) + out[i] = LittleLong(in[i]); +} + +/* <52215> ../engine/model.c:1528 */ +void Mod_LoadPlanes(lump_t *l) +{ + int i, j; + mplane_t *out; + dplane_t *in; + int count; + int bits; + + in = (dplane_t *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error("MOD_LoadBmodel: funny lump size in %s", loadmodel->name); + count = l->filelen / sizeof(*in); + out = (mplane_t*) Hunk_AllocName(count * 2 * sizeof(*out), loadname); + + loadmodel->planes = out; + loadmodel->numplanes = count; + + for (i = 0; i < count; i++, in++, out++) + { + bits = 0; + for (j = 0; j < 3; j++) + { + out->normal[j] = LittleFloat(in->normal[j]); + if (out->normal[j] < 0) + bits |= 1 << j; + } + + out->dist = LittleFloat(in->dist); + out->type = LittleLong(in->type); + out->signbits = bits; + } +} + +/* <5229e> ../engine/model.c:1566 */ +float RadiusFromBounds(vec_t *mins, vec_t *maxs) +{ + int i; + vec3_t corner; + + for (i = 0; i < 3; i++) + { + corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); + } + + return Length(corner); +} + +void Mod_LoadBrushModel(model_t *mod, void *buffer) +{ + g_RehldsHookchains.m_Mod_LoadBrushModel.callChain(&Mod_LoadBrushModel_internal, mod, buffer); +} + +/* <52314> ../engine/model.c:1584 */ +void Mod_LoadBrushModel_internal(model_t *mod, void *buffer) +{ + dmodel_t *bm; + model_t *submodel; + char name[10]; + dheader_t *header = (dheader_t *)buffer; + int i; + + loadmodel->type = mod_brush; + i = LittleLong(header->version); + + if (i != 29 && i != 30) + Sys_Error("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod, i, 30); + mod_base = (unsigned char*) buffer; + + for (i = 0; i < sizeof(dheader_t) / 4; i++) + ((int *)header)[i] = LittleLong(((int *)header)[i]); + + Mod_LoadVertexes(&header->lumps[3]); + Mod_LoadEdges(&header->lumps[12]); + Mod_LoadSurfedges(&header->lumps[13]); + if (Q_stricmp(com_gamedir, "bshift")) + { + Mod_LoadEntities(&header->lumps[LUMP_ENTITIES]); + Mod_LoadTextures(&header->lumps[LUMP_TEXTURES]); + Mod_LoadLighting(&header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes(&header->lumps[LUMP_PLANES]); + } + else + { + Mod_LoadEntities(&header->lumps[LUMP_PLANES]); + Mod_LoadTextures(&header->lumps[LUMP_TEXTURES]); + Mod_LoadLighting(&header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes(&header->lumps[LUMP_ENTITIES]); + } + Mod_LoadTexinfo(&header->lumps[LUMP_TEXINFO]); + Mod_LoadFaces(&header->lumps[LUMP_FACES]); + Mod_LoadMarksurfaces(&header->lumps[LUMP_MARKSURFACES]); + Mod_LoadVisibility(&header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafs(&header->lumps[LUMP_LEAFS]); + Mod_LoadNodes(&header->lumps[LUMP_NODES]); + Mod_LoadClipnodes(&header->lumps[LUMP_CLIPNODES]); + Mod_LoadSubmodels(&header->lumps[LUMP_MODELS]); + Mod_MakeHull0(); + mod->numframes = 2; + mod->flags = 0; + i = 0; + for (i = 0; i < mod->numsubmodels; i++) + { + + bm = &mod->submodels[i]; + mod->hulls[0].firstclipnode = bm->headnode[0]; + for (int j = 1; j < MAX_MAP_HULLS; j++) + { + mod->hulls[j].firstclipnode = bm->headnode[j]; + mod->hulls[j].lastclipnode = mod->numclipnodes - 1; + } + + mod->firstmodelsurface = bm->firstface; + mod->nummodelsurfaces = bm->numfaces; + + mod->maxs[0] = bm->maxs[0]; + mod->maxs[2] = bm->maxs[2]; + mod->maxs[1] = bm->maxs[1]; + mod->mins[0] = bm->mins[0]; + mod->mins[1] = bm->mins[1]; + mod->mins[2] = bm->mins[2]; + + mod->radius = RadiusFromBounds(mod->mins, mod->maxs); + mod->numleafs = bm->visleafs; + + if (i < mod->numsubmodels - 1) + { + _snprintf(name, 10, "*%i", i + 1); + submodel = Mod_FindName(0, name); + *submodel = *mod; + loadmodel = submodel; + Q_strncpy(submodel->name, name, 0x3Fu); + mod = loadmodel; + loadmodel->name[63] = 0; + } + } +} + +/* <5255d> ../engine/model.c:1695 */ +NOXREF void *Mod_LoadAliasFrame(void *pin, int *pframeindex, int numv, trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name) +{ + trivertx_t *pframe; + trivertx_t *pinframe; + int i; + int j; + + daliasframe_t *pdaliasframe = (daliasframe_t *)pin; + + Q_strncpy(name, pdaliasframe->name, 15); + name[15] = 0; + + for (i = 0; i < 3; i++) + { + pbboxmax->v[i] = pdaliasframe->bboxmax.v[i]; + pbboxmin->v[i] = pdaliasframe->bboxmin.v[i]; + } + + pinframe = (trivertx_t *)(pdaliasframe + 1); + pframe = (trivertx_t *)Hunk_AllocName(sizeof(trivertx_t) * numv, loadname); + + *pframeindex = (byte *)pframe - (byte *)pheader; + + for (j = 0; j < numv; j++) + { + pframe[j].lightnormalindex = pinframe[j].lightnormalindex; + + for (int k = 0; k < 3; k++) + pframe[j].v[k] = pinframe[j].v[k]; + } + return (void *)&pinframe[numv]; +} + +/* <52656> ../engine/model.c:1743 */ +NOXREF void *Mod_LoadAliasGroup(void *pin, int *pframeindex, int numv, trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name) +{ + daliasgroup_t *pingroup; + maliasgroup_t *paliasgroup; + int i; + int numframes; + daliasinterval_t *pin_intervals; + float *poutintervals; + void *ptemp; + + pingroup = (daliasgroup_t *)pin; + + numframes = LittleLong(pingroup->numframes); + paliasgroup = (maliasgroup_t *)Hunk_AllocName(sizeof(paliasgroup->frames[0]) * (numframes - 1) + sizeof(maliasgroup_t), loadname); + paliasgroup->numframes = numframes; + + for(i = 0; i < 3; i++) + { + pbboxmin->v[i] = pingroup->bboxmin.v[i]; + pbboxmax->v[i] = pingroup->bboxmax.v[i]; + } + + *pframeindex = (byte *)paliasgroup - (byte *)pheader; + + pin_intervals = (daliasinterval_t *)(pingroup + 1); + poutintervals = (float *)Hunk_AllocName(numframes * sizeof(float), loadname); + paliasgroup->intervals = (byte *)poutintervals - (byte *)pheader; + + for (i = 0; i < numframes; i++) + { + *poutintervals = LittleFloat(pin_intervals->interval); + + if (*poutintervals <= 0.0f) + Sys_Error(__FUNCTION__ ": interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + for(i = 0; i < numframes; i++) + ptemp = Mod_LoadAliasFrame(ptemp, &paliasgroup->frames[i].frame, numv, &paliasgroup->frames[i].bboxmin, &paliasgroup->frames[i].bboxmax, pheader, name); + + return ptemp; +} + +/* <5275d> ../engine/model.c:1808 */ +NOXREF void *Mod_LoadAliasSkin(void *pin, int *pskinindex, int skinsize, aliashdr_t *pheader) +{ + unsigned char *pskin; + unsigned char *pinskin; + //unsigned short *pusskin; + + pskin = (unsigned char *)Hunk_AllocName(skinsize * r_pixbytes, loadname); + pinskin = (unsigned char *)pin; + + *pskinindex = pskin - (unsigned char *)pheader; + + if (r_pixbytes == 1) + Q_memcpy(pskin, pinskin, skinsize); + else if (r_pixbytes != 2) + Sys_Error(__FUNCTION__ ": driver set invalid r_pixbytes: %d\n", r_pixbytes); + + return (void *)&pinskin[skinsize]; +} + +/* <52812> ../engine/model.c:1844 */ +NOXREF void *Mod_LoadAliasSkinGroup(void *pin, int *pskinindex, int skinsize, aliashdr_t *pheader) +{ + daliasskingroup_t *pinskingroup; + maliasskingroup_t *paliasskingroup; + int i; + int numskins; + daliasskininterval_t *pinskinintervals; + float *poutskinintervals; + void *ptemp; + + pinskingroup = (daliasskingroup_t *)pin; + numskins = LittleLong(pinskingroup->numskins); + paliasskingroup = (maliasskingroup_t *)Hunk_AllocName(sizeof(paliasskingroup->skindescs[0]) * (numskins - 1) + sizeof(maliasskingroup_t), loadname); + paliasskingroup->numskins = numskins; + *pskinindex = (byte *)paliasskingroup - (byte *)pheader; + poutskinintervals = (float *)Hunk_AllocName(sizeof(float) * numskins, loadname); + paliasskingroup->intervals = (byte *)poutskinintervals - (byte *)pheader; + + pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1); + + for(i = 0; i < numskins; i++) + { + *poutskinintervals = LittleFloat(pinskinintervals->interval); + + if(*poutskinintervals <= 0.0f) + Sys_Error(__FUNCTION__ ": interval<=0"); + + poutskinintervals++; + pinskinintervals++; + } + + ptemp = (void *)pinskinintervals; + + for(i = 0; i < numskins; i++) + ptemp = Mod_LoadAliasSkin(ptemp, &paliasskingroup->skindescs[i].skin, skinsize, pheader); + + return ptemp; +} + +/* <52936> ../engine/model.c:1900 */ +NOXREF void Mod_LoadAliasModel(model_t *mod, void *buffer) +{ + int i; + mdl_t *pmodel; + mdl_t *pinmodel; + stvert_t *pstverts; + stvert_t *pinstverts; + aliashdr_t *pheader; + mtriangle_t *ptri; + dtriangle_t *pintriangles; + int version; + int numframes; + int numskins; + int size; + daliasframetype_t *pframetype; + daliasskintype_t *pskintype; + maliasskindesc_t *pskindesc; + int skinsize; + int start; + int end; + int total; + + start = Hunk_LowMark(); + pinmodel = (mdl_t *)buffer; + version = LittleLong(pinmodel->version); + + if (version != ALIAS_MODEL_VERSION) + Sys_Error("%s has wrong version number (%i should be %i)", mod->name, version, ALIAS_MODEL_VERSION); + + size = sizeof(mtriangle_t) * LittleLong(pinmodel->numtris) + + sizeof(stvert_t) * LittleLong(pinmodel->numverts) + + sizeof(mdl_t) + sizeof(aliashdr_t) + + sizeof(pheader->frames[0]) * (LittleLong(pinmodel->numframes) - 1); + + pheader = (aliashdr_t *)Hunk_AllocName(size, loadname); + pmodel = (mdl_t *)&pheader->frames[LittleLong(pinmodel->numframes)]; + mod->flags = LittleLong(pinmodel->flags); + + pmodel->boundingradius = LittleFloat(pinmodel->boundingradius); + pmodel->numskins = LittleLong(pinmodel->numskins); + pmodel->skinwidth = LittleLong(pinmodel->skinwidth); + pmodel->skinheight = LittleLong(pinmodel->skinheight); + + if (pmodel->skinheight > 480) + Sys_Error("model %s has a skin taller than %d", mod->name, 480); + + pmodel->numverts = LittleLong(pinmodel->numverts); + + if (pmodel->numverts < 1) + Sys_Error("model %s has no vertices", mod->name); + + if (pmodel->numverts > 2000) + Sys_Error("model %s has too many vertices", mod->name); + + pmodel->numtris = LittleLong(pinmodel->numtris); + + if (pmodel->numtris < 1) + Sys_Error("model %s has no triangles", mod->name); + + pmodel->numframes = LittleLong(pinmodel->numframes); + pmodel->size = LittleFloat(pinmodel->size) * 0.09090909090909091; + + mod->synctype = (synctype_t)LittleLong(pinmodel->synctype); + mod->numframes = pmodel->numframes; + + for (i = 0; i < 3; i++) + { + pmodel->scale[i] = LittleFloat(pinmodel->scale[i]); + pmodel->scale_origin[i] = LittleFloat(pinmodel->scale_origin[i]); + pmodel->eyeposition[i] = LittleFloat(pinmodel->eyeposition[i]); + } + + numskins = pmodel->numskins; + numframes = pmodel->numframes; + + if (pmodel->skinwidth & 3) + Sys_Error(__FUNCTION__ ": skinwidth not multiple of 4"); + + pheader->model = (byte *)pmodel - (byte *)pheader; + skinsize = pmodel->skinwidth * pmodel->skinheight; + + if (numskins < 1) + Sys_Error(__FUNCTION__ ": Invalid # of skins: %d\n", numskins); + + pskintype = (daliasskintype_t *)&pinmodel[1]; + pskindesc = (maliasskindesc_t *)Hunk_AllocName(sizeof(maliasskindesc_t) * numskins, loadname); + pheader->skindesc = (byte *)pskintype - (byte *)pheader; + + for(i = 0; i < numskins; i++) + { + aliasskintype_t skintype = (aliasskintype_t)LittleLong(pskintype->type); + + pskindesc[i].type = skintype; + + if(skintype == ALIAS_SKIN_SINGLE) + pskintype = (daliasskintype_t *)Mod_LoadAliasSkin(&pskintype[1], &pskindesc[i].skin, skinsize, pheader); + else + pskintype = (daliasskintype_t *)Mod_LoadAliasSkinGroup(&pskintype[1], &pskindesc[i].skin, skinsize, pheader); + } + + pstverts = (stvert_t *)&pmodel[1]; + pinstverts = (stvert_t *)pskintype; + + pheader->stverts = (byte *)pstverts - (byte *)pheader; + for(i = 0; i < pmodel->numverts; i++) + { + pstverts[i].onseam = LittleLong(pinstverts[i].onseam); + pstverts[i].s = (LittleLong(pinstverts[i].s) << 16); + pstverts[i].t = (LittleLong(pinstverts[i].t) << 16); + } + + ptri = (mtriangle_t *)&pstverts[pmodel->numverts]; + pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts]; + + pheader->triangles = (byte *)ptri - (byte *)pheader; + for(i = 0; i < pmodel->numtris; i++) + { + ptri[i].facesfront = LittleLong(pintriangles[i].facesfront); + + for(int j = 0; j < 3; j++) + ptri[i].vertindex[j] = LittleLong(pintriangles[i].vertindex[j]); + } + + if(numframes < 1) + Sys_Error(__FUNCTION__ ": Invalid # of frames: %d\n", numframes); + + pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris]; + for(i = 0; i < numframes; i++) + { + aliasframetype_t frametype = (aliasframetype_t)LittleLong(pframetype->type); + pheader->frames[i].type = frametype; + + if(frametype == ALIAS_SINGLE) + pframetype = (daliasframetype_t *)Mod_LoadAliasFrame(&pframetype[1], &pheader->frames[i].frame, pmodel->numverts, &pheader->frames[i].bboxmin, &pheader->frames[i].bboxmax, pheader, pheader->frames[i].name); + else + pframetype = (daliasframetype_t *)Mod_LoadAliasGroup(&pframetype[1], &pheader->frames[i].frame, pmodel->numverts, &pheader->frames[i].bboxmin, &pheader->frames[i].bboxmax, pheader, pheader->frames[i].name); + } + + mod->type = mod_alias; + + mod->mins[0] = -16.0f; + mod->mins[1] = -16.0f; + mod->mins[2] = -16.0f; + + mod->maxs[0] = 16.0f; + mod->maxs[1] = 16.0f; + mod->maxs[2] = 16.0f; + + const int dada = sizeof(color24); + + PackedColorVec *pPal = (PackedColorVec *)Hunk_AllocName(sizeof(PackedColorVec) * 256, loadname); + color24 *pPalSrc = (color24 *)&pframetype[0]; + + for (i = 0; i < 256; i++) + { + pPal[i].b = pPalSrc->r; + pPal[i].g = pPalSrc->g; + pPal[i].r = pPalSrc->b; + pPal[i].a = 0; + + pPalSrc++; + } + + pheader->palette = (byte *)pPal - (byte *)pheader; + end = Hunk_LowMark(); + total = end - start; + Cache_Alloc(&mod->cache, total, loadname); + + if(mod->cache.data) + { + Q_memcpy(mod->cache.data, pheader, total); + Hunk_FreeToLowMark(start); + } +} + +/* <52b76> ../engine/model.c:2150 */ +void *Mod_LoadSpriteFrame(void *pin, mspriteframe_t **ppframe) +{ + dspriteframe_t *pinframe; + mspriteframe_t *pspriteframe; + int width, height, size, origin[2]; + unsigned short *ppixout; + byte *ppixin; + + pinframe = (dspriteframe_t *)pin; + + width = LittleLong(pinframe->width); + height = LittleLong(pinframe->height); + size = width * height; + + pspriteframe = (mspriteframe_t*) Hunk_AllocName(sizeof(mspriteframe_t) + size * r_pixbytes, loadname); + + Q_memset(pspriteframe, 0, sizeof(mspriteframe_t) + size); + *ppframe = pspriteframe; + + pspriteframe->width = width; + pspriteframe->height = height; + origin[0] = LittleLong(pinframe->origin[0]); + origin[1] = LittleLong(pinframe->origin[1]); + + pspriteframe->up = (float)origin[1]; + pspriteframe->down = (float)(origin[1] - height); + pspriteframe->left = (float)origin[0]; + pspriteframe->right = (float)(width + origin[0]); + + if (r_pixbytes == 1) + { + Q_memcpy(&pspriteframe->pixels[0], (byte *)(pinframe + 1), size); + } + else if (r_pixbytes == 2) + { + ppixin = (byte *)(pinframe + 1); + ppixout = (unsigned short *)&pspriteframe->pixels[0]; + + /* + //seems to be disabled on server + for (i = 0; i < size; i++) + ppixout[i] = d_8to16table[ppixin[i]]; + */ + + } + else + { + Sys_Error("Mod_LoadSpriteFrame: driver set invalid r_pixbytes: %d\n", r_pixbytes); + } + + return (void *)((byte *)pinframe + sizeof(dspriteframe_t) + size); +} + +/* <52c36> ../engine/model.c:2204 */ +void *Mod_LoadSpriteGroup(void *pin, mspriteframe_t **ppframe) +{ + dspritegroup_t *pingroup; + mspritegroup_t *pspritegroup; + int i, numframes; + dspriteinterval_t *pin_intervals; + float *poutintervals; + void *ptemp; + + pingroup = (dspritegroup_t *)pin; + numframes = LittleLong(pingroup->numframes); + + pspritegroup = (mspritegroup_t*)Hunk_AllocName(sizeof(mspritegroup_t) + (numframes - 1) * sizeof(pspritegroup->frames[0]), loadname); + + pspritegroup->numframes = numframes; + + *ppframe = (mspriteframe_t *)pspritegroup; + + pin_intervals = (dspriteinterval_t *)(pingroup + 1); + + poutintervals = (float*)Hunk_AllocName(numframes * sizeof(float), loadname); + + pspritegroup->intervals = poutintervals; + + for (i = 0; i < numframes; i++) + { + *poutintervals = LittleFloat(pin_intervals->interval); + if (*poutintervals <= 0.0f) + Sys_Error(__FUNCTION__ ": interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + + for (i = 0; i < numframes; i++) + { + ptemp = Mod_LoadSpriteFrame(ptemp, &pspritegroup->frames[i]); + } + + return ptemp; +} + +/* <52cf2> ../engine/model.c:2256 */ +void Mod_LoadSpriteModel(model_t *mod, void *buffer) +{ + int i; + int version; + dsprite_t *pin; + msprite_t *psprite; + int numframes; + int size; + dspriteframetype_t *pframetype; + + pin = (dsprite_t *)buffer; + + version = LittleLong(pin->version); + if (version != SPRITE_VERSION) + Sys_Error("%s has wrong version number " + "(%i should be %i)", mod->name, version, SPRITE_VERSION); + + numframes = LittleLong(pin->numframes); + int palsize = *(uint16_t*)&pin[1]; + size = sizeof(msprite_t) + (numframes - 1) * sizeof(psprite->frames) + 2 + 8 * palsize; + + psprite = (msprite_t*) Hunk_AllocName(size, loadname); + + mod->cache.data = psprite; + + psprite->type = LittleLong(pin->type); + psprite->maxwidth = LittleLong(pin->width); + psprite->maxheight = LittleLong(pin->height); + psprite->beamlength = LittleFloat(pin->beamlength); + mod->synctype = (synctype_t) LittleLong(pin->synctype); + psprite->numframes = numframes; + + mod->mins[0] = mod->mins[1] = float(-psprite->maxwidth / 2); + mod->maxs[0] = mod->maxs[1] = float(psprite->maxwidth / 2); + mod->mins[2] = float (- psprite->maxheight / 2); + mod->maxs[2] = float(psprite->maxheight / 2); + + unsigned char *palsrc = (unsigned char*)(&pin[1]) + 2; //header + palette size + uint16_t* paldest = (uint16_t*)((char*)(psprite + 1) + sizeof(psprite->frames) * (numframes - 1)); //sprite + [frames-1] + *(paldest++) = palsize; //write palette size + for (i = 0; i < palsize; i++, paldest += 4, palsrc += 3) + { + paldest[3] = 0; + paldest[0] = palsrc[0]; + paldest[1] = palsrc[1]; + paldest[2] = palsrc[2]; + } + + // + // load the frames + // + if (numframes < 1) + Sys_Error(__FUNCTION__ ": Invalid # of frames: %d\n", numframes); + + mod->numframes = numframes; + mod->flags = 0; + + pframetype = (dspriteframetype_t *)((char*)(pin + 1) + 2 + 3*palsize); + + for (i = 0; i < numframes; i++) + { + spriteframetype_t frametype; + + frametype = (spriteframetype_t) LittleLong(pframetype->type); + psprite->frames[i].type = frametype; + + if (frametype == SPR_SINGLE) + { + pframetype = (dspriteframetype_t *) + Mod_LoadSpriteFrame(pframetype + 1, + &psprite->frames[i].frameptr); + } + else + { + pframetype = (dspriteframetype_t *) + Mod_LoadSpriteGroup(pframetype + 1, + &psprite->frames[i].frameptr); + } + } + + mod->type = mod_sprite; +} + +/* <5300a> ../engine/model.c:2360 */ +NOXREF void Mod_UnloadSpriteTextures(model_t *pModel) +{ + if (!pModel) + return; + + if (pModel->type == mod_sprite) + { + pModel->needload = NL_NEEDS_LOADED; +#ifndef SWDS + char name[256]; + msprite_t *spt = (msprite_t *)pModel->cache.data; + if (spt) + { + for (int i = 0; i < spt->numframes; i++) + { + Q_sprintf(name, "%s_%i", pModel->name, i); + GL_UnloadTexture(name); + } + } +#endif // SWDS + } +} + +/* <53033> ../engine/model.c:2376 */ +void Mod_Print(void) +{ + int i; + model_t *mod; + Con_Printf("Cached models:\n"); + for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) + { + Con_Printf("%8p : %s", mod->cache.data, mod->name); + if (mod->needload & NL_UNREFERENCED) + Con_Printf(" (!R)"); + if (mod->needload & NL_NEEDS_LOADED) + Con_Printf(" (!P)"); + Con_Printf("\n"); + } +} + +/* <5306c> ../engine/model.c:2399 */ +NOXREF void Mod_ChangeGame(void) +{ + int i; + model_t *mod; + mod_known_info_t *p; + + for (i = 0; i < mod_numknown; i++) + { + mod = &mod_known[i]; + + if (mod->type == mod_studio) + { + if (Cache_Check(&mod->cache)) + Cache_Free(&mod->cache); + } + + p = &mod_known_info[i]; + + p->firstCRCDone = FALSE; + p->initialCRC = 0; + } +} diff --git a/rehlds/engine/model_rehlds.h b/rehlds/engine/model_rehlds.h new file mode 100644 index 0000000..39816ad --- /dev/null +++ b/rehlds/engine/model_rehlds.h @@ -0,0 +1,116 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +/* + +#include "const.h" +#include "d_local.h" +#include "modelgen.h" + +#include "quakedef.h" +#include "spritegn.h" +#include "crc.h" +*/ + +#include "model.h" + +#include "maintypes.h" +#include "bspfile.h" +#include "crc.h" + + +#ifdef HOOK_ENGINE +#define loadmodel (*ploadmodel) +#define loadname (*ploadname) +#define mod_known (*pmod_known) +#define mod_numknown (*pmod_numknown) +#define mod_base (*pmod_base) +#define wadpath (*pwadpath) +#define tested (*ptested) +#define ad_enabled (*pad_enabled) +#define ad_wad (*pad_wad) +#define mod_known_info (*pmod_known_info) +#endif + +extern model_t* loadmodel; +extern char loadname[32]; +extern model_t mod_known[MAX_KNOWN_MODELS]; +extern int mod_numknown; +extern unsigned char* mod_base; +extern char *wadpath; +extern int tested; +extern int ad_enabled; +extern cachewad_t ad_wad; +extern mod_known_info_t mod_known_info[MAX_KNOWN_MODELS]; + +void SW_Mod_Init(void); +void *Mod_Extradata(model_t *mod); +mleaf_t *Mod_PointInLeaf(vec_t *p, model_t *model); +void Mod_ClearAll(void); +void Mod_FillInCRCInfo(qboolean trackCRC, int model_number); +model_t *Mod_FindName(qboolean trackCRC, const char *name); +NOXREF qboolean Mod_ValidateCRC(const char *name, CRC32_t crc); +NOXREF void Mod_NeedCRC(const char *name, qboolean needCRC); +model_t *Mod_LoadModel(model_t *mod, qboolean crash, qboolean trackCRC); +NOXREF void Mod_MarkClient(model_t *pModel); +model_t *Mod_ForName(const char *name, qboolean crash, qboolean trackCRC); +void Mod_AdInit(void); +void Mod_AdSwap(texture_t *src, int pixels, int entries); +void Mod_LoadTextures(lump_t *l); +void Mod_LoadLighting(lump_t *l); +void Mod_LoadVisibility(lump_t *l); +void Mod_LoadEntities(lump_t *l); +void Mod_LoadVertexes(lump_t *l); +void Mod_LoadSubmodels(lump_t *l); +void Mod_LoadEdges(lump_t *l); +void Mod_LoadTexinfo(lump_t *l); +void CalcSurfaceExtents(msurface_t *s); +void Mod_LoadFaces(lump_t *l); +void Mod_SetParent(mnode_t *node, mnode_t *parent); +void Mod_LoadNodes(lump_t *l); +void Mod_LoadLeafs(lump_t *l); +void Mod_LoadClipnodes(lump_t *l); +void Mod_MakeHull0(void); +void Mod_LoadMarksurfaces(lump_t *l); +void Mod_LoadSurfedges(lump_t *l); +void Mod_LoadPlanes(lump_t *l); +float RadiusFromBounds(vec_t *mins, vec_t *maxs); +void Mod_LoadBrushModel(model_t *mod, void *buffer); +void Mod_LoadBrushModel_internal(model_t *mod, void *buffer); +NOXREF void *Mod_LoadAliasFrame(void *pin, int *pframeindex, int numv, trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name); +NOXREF void *Mod_LoadAliasGroup(void *pin, int *pframeindex, int numv, trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name); +NOXREF void *Mod_LoadAliasSkin(void *pin, int *pskinindex, int skinsize, aliashdr_t *pheader); +NOXREF void *Mod_LoadAliasSkinGroup(void *pin, int *pskinindex, int skinsize, aliashdr_t *pheader); +NOXREF void Mod_LoadAliasModel(model_t *mod, void *buffer); +void *Mod_LoadSpriteFrame(void *pin, mspriteframe_t **ppframe); +void *Mod_LoadSpriteGroup(void *pin, mspriteframe_t **ppframe); +void Mod_LoadSpriteModel(model_t *mod, void *buffer); +NOXREF void Mod_UnloadSpriteTextures(model_t *pModel); +void Mod_Print(void); +NOXREF void Mod_ChangeGame(void); diff --git a/rehlds/engine/modinfo.h b/rehlds/engine/modinfo.h new file mode 100644 index 0000000..18dc8b2 --- /dev/null +++ b/rehlds/engine/modinfo.h @@ -0,0 +1,64 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef MODINFO_H +#define MODINFO_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + + +/* <8eef1> ../engine/modinfo.h:7 */ +typedef enum +{ + BOTH = 0, + SINGLEPLAYER_ONLY, + MULTIPLAYER_ONLY, +} MOD_GAMEPLAY_TYPE_E; + +/* <8ef1b> ../engine/modinfo.h:10 */ +typedef struct modinfo_s +{ + qboolean bIsMod; + char szInfo[256]; + char szDL[256]; + char szHLVersion[32]; + int version; + int size; + qboolean svonly; + qboolean cldll; + qboolean secure; + MOD_GAMEPLAY_TYPE_E type; + int num_edicts; + int clientDllCRC; +} modinfo_t; + + +#endif // MODINFO_H diff --git a/rehlds/engine/module.cpp b/rehlds/engine/module.cpp new file mode 100644 index 0000000..d851ffb --- /dev/null +++ b/rehlds/engine/module.cpp @@ -0,0 +1,36 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +// TODO: Implement security module +cl_enginefunc_dst_t *pg_engdstAddrs; + +modfuncs_t g_modfuncs; +module_t g_module; diff --git a/rehlds/engine/net.h b/rehlds/engine/net.h new file mode 100644 index 0000000..07c3b85 --- /dev/null +++ b/rehlds/engine/net.h @@ -0,0 +1,373 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef GS_NET_H +#define GS_NET_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "common.h" +#include "enums.h" +#include "netadr.h" + + +#define PROTOCOL_VERSION 48 + +// MAX_CHALLENGES is made large to prevent a denial +// of service attack that could cycle all of them +// out before legitimate users connected +#define MAX_CHALLENGES 1024 + +// Client connection is initiated by requesting a challenge value +// the server sends this value back +#define S2C_CHALLENGE 'A' // + challenge value + +// HLMaster rejected a server's connection because the server needs to be updated +#define M2S_REQUESTRESTART 'O' + +// send a log event as key value +#define S2A_LOGSTRING 'R' + +// Send a log string +#define S2A_LOGKEY 'S' + +// Basic information about the server +#define A2S_INFO 'T' + +// Details about each player on the server +#define A2S_PLAYER 'U' + +// The rules the server is using +#define A2S_RULES 'V' + +// Another user is requesting a challenge value from this machine +#define A2A_GETCHALLENGE 'W' // Request challenge # from another machine + +// Generic Ping Request +#define A2A_PING 'i' // respond with an A2A_ACK + +// Generic Ack +#define A2A_ACK 'j' // general acknowledgement without info + +// Challenge response from master +#define M2A_CHALLENGE 's' // + challenge value + +// 0 == regular, 1 == file stream +#define MAX_STREAMS 2 + +// Flow control bytes per second limits +#define MAX_RATE 20000 +#define MIN_RATE 1000 + +// Default data rate +#define DEFAULT_RATE (9999.0f) + +// NETWORKING INFO + +// This is the packet payload without any header bytes (which are attached for actual sending) +#define NET_MAX_PAYLOAD 3990 + +// This is the payload plus any header info (excluding UDP header) + +// Packet header is: +// 4 bytes of outgoing seq +// 4 bytes of incoming seq +// and for each stream +// { +// byte (on/off) +// int (fragment id) +// short (startpos) +// short (length) +// } +#define HEADER_BYTES ( 8 + MAX_STREAMS * 9 ) + +// Pad a number so it lies on an N byte boundary. +// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4 +#define PAD_NUMBER(number, boundary) \ + ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary) + +// Pad this to next higher 16 byte boundary +// This is the largest packet that can come in/out over the wire, before processing the header +// bytes will be stripped by the networking channel layer +//#define NET_MAX_MESSAGE PAD_NUMBER( ( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 ) +// This is currently used value in the engine. TODO: define above gives 4016, check it why. +#define NET_MAX_MESSAGE 4037 + + +typedef enum svc_commands_e +{ + svc_bad, //0 + svc_nop, //1 + svc_disconnect, //2 + svc_event, //3 + svc_version, //4 + svc_setview, //5 + svc_sound, //6 + svc_time, //7 + svc_print, //8 + svc_stufftext, + svc_setangle, + svc_serverinfo, + svc_lightstyle, + svc_updateuserinfo, + svc_deltadescription, + svc_clientdata, + svc_stopsound, + svc_pings, + svc_particle, + svc_damage, + svc_spawnstatic, + svc_event_reliable, + svc_spawnbaseline, + svc_temp_entity, + svc_setpause, + svc_signonnum, + svc_centerprint, + svc_killedmonster, + svc_foundsecret, + svc_spawnstaticsound, + svc_intermission, + svc_finale, + svc_cdtrack, + svc_restore, + svc_cutscene, + svc_weaponanim, + svc_decalname, + svc_roomtype, + svc_addangle, + svc_newusermsg, + svc_packetentities, + svc_deltapacketentities, + svc_choke, + svc_resourcelist, + svc_newmovevars, + svc_resourcerequest, + svc_customization, + svc_crosshairangle, + svc_soundfade, + svc_filetxferfailed, + svc_hltv, + svc_director, + svc_voiceinit, + svc_voicedata, + svc_sendextrainfo, + svc_timescale, + svc_resourcelocation, + svc_sendcvarvalue, + svc_sendcvarvalue2, + svc_startofusermessages = svc_sendcvarvalue2, + svc_endoflist = 255, +} svc_commands_t; + +typedef enum clc_commands_e +{ + clc_bad, + clc_nop, + clc_move, + clc_stringcmd, + clc_delta, + clc_resourcelist, + clc_tmove, + clc_fileconsistency, + clc_voicedata, + clc_hltv, + clc_cvarvalue, + clc_cvarvalue2, + clc_endoflist = 255, +} clc_commands_t; + + +#define MAX_FLOWS 2 + +#define FLOW_OUTGOING 0 +#define FLOW_INCOMING 1 + +/* ../engine/net.h:91 */ +// Message data +typedef struct flowstats_s +{ + // Size of message sent/received + int size; + // Time that message was sent/received + double time; +} flowstats_t; + +#define MAX_LATENT 32 + +/* ../engine/net.h:101 */ +typedef struct flow_s +{ + // Data for last MAX_LATENT messages + flowstats_t stats[MAX_LATENT]; + // Current message position + int current; + // Time when we should recompute k/sec data + double nextcompute; + // Average data + float kbytespersec; + float avgkbytespersec; +} flow_t; + +// Size of fragmentation buffer internal buffers +#define FRAGMENT_SIZE 1400 +#define MAX_FRAGMENTS 25000 + +#define UDP_HEADER_SIZE 28 +#define MAX_RELIABLE_PAYLOAD 1200 + +#define FRAG_NORMAL_STREAM 0 +#define FRAG_FILE_STREAM 1 + +#define MAKE_FRAGID(id,count) ( ( ( id & 0xffff ) << 16 ) | ( count & 0xffff ) ) +#define FRAG_GETID(fragid) ( ( fragid >> 16 ) & 0xffff ) +#define FRAG_GETCOUNT(fragid) ( fragid & 0xffff ) + +/* ../engine/net.h:124 */ +// Generic fragment structure +typedef struct fragbuf_s +{ + // Next buffer in chain + fragbuf_s *next; + // Id of this buffer + int bufferid; + // Message buffer where raw data is stored + sizebuf_t frag_message; + // The actual data sits here + byte frag_message_buf[FRAGMENT_SIZE]; + // Is this a file buffer? + qboolean isfile; + // Is this file buffer from memory ( custom decal, etc. ). + qboolean isbuffer; + qboolean iscompressed; + // Name of the file to save out on remote host + char filename[MAX_PATH]; + // Offset in file from which to read data + int foffset; + // Size of data to read at that offset + int size; +} fragbuf_t; + +/* ../engine/net.h:149 */ +// Waiting list of fragbuf chains +typedef struct fragbufwaiting_s +{ + // Next chain in waiting list + fragbufwaiting_s *next; + // Number of buffers in this chain + int fragbufcount; + // The actual buffers + fragbuf_t *fragbufs; +} fragbufwaiting_t; + +/* <1001> ../engine/net.h:160 */ +// Network Connection Channel +typedef struct netchan_s +{ + // NS_SERVER or NS_CLIENT, depending on channel. + netsrc_t sock; + + // Address this channel is talking to. + netadr_t remote_address; + + int player_slot; + // For timeouts. Time last message was received. + float last_received; + // Time when channel was connected. + float connect_time; + + // Bandwidth choke + // Bytes per second + double rate; + // If realtime > cleartime, free to send next packet + double cleartime; + + // Sequencing variables + // + // Increasing count of sequence numbers + int incoming_sequence; + // # of last outgoing message that has been ack'd. + int incoming_acknowledged; + // Toggles T/F as reliable messages are received. + int incoming_reliable_acknowledged; + // single bit, maintained local + int incoming_reliable_sequence; + // Message we are sending to remote + int outgoing_sequence; + // Whether the message contains reliable payload, single bit + int reliable_sequence; + // Outgoing sequence number of last send that had reliable data + int last_reliable_sequence; + + void *connection_status; + int (*pfnNetchan_Blocksize)(void *); + + // Staging and holding areas + sizebuf_t message; + byte message_buf[NET_MAX_PAYLOAD]; + + // Reliable message buffer. We keep adding to it until reliable is acknowledged. Then we clear it. + int reliable_length; + byte reliable_buf[NET_MAX_PAYLOAD]; + + // Waiting list of buffered fragments to go onto queue. Multiple outgoing buffers can be queued in succession. + fragbufwaiting_t *waitlist[MAX_STREAMS]; + + // Is reliable waiting buf a fragment? + int reliable_fragment[MAX_STREAMS]; + // Buffer id for each waiting fragment + unsigned int reliable_fragid[MAX_STREAMS]; + + // The current fragment being set + fragbuf_t *fragbufs[MAX_STREAMS]; + // The total number of fragments in this stream + int fragbufcount[MAX_STREAMS]; + + // Position in outgoing buffer where frag data starts + short int frag_startpos[MAX_STREAMS]; + // Length of frag data in the buffer + short int frag_length[MAX_STREAMS]; + + // Incoming fragments are stored here + fragbuf_t *incomingbufs[MAX_STREAMS]; + // Set to true when incoming data is ready + qboolean incomingready[MAX_STREAMS]; + + // Only referenced by the FRAG_FILE_STREAM component + // Name of file being downloaded + char incomingfilename[MAX_PATH]; + + void *tempbuffer; + int tempbuffersize; + + // Incoming and outgoing flow metrics + flow_t flow[MAX_FLOWS]; +} netchan_t; + +#endif // GS_NET_H diff --git a/rehlds/engine/net_chan.cpp b/rehlds/engine/net_chan.cpp new file mode 100644 index 0000000..acc4ecb --- /dev/null +++ b/rehlds/engine/net_chan.cpp @@ -0,0 +1,1721 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +int net_drop; + +char gDownloadFile[256]; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t net_log = { "net_log", "0", 0, 0.0f, NULL }; +cvar_t net_showpackets = { "net_showpackets", "0", 0, 0.0f, NULL }; +cvar_t net_showdrop = { "net_showdrop", "0", 0, 0.0f, NULL }; +cvar_t net_drawslider = { "net_drawslider", "0", 0, 0.0f, NULL }; +cvar_t net_chokeloopback = { "net_chokeloop", "0", 0, 0.0f, NULL }; +cvar_t sv_filetransfercompression = { "sv_filetransfercompression", "1", 0, 0.0f, NULL }; +cvar_t sv_filetransfermaxsize = { "sv_filetransfermaxsize", "10485760", 0, 0.0f, NULL }; + +#else //HOOK_ENGINE + +cvar_t net_log; +cvar_t net_showpackets; +cvar_t net_showdrop; +cvar_t net_drawslider; +cvar_t net_chokeloopback; +cvar_t sv_filetransfercompression; +cvar_t sv_filetransfermaxsize; + +#endif //HOOK_ENGINE + +/* <6565b> ../engine/net_chan.c:103 */ +void Netchan_UnlinkFragment(fragbuf_t *buf, fragbuf_t **list) +{ + fragbuf_t *search; + + if (list == NULL) + { + Con_Printf(__FUNCTION__ ": Asked to unlink fragment from empty list, ignored\n"); + return; + } + + if (*list == buf) + { + *list = buf->next; + Mem_Free(buf); + return; + } + + search = *list; + while (search->next) + { + if (search->next == buf) + { + search->next = buf->next; + Mem_Free(buf); + return; + } + search = search->next; + } + + Con_Printf(__FUNCTION__ ": Couldn't find fragment\n"); +} + +/* <656b9> ../engine/net_chan.c:148 */ +void Netchan_OutOfBand(netsrc_t sock, netadr_t adr, int length, byte *data) +{ + sizebuf_t send; + byte send_buf[NET_MAX_PAYLOAD]; + + send.buffername = "Netchan_OutOfBand"; + send.data = send_buf; + send.maxsize = sizeof(send_buf); + send.cursize = 0; + send.flags = SIZEBUF_ALLOW_OVERFLOW; + + MSG_WriteLong(&send, -1); + SZ_Write(&send, data, length); + + if (!g_pcls.demoplayback) + { + NET_SendPacket(sock, send.cursize, send.data, adr); + } +} + +/* <65700> ../engine/net_chan.c:177 */ +void Netchan_OutOfBandPrint(netsrc_t sock, netadr_t adr, char *format, ...) +{ + va_list argptr; + char string[8192]; + + va_start(argptr, format); + Q_vsnprintf(string, sizeof(string), format, argptr); + va_end(argptr); + + Netchan_OutOfBand(sock, adr, Q_strlen(string) + 1, (byte *)string); +} + +/* <65776> ../engine/net_chan.c:196 */ +void Netchan_ClearFragbufs(fragbuf_t **ppbuf) +{ + fragbuf_t *buf, *n; + + if (!ppbuf) + { + return; + } + + // Throw away any that are sitting around + buf = *ppbuf; + while (buf) + { + n = buf->next; + Mem_Free(buf); + buf = n; + } + *ppbuf = NULL; +} + +/* <65810> ../engine/net_chan.c:220 */ +void Netchan_ClearFragments(netchan_t *chan) +{ + fragbufwaiting_t *wait, *next; + for (int i = 0; i < MAX_STREAMS; i++) + { + wait = chan->waitlist[i]; + while (wait) + { + next = wait->next; + Netchan_ClearFragbufs(&wait->fragbufs); + Mem_Free(wait); + wait = next; + } + chan->waitlist[i] = NULL; + + Netchan_ClearFragbufs(&chan->fragbufs[i]); + Netchan_FlushIncoming(chan, i); + } +} + +/* <6590d> ../engine/net_chan.c:250 */ +void Netchan_Clear(netchan_t *chan) +{ + Netchan_ClearFragments(chan); + + if (chan->reliable_length) + { + Con_DPrintf(__FUNCTION__ ": reliable length not 0, reliable_sequence: %d, incoming_reliable_acknowledged: %d\n", chan->reliable_length, chan->incoming_reliable_acknowledged); + chan->reliable_sequence ^= 1; + chan->reliable_length = 0; + } + + chan->cleartime = 0.0; + + for (int i = 0; i < MAX_STREAMS; i++) + { + chan->reliable_fragid[i] = 0; + chan->reliable_fragment[i] = 0; + chan->fragbufcount[i] = 0; + chan->frag_startpos[i] = 0; + chan->frag_length[i] = 0; + chan->incomingready[i] = FALSE; + } + + if (chan->tempbuffer) + { + Mem_Free(chan->tempbuffer); + chan->tempbuffer = NULL; + } + chan->tempbuffersize = 0; +} + +/* <65957> ../engine/net_chan.c:295 */ +void Netchan_Setup(netsrc_t socketnumber, netchan_t *chan, netadr_t adr, int player_slot, void *connection_status, qboolean(*pfnNetchan_Blocksize)(void *)) +{ + Netchan_Clear(chan); + + Q_memset(chan, 0, sizeof(netchan_t)); + + chan->player_slot = player_slot + 1; + chan->sock = socketnumber; + chan->remote_address = adr; + chan->last_received = (float)realtime; + chan->connect_time = (float)realtime; + + chan->message.buffername = "netchan->message"; + chan->message.data = chan->message_buf; + chan->message.maxsize = sizeof(chan->message_buf); +#ifdef REHLDS_FIXES + chan->message.cursize = 0; +#endif // REHLDS_FIXES + chan->message.flags = SIZEBUF_ALLOW_OVERFLOW; + + chan->rate = DEFAULT_RATE; + + // Prevent the first message from getting dropped after connection is set up. + chan->outgoing_sequence = 1; + + chan->connection_status = connection_status; + chan->pfnNetchan_Blocksize = pfnNetchan_Blocksize; +} + +/* <65a0a> ../engine/net_chan.c:327 */ +qboolean Netchan_CanPacket(netchan_t *chan) +{ + // Never choke loopback packets. + if (net_chokeloopback.value == 0.0f && chan->remote_address.type == NA_LOOPBACK) + { + chan->cleartime = realtime; + return TRUE; + } + + return chan->cleartime < realtime ? TRUE : FALSE; +} + +/* <65a37> ../engine/net_chan.c:350 */ +void Netchan_UpdateFlow(netchan_t *chan) +{ + if (!chan) + return; + + int bytes = 0; + float faccumulatedtime = 0.0f; + + for (int flow = 0; flow < MAX_FLOWS; flow++) + { + flow_t *pflow = &chan->flow[flow]; + if (realtime - pflow->nextcompute < 0.1) + continue; + + pflow->nextcompute = realtime + 0.1; + int start = pflow->current - 1; + for (int i = 0; i < MAX_LATENT - 1; i++) + { + flowstats_t *pprev = &pflow->stats[(start - i) & 0x1F]; + flowstats_t *pstat = &pflow->stats[(start - i - 1) & 0x1F]; + + faccumulatedtime += pprev->time - pstat->time; + bytes += pstat->size; + } + + pflow->kbytespersec = (faccumulatedtime == 0.0f) ? 0.0f : bytes / faccumulatedtime / 1024.0f; + pflow->avgkbytespersec = pflow->avgkbytespersec * (2.0 / 3) + pflow->kbytespersec * (1.0 / 3); + } +} + +/* <65b51> ../engine/net_chan.c:412 */ +void Netchan_Transmit(netchan_t *chan, int length, byte *data) +{ + byte send_buf[NET_MAX_MESSAGE]; + qboolean send_reliable; + qboolean send_reliable_fragment; + qboolean send_resending = false; + unsigned w1, w2; + int i, j; + + float fRate; + + sizebuf_t sb_send; + sb_send.data = send_buf; + sb_send.buffername = "Netchan_Transmit"; + sb_send.maxsize = sizeof(send_buf); + sb_send.flags = 0; + sb_send.cursize = 0; + + // check for message overflow + if (chan->message.flags & 2) { + Con_Printf("%s:Outgoing message overflow\n", NET_AdrToString(chan->remote_address)); + return; + } + + // if the remote side dropped the last reliable message, resend it + send_reliable = false; + + if (chan->incoming_acknowledged > chan->last_reliable_sequence && + chan->incoming_reliable_acknowledged != chan->reliable_sequence) + { + send_reliable = true; + send_resending = true; + } + + // + // A packet can have "reliable payload + frag payload + unreliable payload + // frag payload can be a file chunk, if so, it needs to be parsed on the receiving end and reliable payload + unreliable payload need + // to be passed on to the message queue. The processing routine needs to be able to handle the case where a message comes in and a file + // transfer completes + // + // + // if the reliable transmit buffer is empty, copy the current message out + if (!chan->reliable_length) + { + qboolean send_frag = false; + fragbuf_t *pbuf; + + // Will be true if we are active and should let chan->message get some bandwidth + int send_from_frag[MAX_STREAMS] = { 0, 0 }; + int send_from_regular = 0; + + // If we have data in the waiting list(s) and we have cleared the current queue(s), then + // push the waitlist(s) into the current queue(s) + Netchan_FragSend(chan); + + // Sending regular payload + send_from_regular = (chan->message.cursize) ? 1 : 0; + + // Check to see if we are sending a frag payload + // + for (i = 0; i < MAX_STREAMS; i++) + { + if (chan->fragbufs[i]) + { + send_from_frag[i] = 1; + } + } + + // Stall reliable payloads if sending from frag buffer + if (send_from_regular && (send_from_frag[FRAG_NORMAL_STREAM])) + { + send_from_regular = false; + + // If the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer + // + if (chan->message.cursize > MAX_RELIABLE_PAYLOAD) + { + Netchan_CreateFragments_(chan == &g_pcls.netchan ? 1 : 0, chan, &chan->message); + SZ_Clear(&chan->message); + } + } + + // Startpos will be zero if there is no regular payload + for (i = 0; i < MAX_STREAMS; i++) + { + chan->frag_startpos[i] = 0; + + // Assume no fragment is being sent + chan->reliable_fragment[i] = 0; + chan->reliable_fragid[i] = 0; + chan->frag_length[i] = 0; + + if (send_from_frag[i]) + { + send_frag = true; + } + } + + if (send_from_regular || send_frag) + { + chan->reliable_sequence ^= 1; + send_reliable = true; + } + + if (send_from_regular) { + memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize); + chan->reliable_length = chan->message.cursize; + SZ_Clear(&chan->message); + + // If we send fragments, this is where they'll start + for (i = 0; i < MAX_STREAMS; i++) { + chan->frag_startpos[i] = chan->reliable_length; + } + } + + for (i = 0; i < MAX_STREAMS; i++) { + int fragment_size; + + // Is there something in the fragbuf? + pbuf = chan->fragbufs[i]; + + fragment_size = 0; // Compiler warning. + if (pbuf) { + fragment_size = pbuf->frag_message.cursize; + + // Files set size a bit differently. + if (pbuf->isfile && !pbuf->isbuffer) + { + fragment_size = pbuf->size; + } + } + + // Make sure we have enought space left + if (send_from_frag[i] && pbuf && ((chan->reliable_length + fragment_size) < MAX_RELIABLE_PAYLOAD)) { + + chan->reliable_fragid[i] = MAKE_FRAGID(pbuf->bufferid, chan->fragbufcount[i]); // Which buffer are we sending? + + // If it's not in-memory, then we'll need to copy it in frame the file handle. + if (pbuf->isfile && !pbuf->isbuffer) { + char compressedfilename[MAX_PATH]; + FileHandle_t hfile; + if (pbuf->iscompressed) + { + _snprintf(compressedfilename, sizeof(compressedfilename), "%s.ztmp", pbuf->filename); + hfile = FS_Open(compressedfilename, "rb"); + } + else + { + hfile = FS_Open(pbuf->filename, "rb"); + } + FS_Seek(hfile, pbuf->foffset, FILESYSTEM_SEEK_HEAD); + FS_Read(&pbuf->frag_message.data[pbuf->frag_message.cursize], pbuf->size, 1, hfile); + pbuf->frag_message.cursize += pbuf->size; + FS_Close(hfile); + } + + + memcpy(chan->reliable_buf + chan->reliable_length, pbuf->frag_message.data, pbuf->frag_message.cursize); + chan->reliable_length += pbuf->frag_message.cursize; + chan->frag_length[i] = pbuf->frag_message.cursize; + + + // Unlink pbuf + Netchan_UnlinkFragment(pbuf, &chan->fragbufs[i]); + + chan->reliable_fragment[i] = 1; + + // Offset the rest of the starting positions + for (j = i + 1; j < MAX_STREAMS; j++) + { + chan->frag_startpos[j] += chan->frag_length[i]; + } + } + } + } + + // Prepare the packet header + w1 = chan->outgoing_sequence | (send_reliable << 31); + w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence << 31); + + send_reliable_fragment = false; + + for (i = 0; i < MAX_STREAMS; i++) + { + if (chan->reliable_fragment[i]) + { + send_reliable_fragment = true; + break; + } + } + + if (send_reliable && send_reliable_fragment) + { + w1 |= (1 << 30); + } + + chan->outgoing_sequence++; + + MSG_WriteLong(&sb_send, w1); + MSG_WriteLong(&sb_send, w2); + + if (send_reliable && send_reliable_fragment) + { + for (i = 0; i < MAX_STREAMS; i++) + { + if (chan->reliable_fragment[i]) + { + MSG_WriteByte(&sb_send, 1); + MSG_WriteLong(&sb_send, chan->reliable_fragid[i]); + MSG_WriteShort(&sb_send, chan->frag_startpos[i]); + MSG_WriteShort(&sb_send, chan->frag_length[i]); + } + else + { + MSG_WriteByte(&sb_send, 0); + } + } + } + + // Copy the reliable message to the packet first + if (send_reliable) { + SZ_Write(&sb_send, chan->reliable_buf, chan->reliable_length); + chan->last_reliable_sequence = chan->outgoing_sequence - 1; + } + + // Is there room for the unreliable payload? + int max_send_size = 1400; + if (!send_resending) + max_send_size = sb_send.maxsize; + + if ((max_send_size - sb_send.cursize) >= length) { + SZ_Write(&sb_send, data, length); + } + else { + Con_DPrintf("Netchan_Transmit: Unreliable would overfow, ignoring\n"); + } + + // Deal with packets that are too small for some networks + if (sb_send.cursize < 16) // Packet too small for some networks + { + int i; + // Go ahead and pad a full 16 extra bytes -- this only happens during authentication / signon + for (i = sb_send.cursize; i < 16; i++) + { + // Note that the server can parse svc_nop, too. + MSG_WriteByte(&sb_send, svc_nop); + } + } + + int statId = chan->flow[FLOW_OUTGOING].current & 0x1F; + chan->flow[FLOW_OUTGOING].stats[statId].size = sb_send.cursize + UDP_HEADER_SIZE; + chan->flow[FLOW_OUTGOING].stats[statId].time = realtime; + chan->flow[FLOW_OUTGOING].current++; + Netchan_UpdateFlow(chan); + + if (!g_pcls.demoplayback) + { + COM_Munge2(sb_send.data + 8, sb_send.cursize - 8, (unsigned char)(chan->outgoing_sequence - 1)); + + if (g_modfuncs.m_pfnProcessOutgoingNet) + g_modfuncs.m_pfnProcessOutgoingNet(chan, &sb_send); + + NET_SendPacket(chan->sock, sb_send.cursize, sb_send.data, chan->remote_address); + } + + if (g_psv.active && sv_lan.value != 0.0f && sv_lan_rate.value > 1000.0) + fRate = 1.0 / sv_lan_rate.value; + else + fRate = 1.0 / chan->rate; + + if (chan->cleartime < realtime) { + chan->cleartime = realtime; + } + + chan->cleartime += (sb_send.cursize + UDP_HEADER_SIZE) * fRate; + + if (net_showpackets.value != 0.0f && net_showpackets.value != 2.0f) { + char c = (chan == &g_pcls.netchan) ? 'c' : 's'; + + Con_Printf(" %c --> sz=%i seq=%i ack=%i rel=%i tm=%f\n" + , c + , sb_send.cursize + , chan->outgoing_sequence - 1 + , chan->incoming_sequence + , send_reliable ? 1 : 0 + , (float)(chan == &g_pcls.netchan ? g_pcl.time : g_psv.time)); + } +} + +/* <65449> ../engine/net_chan.c:730 */ +fragbuf_t *Netchan_FindBufferById(fragbuf_t **pplist, int id, qboolean allocate) +{ + fragbuf_t *list = *pplist; + fragbuf_t *pnewbuf; + + while (list) + { + if (list->bufferid == id) + return list; + + list = list->next; + } + + if (!allocate) + return NULL; + + // Create new entry + pnewbuf = Netchan_AllocFragbuf(); + pnewbuf->bufferid = id; + Netchan_AddBufferToList(pplist, pnewbuf); + + return pnewbuf; +} + +/* <65e8c> ../engine/net_chan.c:767 */ +void Netchan_CheckForCompletion(netchan_t *chan, int stream, int intotalbuffers) +{ + int c; + int size; + int id; + fragbuf_t *p; + + size = 0; + c = 0; + + p = chan->incomingbufs[stream]; + if (!p) + return; + + while (p) + { + size += p->frag_message.cursize; + c++; + + id = FRAG_GETID(p->bufferid); + if (id != c && chan == &g_pcls.netchan) + { + if (chan->sock == NS_MULTICAST) + { + char szCommand[32]; + _snprintf(szCommand, sizeof(szCommand), "listen %s\n", NET_AdrToString(chan->remote_address)); + Cbuf_AddText(szCommand); + return; + } + Con_Printf("Netchan_CheckForCompletion: Lost/dropped fragment would cause stall, retrying connection\n"); + Cbuf_AddText("retry\n"); + } + + p = p->next; + } + + // Received final message + if (c == intotalbuffers) + { + chan->incomingready[stream] = true; + } +} + +/* <65f1e> ../engine/net_chan.c:826 */ +qboolean Netchan_Validate(netchan_t *chan, qboolean *frag_message, unsigned int *fragid, int *frag_offset, int *frag_length) +{ + for (int i = 0; i < MAX_STREAMS; i++) + { + if (!frag_message[i]) + continue; + + if (FRAG_GETID(fragid[i]) > MAX_FRAGMENTS || FRAG_GETCOUNT(fragid[i]) > MAX_FRAGMENTS) + { + return FALSE; + } + + if ((unsigned int)frag_length[i] > 0x800 || (unsigned int)frag_offset[i] > 0x4000) + { + return FALSE; + } + + } + + return TRUE; +} + +/* <65fe9> ../engine/net_chan.c:872 */ +qboolean Netchan_Process(netchan_t *chan) +{ + // int i; // 874 + // unsigned int sequence; // 875 + // unsigned int sequence_ack; // 875 + // unsigned int reliable_ack; // 876 + // unsigned int reliable_message; // 876 + // unsigned int fragid; // 877 + // qboolean frag_message; // 878 + // int frag_offset; // 879 + // int frag_length; // 880 + // qboolean message_contains_fragments; // 881 + // Netchan_Validate(netchan_t *chan, + // qboolean *frag_message, + // unsigned int *fragid, + // int *frag_offset, + // int *frag_length); /* size=0, low_pc=0 */ // 933 + // { + // char c; // 946 + // int mask; // 947 + // } + // { + // int j; // 1038 + // unsigned char *src; // 1039 + // unsigned char *dst; // 1039 + // int len; // 1040 + // fragbuf_t *pbuf; // 1041 + // int inbufferid; // 1042 + // int intotalbuffers; // 1043 + // Netchan_FindBufferById(fragbuf_t **pplist, + // int id, + // qboolean allocate); /* size=0, low_pc=0 */ // 1053 + // { + // int nbytes; // 1056 + // } + // } + + int i; + unsigned int sequence, sequence_ack; + unsigned int reliable_ack, reliable_message; + unsigned int fragid[MAX_STREAMS] = { 0, 0 }; + qboolean frag_message[MAX_STREAMS] = { false, false }; + int frag_offset[MAX_STREAMS] = { 0, 0 }; + int frag_length[MAX_STREAMS] = { 0, 0 }; + qboolean message_contains_fragments; + + + if (!g_pcls.demoplayback && !g_pcls.passive) + { + if (!NET_CompareAdr(net_from, chan->remote_address)) + return FALSE; + } + + chan->last_received = realtime; + + // get sequence numbers + MSG_BeginReading(); + sequence = MSG_ReadLong(); + sequence_ack = MSG_ReadLong(); + + if (sequence_ack & 0x40000000) + { + if (!g_modfuncs.m_pfnProcessIncomingNet) + return FALSE; + } + + if (g_modfuncs.m_pfnProcessIncomingNet) + { + if (!g_modfuncs.m_pfnProcessIncomingNet(chan, &net_message)) + return FALSE; + } + + reliable_message = sequence >> 31; + reliable_ack = sequence_ack >> 31; + message_contains_fragments = sequence & (1 << 30) ? true : false; + + COM_UnMunge2(&net_message.data[8], net_message.cursize - 8, sequence & 0xFF); + if (message_contains_fragments) + { + for (i = 0; i < MAX_STREAMS; i++) + { + if (MSG_ReadByte()) + { + frag_message[i] = true; + fragid[i] = MSG_ReadLong(); + frag_offset[i] = MSG_ReadShort(); + frag_length[i] = MSG_ReadShort(); + } + } + + if (!Netchan_Validate(chan, frag_message, fragid, frag_offset, frag_offset)) + return FALSE; + } + + sequence &= ~(1 << 31); + sequence &= ~(1 << 30); + sequence_ack &= ~(1 << 31); + sequence_ack &= ~(1 << 30); + + if (net_showpackets.value != 0.0 && net_showpackets.value != 3.0) + { + char c = (chan == &g_pcls.netchan) ? 'c' : 's'; + + Con_Printf( + " %c <-- sz=%i seq=%i ack=%i rel=%i tm=%f\n", + c, + net_message.cursize, + sequence, + sequence_ack, + reliable_message, + (chan == &g_pcls.netchan) ? g_pcl.time : g_psv.time); + } + + if (sequence <= (unsigned)chan->incoming_sequence) + { + if (net_showdrop.value != 0.0) { + if (sequence == (unsigned)chan->incoming_sequence) + Con_Printf("%s:duplicate packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence); + else + Con_Printf("%s:out of order packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence); + } + return FALSE; + } + + // + // dropped packets don't keep the message from being used + // + net_drop = sequence - (chan->incoming_sequence + 1); + if (net_drop > 0 && net_showdrop.value != 0.0) + { + Con_Printf("%s:Dropped %i packets at %i\n", NET_AdrToString(chan->remote_address), net_drop, sequence); + } + + // + // if the current outgoing reliable message has been acknowledged + // clear the buffer to make way for the next + // + if (reliable_ack == (unsigned)chan->reliable_sequence) + { + // Make sure we actually could have ack'd this message + if (chan->incoming_acknowledged + 1 >= chan->last_reliable_sequence) + { + chan->reliable_length = 0; // it has been received + } + } + + // + // if this message contains a reliable message, bump incoming_reliable_sequence + // + chan->incoming_sequence = sequence; + chan->incoming_acknowledged = sequence_ack; + chan->incoming_reliable_acknowledged = reliable_ack; + if (reliable_message) + { + chan->incoming_reliable_sequence ^= 1; + } + + int statId = chan->flow[FLOW_INCOMING].current & 0x1F; + chan->flow[FLOW_INCOMING].stats[statId].size = net_message.cursize + UDP_HEADER_SIZE; + chan->flow[FLOW_INCOMING].stats[statId].time = realtime; + chan->flow[FLOW_INCOMING].current++; + Netchan_UpdateFlow(chan); + + if (message_contains_fragments) + { + for (i = 0; i < MAX_STREAMS; i++) + { + int j; + fragbuf_t *pbuf; + int inbufferid; + int intotalbuffers; + + if (!frag_message[i]) + continue; + + inbufferid = FRAG_GETID(fragid[i]); + intotalbuffers = FRAG_GETCOUNT(fragid[i]); + + if (fragid[i] != 0) + { + pbuf = Netchan_FindBufferById(&chan->incomingbufs[i], fragid[i], true); + if (pbuf) { + int len = frag_length[i]; + SZ_Clear(&pbuf->frag_message); + SZ_Write(&pbuf->frag_message, &net_message.data[msg_readcount + frag_offset[i]], len); + } + else { + Con_Printf("Netchan_Process: Couldn't allocate or find buffer %i\n", inbufferid); + } + // Count # of incoming bufs we've queued? are we done? + Netchan_CheckForCompletion(chan, i, intotalbuffers); + } + + // Rearrange incoming data to not have the frag stuff in the middle of it + + int wpos = msg_readcount + frag_offset[i]; + int rpos = msg_readcount + frag_offset[i] + frag_length[i]; + int epos = net_message.cursize - rpos; + for (j = 0; j < epos; j++) { + net_message.data[wpos + j] = net_message.data[rpos + j]; + } + net_message.cursize -= frag_length[i]; + for (j = i + 1; j < MAX_STREAMS; j++) + { + frag_offset[j] -= frag_length[i]; + } + } + + // Is there anything left to process? + if (net_message.cursize <= 16) + return FALSE; + } + + return TRUE; +} + +/* <65aeb> ../engine/net_chan.c:1123 */ +void Netchan_FragSend(netchan_t *chan) +{ + fragbufwaiting_t *wait; + int i; + + if (!chan) + return; + + for (i = 0; i < MAX_STREAMS; i++) + { + // Already something queued up, just leave in waitlist + if (chan->fragbufs[i]) + { + continue; + } + + wait = chan->waitlist[i]; + + // Nothing to queue? + if (!wait) + { + continue; + } + + chan->waitlist[i] = wait->next; + + wait->next = NULL; + + // Copy in to fragbuf + chan->fragbufs[i] = wait->fragbufs; + chan->fragbufcount[i] = wait->fragbufcount; + + // Throw away wait list + Mem_Free(wait); + } +} + +/* <66273> ../engine/net_chan.c:1165 */ +void Netchan_AddBufferToList(fragbuf_t **pplist, fragbuf_t *pbuf) +{ + // Find best slot + fragbuf_t *pprev, *n; + int id1, id2; + + pbuf->next = NULL; + + if (!pplist) + return; + + if (!*pplist) + { + pbuf->next = *pplist; + *pplist = pbuf; + return; + } + + pprev = *pplist; + while (pprev->next) + { + n = pprev->next; // Next item in list + id1 = FRAG_GETID(n->bufferid); + id2 = FRAG_GETID(pbuf->bufferid); + + if (id1 > id2) + { + // Insert here + pbuf->next = n->next; + pprev->next = pbuf; + return; + } + + pprev = pprev->next; + } + + // Insert at end + pprev->next = pbuf; +} + +/* <6554c> ../engine/net_chan.c:1211 */ +fragbuf_t *Netchan_AllocFragbuf(void) +{ + fragbuf_t *buf; + + buf = (fragbuf_t *)Mem_ZeroMalloc(sizeof(fragbuf_t)); + buf->bufferid = 0; + buf->frag_message.cursize = 0; + buf->frag_message.data = buf->frag_message_buf; + buf->frag_message.maxsize = FRAGMENT_SIZE; + buf->frag_message.buffername = "Frag Buffer Alloc'd"; + buf->next = 0; + + return buf; +} + +/* <65302> ../engine/net_chan.c:1234 */ +void Netchan_AddFragbufToTail(fragbufwaiting_t *wait, fragbuf_t *buf) +{ + fragbuf_t *p; + + buf->next = 0; + wait->fragbufcount++; + + p = wait->fragbufs; + if (p) + { + while (p->next) + { + p = p->next; + } + p->next = buf; + } + else + { + wait->fragbufs = buf; + } +} + +/* <6556c> ../engine/net_chan.c:1261 */ +void Netchan_CreateFragments_(qboolean server, netchan_t *chan, sizebuf_t *msg) +{ + fragbuf_t *buf; + int chunksize; + int send; + int remaining; + int pos; + int bufferid = 1; + fragbufwaiting_t *wait, *p; + + if (msg->cursize == 0) + { + return; + } + + // Compress if not done already + if (msg->data[0] != 'B' || msg->data[1] != 'Z' || msg->data[2] != '2' || msg->data[3] != 0) + { + unsigned char compressed[65536]; + char hdr[4] = "BZ2"; + unsigned int compressedSize = msg->cursize - sizeof(hdr); // we should fit in same data buffer minus 4 bytes for a header + if (!BZ2_bzBuffToBuffCompress((char *)compressed, &compressedSize, (char *)msg->data, msg->cursize, 9, 0, 30)) + { + Con_DPrintf("Compressing split packet (%d -> %d bytes)\n", msg->cursize, compressedSize); + memcpy(msg->data, hdr, sizeof(hdr)); + memcpy(msg->data + sizeof(hdr), compressed, compressedSize); + msg->cursize = compressedSize + sizeof(hdr); + } + } + +#ifdef REHLDS_FIXES + chunksize = clamp(chan->pfnNetchan_Blocksize(chan->connection_status), 64, 1200); +#else + chunksize = chan->pfnNetchan_Blocksize(chan->connection_status); +#endif // REHLDS_FIXES + + + wait = (fragbufwaiting_t *)Mem_ZeroMalloc(sizeof(fragbufwaiting_t)); + + remaining = msg->cursize; + pos = 0; + while (remaining > 0) + { + send = min(remaining, chunksize); + remaining -= send; + + buf = Netchan_AllocFragbuf(); + if (!buf) + { + return; + } + + buf->bufferid = bufferid++; + + // Copy in data + SZ_Clear(&buf->frag_message); + SZ_Write(&buf->frag_message, &msg->data[pos], send); + pos += send; + + Netchan_AddFragbufToTail(wait, buf); + } + + // Now add waiting list item to the end of buffer queue + if (!chan->waitlist[FRAG_NORMAL_STREAM]) + { + chan->waitlist[FRAG_NORMAL_STREAM] = wait; + } + else + { + p = chan->waitlist[FRAG_NORMAL_STREAM]; + while (p->next) + { + p = p->next; + } + p->next = wait; + } +} + +/* <6635e> ../engine/net_chan.c:1353 */ +void Netchan_CreateFragments(qboolean server, netchan_t *chan, sizebuf_t *msg) +{ + // Always queue any pending reliable data ahead of the fragmentation buffer + if (chan->message.cursize > 0) + { + Netchan_CreateFragments_(server, chan, &chan->message); + chan->message.cursize = 0; + } + + Netchan_CreateFragments_(server, chan, msg); +} + +/* <663e4> ../engine/net_chan.c:1371 */ +void Netchan_CreateFileFragmentsFromBuffer(qboolean server, netchan_t *chan, const char *filename, unsigned char *uncompressed_pbuf, int uncompressed_size) +{ + int chunksize; + int send; + fragbufwaiting_t *p; + fragbuf_t *buf; + unsigned char *pbuf; + signed int bCompressed; + signed int firstfragment; + signed int bufferid; + int remaining; + int pos; + unsigned int size; + fragbufwaiting_t *wait; + + if (!uncompressed_size == 0) + return; + + bufferid = 1; + firstfragment = TRUE; + size = uncompressed_size; + + pbuf = (unsigned char *)Mem_Malloc(uncompressed_size); + if (BZ2_bzBuffToBuffCompress((char*)pbuf, &size, (char*)uncompressed_pbuf, uncompressed_size, 9, 0, 30)) + { + bCompressed = FALSE; + Mem_Free(pbuf); + pbuf = uncompressed_pbuf; + size = uncompressed_size; + } + else + { + bCompressed = TRUE; + Con_DPrintf("Compressed %s for transmission (%d -> %d)\n", filename, uncompressed_size, size); + } + + chunksize = chan->pfnNetchan_Blocksize(chan->connection_status); + send = chunksize; + wait = (fragbufwaiting_t *)Mem_ZeroMalloc(0xCu); + remaining = size; + pos = 0; + + while (remaining > 0) + { + send = min(remaining, chunksize); + buf = (fragbuf_t *)Netchan_AllocFragbuf(); + if (!buf) + { + Con_Printf("Couldn't allocate fragbuf_t\n"); + Mem_Free(wait); + if (server) + SV_DropClient(host_client, 0, "Malloc problem"); + else + rehlds_syserror(__FUNCTION__ "Reverse me: client-side code"); + + return; + } + + buf->bufferid = bufferid++; + SZ_Clear(&buf->frag_message); + if (firstfragment) + { + firstfragment = FALSE; + MSG_WriteString(&buf->frag_message, filename); + MSG_WriteString(&buf->frag_message, bCompressed ? "bz2" : "uncompressed"); + MSG_WriteLong(&buf->frag_message, uncompressed_size); + send -= buf->frag_message.cursize; + } + + buf->isbuffer = TRUE; + buf->isfile = TRUE; + buf->size = send; + buf->foffset = pos; + + MSG_WriteBuf(&buf->frag_message, send, &pbuf[pos]); + pos += send; + remaining -= send; + + Netchan_AddFragbufToTail(wait, buf); + } + + if (!chan->waitlist[FRAG_FILE_STREAM]) { + chan->waitlist[FRAG_FILE_STREAM] = wait; + } + else + { + p = chan->waitlist[FRAG_FILE_STREAM]; + while (p->next) + p = p->next; + + p->next = wait; + } + +} + +/* <66564> ../engine/net_chan.c:1500 */ +int Netchan_CreateFileFragments(qboolean server, netchan_t *chan, const char *filename) +{ + int chunksize; + int compressedFileTime; + FileHandle_t hfile; + signed int filesize; + int remaining; + fragbufwaiting_t *p; + int send; + fragbuf_t *buf; + char compressedfilename[260]; + int firstfragment; + int bufferid; + int bCompressed; + int pos; + fragbufwaiting_t *wait; + int uncompressed_size; + + bufferid = 1; + firstfragment = TRUE; + bCompressed = FALSE; + chunksize = chan->pfnNetchan_Blocksize(chan->connection_status); + + Q_snprintf(compressedfilename, 0x104u, "%s.ztmp", filename); + compressedFileTime = FS_GetFileTime(compressedfilename); + if (compressedFileTime >= FS_GetFileTime(filename)) + { + hfile = FS_Open(compressedfilename, "rb"); + if (hfile) + { + filesize = FS_Size(hfile); + FS_Close(hfile); + bCompressed = 1; + hfile = FS_Open(filename, "rb"); + if (!hfile) + { + Con_Printf("Warning: Unable to open %s for transfer\n", filename); + return 0; + } + + uncompressed_size = FS_Size(hfile); + if (uncompressed_size > sv_filetransfermaxsize.value) + { + FS_Close(hfile); + Con_Printf("Warning: File %s is too big to transfer from host %s\n", filename, NET_AdrToString(chan->remote_address)); + return 0; + } + } + } + else + { + hfile = FS_Open(filename, "rb"); + if (!hfile) + { + Con_Printf("Warning: Unable to open %s for transfer\n", filename); + return 0; + } + filesize = FS_Size(hfile); + if (filesize > sv_filetransfermaxsize.value) + { + FS_Close(hfile); + Con_Printf("Warning: File %s is too big to transfer from host %s\n", filename, NET_AdrToString(chan->remote_address)); + return 0; + } + + uncompressed_size = filesize; + if (sv_filetransfercompression.value != 0.0) + { + unsigned char* uncompressed = (unsigned char*)Mem_Malloc(filesize); + unsigned char* compressed = (unsigned char*)Mem_Malloc(filesize); + unsigned int compressedSize = filesize; + FS_Read(uncompressed, filesize, 1, hfile); + if (BZ_OK == BZ2_bzBuffToBuffCompress((char*)compressed, &compressedSize, (char*)uncompressed, filesize, 9, 0, 30)) + { + FileHandle_t destFile = FS_Open(compressedfilename, "wb"); + if (destFile) + { + Con_DPrintf("Creating compressed version of file %s (%d -> %d)\n", filename, filesize, compressedSize); + FS_Write(compressed, compressedSize, 1, destFile); + FS_Close(destFile); + filesize = compressedSize; + bCompressed = 1; + } + } + Mem_Free(uncompressed); + Mem_Free(compressed); + } + } + FS_Close(hfile); + + wait = (fragbufwaiting_t *)Mem_ZeroMalloc(0xCu); + remaining = filesize; + pos = 0; + + while (remaining) + { + send = min(chunksize, remaining); + buf = Netchan_AllocFragbuf(); + if (!buf) + { + Con_Printf("Couldn't allocate fragbuf_t\n"); + Mem_Free(wait); + if (server) + { + SV_DropClient(host_client, 0, "Malloc problem"); + return 0; + } + else + { + rehlds_syserror(__FUNCTION__ ": Reverse clientside code"); + return 0; + } + } + + buf->bufferid = bufferid++; + SZ_Clear(&buf->frag_message); + if (firstfragment) + { + firstfragment = FALSE; + MSG_WriteString(&buf->frag_message, filename); + MSG_WriteString(&buf->frag_message, bCompressed ? "bz2" : "uncompressed"); + MSG_WriteLong(&buf->frag_message, uncompressed_size); + send -= buf->frag_message.cursize; + } + buf->isfile = TRUE; + buf->iscompressed = bCompressed; + buf->size = send; + buf->foffset = pos; + + Q_strncpy(buf->filename, filename, MAX_PATH - 1); + buf->filename[MAX_PATH - 1] = 0; + + pos += send; + remaining -= send; + + Netchan_AddFragbufToTail(wait, buf); + } + + if (!chan->waitlist[FRAG_FILE_STREAM]) + { + chan->waitlist[FRAG_FILE_STREAM] = wait; + } + else + { + p = chan->waitlist[FRAG_FILE_STREAM]; + while (p->next) + p = p->next; + + p->next = wait; + } + + return 1; +} + +/* <6674e> ../engine/net_chan.c:1699 */ +void Netchan_FlushIncoming(netchan_t *chan, int stream) +{ + fragbuf_t *p, *n; + + SZ_Clear(&net_message); + msg_readcount = 0; + + p = chan->incomingbufs[stream]; + while (p) + { + n = p->next; + Mem_Free(p); + p = n; + }; + + chan->incomingbufs[stream] = NULL; + chan->incomingready[stream] = FALSE; +} + +/* <66786> ../engine/net_chan.c:1723 */ +qboolean Netchan_CopyNormalFragments(netchan_t *chan) +{ + fragbuf_t *p, *n; + + if (!chan->incomingready[FRAG_NORMAL_STREAM]) + return FALSE; + + if (!chan->incomingbufs[FRAG_NORMAL_STREAM]) + { + Con_Printf("Netchan_CopyNormalFragments: Called with no fragments readied\n"); + chan->incomingready[FRAG_NORMAL_STREAM] = FALSE; + return FALSE; + } + + p = chan->incomingbufs[FRAG_NORMAL_STREAM]; + + SZ_Clear(&net_message); + MSG_BeginReading(); + + while (p) + { + n = p->next; + + SZ_Write(&net_message, p->frag_message.data, p->frag_message.cursize); + + Mem_Free(p); + p = n; + } + + if (net_message.data[0] == 'B' && net_message.data[1] == 'Z' && net_message.data[2] == '2' && net_message.data[3] == 0) + { + char uncompressed[65536]; + unsigned int uncompressedSize = 65536; + BZ2_bzBuffToBuffDecompress(uncompressed, &uncompressedSize, (char*)net_message.data + 4, net_message.cursize - 4, 1, 0); + memcpy(net_message.data, uncompressed, uncompressedSize); + net_message.cursize = uncompressedSize; + } + + chan->incomingbufs[FRAG_NORMAL_STREAM] = NULL; + chan->incomingready[FRAG_NORMAL_STREAM] = false; + + return TRUE; +} + +/* <667f7> ../engine/net_chan.c:1789 */ +qboolean Netchan_CopyFileFragments(netchan_t *chan) +{ + fragbuf_t *p; + int nsize; + unsigned char *buffer; + int pos; + signed int cursize; + char filename[MAX_PATH]; + char compressor[32]; + fragbuf_s *n; + qboolean bCompressed; + size_t uncompressedSize; + + + if (!chan->incomingready[FRAG_FILE_STREAM]) + return FALSE; + + p = chan->incomingbufs[FRAG_FILE_STREAM]; + if (!p) + { + Con_Printf("Netchan_CopyFileFragments: Called with no fragments readied\n"); + chan->incomingready[FRAG_FILE_STREAM] = FALSE; + return FALSE; + } + + bCompressed = FALSE; + SZ_Clear(&net_message); + MSG_BeginReading(); + SZ_Write(&net_message, p->frag_message.data, p->frag_message.cursize); + Q_strncpy(filename, MSG_ReadString(), sizeof(filename) - 1); + filename[sizeof(filename) - 1] = 0; + + Q_strncpy(compressor, MSG_ReadString(), sizeof(compressor) - 1); + compressor[sizeof(compressor) - 1] = 0; + if (!Q_stricmp(compressor, "bz2")) + bCompressed = TRUE; + + uncompressedSize = MSG_ReadLong(); + if (Q_strlen(filename) <= 0) + { + Con_Printf("File fragment received with no filename\nFlushing input queue\n"); + Netchan_FlushIncoming(chan, 1); + return FALSE; + } + + if (Q_strstr(filename, "..")) + { + Con_Printf("File fragment received with relative path, ignoring\n"); + Netchan_FlushIncoming(chan, 1); + return FALSE; + } + + if (filename[0] != '!' && !IsSafeFileToDownload(filename)) + { + Con_Printf("File fragment received with bad path, ignoring\n"); + Netchan_FlushIncoming(chan, 1); + return FALSE; + } + + if (g_pcls.state != ca_dedicated && filename[0] != '!') + { + Con_Printf("File fragment received with bad path, ignoring (2)\n"); + Netchan_FlushIncoming(chan, 1); + return FALSE; + } + + Q_strncpy(chan->incomingfilename, filename, MAX_PATH - 1); + chan->incomingfilename[MAX_PATH - 1] = 0; + + if (filename[0] != '!' && FS_FileExists(filename)) + { + Con_Printf("Can't download %s, already exists\n", filename); + Netchan_FlushIncoming(chan, 1); + return TRUE; + } + + nsize = 0; + while (p) + { + nsize += p->frag_message.cursize; + if (p == chan->incomingbufs[FRAG_FILE_STREAM]) + nsize -= msg_readcount; + p = p->next; + }; + + buffer = (unsigned char*)Mem_ZeroMalloc(nsize + 1); + if (!buffer) + { + Con_Printf("Buffer allocation failed on %i bytes\n", nsize + 1); + Netchan_FlushIncoming(chan, 1); + return FALSE; + } + + p = chan->incomingbufs[FRAG_FILE_STREAM]; + pos = 0; + while (p) + { + n = p->next; + + cursize = p->frag_message.cursize; + // First message has the file name, don't write that into the data stream, just write the rest of the actual data + if (p == chan->incomingbufs[FRAG_FILE_STREAM]) + { + // Copy it in + cursize -= msg_readcount; + memcpy(&buffer[pos], &p->frag_message.data[msg_readcount], cursize); + p->frag_message.cursize = cursize; + } + else + { + memcpy(&buffer[pos], p->frag_message.data, cursize); + } + pos += p->frag_message.cursize; + Mem_Free(p); + p = n; + + } + + if (bCompressed) + { + unsigned char* uncompressedBuffer = (unsigned char*)Mem_Malloc(uncompressedSize); + Con_DPrintf("Decompressing file %s (%d -> %d)\n", filename, nsize, uncompressedSize); + BZ2_bzBuffToBuffDecompress((char*)uncompressedBuffer, &uncompressedSize, (char*)buffer, nsize, 1, 0); + Mem_Free(buffer); + pos = uncompressedSize; + buffer = uncompressedBuffer; + } + + if (filename[0] == '!') + { + if (chan->tempbuffer) + { + Con_DPrintf("Netchan_CopyFragments: Freeing holdover tempbuffer\n"); + Mem_Free(chan->tempbuffer); + } + chan->tempbuffer = buffer; + chan->tempbuffersize = pos; + } + else + { + +#ifdef REHLDS_FIXES + //Don't allow to write files to FS on server + if (chan == &g_pcls.netchan) +#endif // REHLDS_FIXES + { + char filedir[MAX_PATH]; + char *pszFileName; + FileHandle_t handle; + +#ifdef REHLDS_CHECKS + strncpy(filedir, filename, sizeof(filedir) - 1); + filedir[sizeof(filedir) - 1] = 0; +#else + strncpy(filedir, filename, sizeof(filedir)); +#endif // REHLDS_CHECKS + COM_FixSlashes(filedir); + pszFileName = strrchr(filedir, '\\'); + if (pszFileName) + *pszFileName = 0; + + FS_CreateDirHierarchy(filedir, "GAMEDOWNLOAD"); + handle = FS_OpenPathID(filename, "wb", "GAMEDOWNLOAD"); + if (!handle) + { + Con_Printf("File open failed %s\n", filename); + Netchan_FlushIncoming(chan, 1); + return FALSE; + } + + Sys_Printf("COM_WriteFile: %s\n", filename); + FS_Write(buffer, pos, 1, handle); + FS_Close(handle); + } + + Mem_Free(buffer); + } + SZ_Clear(&net_message); + chan->incomingbufs[FRAG_FILE_STREAM] = 0; + chan->incomingready[FRAG_FILE_STREAM] = 0; + msg_readcount = 0; + return TRUE; +} + +/* <66ac6> ../engine/net_chan.c:2009 */ +NOXREF qboolean Netchan_IsSending(netchan_t *chan) +{ + int i; + for (i = 0; i < MAX_STREAMS; i++) + { + if(chan->fragbufs[i]) + return TRUE; + } + return FALSE; +} + +/* <66b01> ../engine/net_chan.c:2028 */ +NOXREF qboolean Netchan_IsReceiving(netchan_t *chan) +{ + int i; + for (i = 0; i < MAX_STREAMS; i++) + { + if(chan->incomingbufs[i]) + return TRUE; + } + return FALSE; +} + +/* <66b3c> ../engine/net_chan.c:2047 */ +qboolean Netchan_IncomingReady(netchan_t *chan) +{ + for (int i = 0; i < MAX_STREAMS; i++) + { + if (chan->incomingready[i]) + return TRUE; + } + return FALSE; +} + +/* <66b77> ../engine/net_chan.c:2067 */ +NOXREF void Netchan_UpdateProgress(netchan_t *chan) +{ + fragbuf_t *p; + int c = 0; + int total = 0; + int i; + float bestpercent = 0.0f; + float percent; + char sz[1024]; + char *in; + char *out; + int len = 0; + + scr_downloading.value = -1.0f; + gDownloadFile[0] = 0; + + if (net_drawslider.value != 1.0f) + { + if (!chan->incomingbufs[FRAG_FILE_STREAM]) + return; + } + for (i = MAX_STREAMS - 1; i >= 0; i--) + { + if (chan->incomingbufs[i]) + { + p = chan->incomingbufs[i]; + total = FRAG_GETCOUNT(p->bufferid); + + while (p) + { + c++; + p = p->next; + } + + if (total) + { + percent = (float)c * 100.0f / (float)total; + if (percent > bestpercent) + bestpercent = percent; + } + p = chan->incomingbufs[i]; + if (i == FRAG_FILE_STREAM) + { + in = (char *)p->frag_message.data; + out = sz; + + while (*in) + { + *out++ = *in++; + len++; + + if (len > 128) + break; + } + + *out = '\0'; + if (Q_strlen(sz) > 0 && (*sz != '!' || !Q_strncmp(sz, "!ModuleC.dll", 11))) + { + Q_strncpy(gDownloadFile, sz, 255); + gDownloadFile[255] = 0; + } + } + } + else if (chan->fragbufs[i]) + { + if (chan->fragbufcount[i]) + { + percent = (float)chan->fragbufs[i]->bufferid * 100.0f / (float)chan->fragbufcount[i]; + if (percent > bestpercent) + bestpercent = percent; + } + } + } + + scr_downloading.value = bestpercent; +} + +/* <66c7c> ../engine/net_chan.c:2170 */ +void Netchan_Init(void) +{ + Cvar_RegisterVariable(&net_log); + Cvar_RegisterVariable(&net_showpackets); + Cvar_RegisterVariable(&net_showdrop); + Cvar_RegisterVariable(&net_chokeloopback); + Cvar_RegisterVariable(&net_drawslider); + Cvar_RegisterVariable(&sv_filetransfercompression); + Cvar_RegisterVariable(&sv_filetransfermaxsize); +} + +/* <65409> ../engine/net_chan.c:2186 */ +NOXREF qboolean Netchan_CompressPacket(sizebuf_t *chan) +{ + return FALSE; +} + +/* <65429> ../engine/net_chan.c:2211 */ +NOXREF qboolean Netchan_DecompressPacket(sizebuf_t *chan) +{ + return FALSE; +} diff --git a/rehlds/engine/net_chan.h b/rehlds/engine/net_chan.h new file mode 100644 index 0000000..97da6b9 --- /dev/null +++ b/rehlds/engine/net_chan.h @@ -0,0 +1,101 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef NET_CHAN_H +#define NET_CHAN_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "cvar.h" +#include "net.h" + + +#ifdef HOOK_ENGINE + +#define gDownloadFile (*pgDownloadFile) + +#define net_drop (*pnet_drop) +#define net_log (*pnet_log) +#define net_showpackets (*pnet_showpackets) +#define net_showdrop (*pnet_showdrop) +#define net_drawslider (*pnet_drawslider) +#define net_chokeloopback (*pnet_chokeloopback) +#define sv_filetransfercompression (*psv_filetransfercompression) +#define sv_filetransfermaxsize (*psv_filetransfermaxsize) + +#endif // HOOK_ENGINE + +extern char gDownloadFile[256]; + +extern int net_drop; +extern cvar_t net_log; +extern cvar_t net_showpackets; +extern cvar_t net_showdrop; +extern cvar_t net_drawslider; +extern cvar_t net_chokeloopback; +extern cvar_t sv_filetransfercompression; +extern cvar_t sv_filetransfermaxsize; + + + +void Netchan_UnlinkFragment(fragbuf_t *buf, fragbuf_t **list); +void Netchan_OutOfBand(netsrc_t sock, netadr_t adr, int length, byte *data); +void Netchan_OutOfBandPrint(netsrc_t sock, netadr_t adr, char *format, ...); +void Netchan_ClearFragbufs(fragbuf_t **ppbuf); +void Netchan_ClearFragments(netchan_t *chan); +void Netchan_Clear(netchan_t *chan); +void Netchan_Setup(netsrc_t socketnumber, netchan_t *chan, netadr_t adr, int player_slot, void *connection_status, qboolean(*pfnNetchan_Blocksize)(void *)); +qboolean Netchan_CanPacket(netchan_t *chan); +void Netchan_UpdateFlow(netchan_t *chan); +void Netchan_Transmit(netchan_t *chan, int length, byte *data); +fragbuf_t *Netchan_FindBufferById(fragbuf_t **pplist, int id, qboolean allocate); +void Netchan_CheckForCompletion(netchan_t *chan, int stream, int intotalbuffers); +qboolean Netchan_Validate(netchan_t *chan, qboolean *frag_message, unsigned int *fragid, int *frag_offset, int *frag_length); +qboolean Netchan_Process(netchan_t *chan); +void Netchan_FragSend(netchan_t *chan); +void Netchan_AddBufferToList(fragbuf_t **pplist, fragbuf_t *pbuf); +fragbuf_t *Netchan_AllocFragbuf(void); +void Netchan_AddFragbufToTail(fragbufwaiting_t *wait, fragbuf_t *buf); +void Netchan_CreateFragments_(qboolean server, netchan_t *chan, sizebuf_t *msg); +void Netchan_CreateFragments(qboolean server, netchan_t *chan, sizebuf_t *msg); +void Netchan_CreateFileFragmentsFromBuffer(qboolean server, netchan_t *chan, const char *filename, unsigned char *uncompressed_pbuf, int uncompressed_size); +int Netchan_CreateFileFragments(qboolean server, netchan_t *chan, const char *filename); +void Netchan_FlushIncoming(netchan_t *chan, int stream); +qboolean Netchan_CopyNormalFragments(netchan_t *chan); +qboolean Netchan_CopyFileFragments(netchan_t *chan); +NOXREF qboolean Netchan_IsSending(netchan_t *chan); +NOXREF qboolean Netchan_IsReceiving(netchan_t *chan); +qboolean Netchan_IncomingReady(netchan_t *chan); +NOXREF void Netchan_UpdateProgress(netchan_t *chan); +void Netchan_Init(void); +NOXREF qboolean Netchan_CompressPacket(sizebuf_t *chan); +NOXREF qboolean Netchan_DecompressPacket(sizebuf_t *chan); + +#endif // NET_CHAN_H diff --git a/rehlds/engine/net_ws.cpp b/rehlds/engine/net_ws.cpp new file mode 100644 index 0000000..07e4a78 --- /dev/null +++ b/rehlds/engine/net_ws.cpp @@ -0,0 +1,2146 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +// Create general message queues +#define NUM_MSG_QUEUES 40 +#define MSG_QUEUE_SIZE 1536 + +#ifdef _WIN32 +CRITICAL_SECTION net_cs; +#endif // _WIN32 + +qboolean net_thread_initialized; + +loopback_t loopbacks[2]; +packetlag_t g_pLagData[3]; // List of lag structures, if fakelag is set. +float gFakeLag; +int net_configured; +#ifdef _WIN32 +netadr_t net_local_ipx_adr; +#endif +netadr_t net_local_adr; +netadr_t net_from; +sizebuf_t net_message; +qboolean noip; +qboolean noipx; + +int use_thread; + +unsigned char net_message_buffer[65536]; +unsigned char in_message_buf[65536]; +sizebuf_t in_message; +netadr_t in_from; + +int ip_sockets[3]; + +#ifdef _WIN32 +int ipx_sockets[3]; +#endif // _WIN32 + +LONGPACKET gNetSplit; +net_messages_t *messages[3]; +net_messages_t *normalqueue; +//void *hNetThread; +//int32 dwNetThreadId; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t net_address = { "net_address", "", 0, 0.0f, NULL }; +cvar_t ipname = { "ip", "localhost", 0, 0.0f, NULL }; +cvar_t defport = { "port", "27015", 0, 0.0f, NULL }; +cvar_t ip_clientport = { "ip_clientport", "0", 0, 0.0f, NULL }; +cvar_t clientport = { "clientport", "27005", 0, 0.0f, NULL }; +int net_sleepforever = 1; + +cvar_t clockwindow = { "clockwindow", "0.5", 0, 0.0f, NULL }; + +cvar_t iphostport = { "ip_hostport", "0", 0, 0.0f, NULL }; +cvar_t hostport = { "hostport", "0", 0, 0.0f, NULL }; +cvar_t multicastport = { "multicastport", "27025", 0, 0.0f, NULL }; + +#ifdef _WIN32 +cvar_t ipx_hostport = { "ipx_hostport", "0", 0, 0.0f, NULL }; +cvar_t ipx_clientport = { "ipx_clientport", "0", 0, 0.0f, NULL }; +#endif //_WIN32 + +cvar_t fakelag = { "fakelag", "0.0", 0, 0.0f, NULL }; +cvar_t fakeloss = { "fakeloss", "0.0", 0, 0.0f, NULL }; +cvar_t net_graph = { "net_graph", "0", FCVAR_ARCHIVE, 0.0f, NULL }; +cvar_t net_graphwidth = { "net_graphwidth", "150", 0, 0.0f, NULL }; +cvar_t net_scale = { "net_scale", "5", FCVAR_ARCHIVE, 0.0f, NULL }; +cvar_t net_graphpos = { "net_graphpos", "1", FCVAR_ARCHIVE, 0.0f, NULL }; + +#else //HOOK_ENGINE + +cvar_t net_address; +cvar_t ipname; +cvar_t defport; +cvar_t ip_clientport; +cvar_t clientport; +int net_sleepforever; + +cvar_t clockwindow; + +cvar_t iphostport; +cvar_t hostport; +cvar_t multicastport; + +#ifdef _WIN32 +cvar_t ipx_hostport; +cvar_t ipx_clientport; +#endif //_WIN32 + +cvar_t fakelag; +cvar_t fakeloss; +cvar_t net_graph; +cvar_t net_graphwidth; +cvar_t net_scale; +cvar_t net_graphpos; + +#endif //HOOK_ENGINE + +/* ../engine/net_ws.c:167 */ +void NET_ThreadLock(void) +{ +#ifdef _WIN32 + if (use_thread && net_thread_initialized) + { + EnterCriticalSection(&net_cs); + } +#endif // _WIN32 +} + +/* ../engine/net_ws.c:177 */ +void NET_ThreadUnlock(void) +{ +#ifdef _WIN32 + if (use_thread && net_thread_initialized) + { + LeaveCriticalSection(&net_cs); + } +#endif // _WIN32 +} + +/* ../engine/net_ws.c:187 */ +short unsigned int Q_ntohs(short unsigned int netshort) +{ + return ntohs(netshort); +} + +/* ../engine/net_ws.c:194 */ +void NetadrToSockadr(netadr_t *a, struct sockaddr *s) +{ + Q_memset(s, 0, sizeof(*s)); + + switch (a->type) + { + case NA_BROADCAST: + ((struct sockaddr_in *)s)->sin_family = AF_INET; + ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)s)->sin_port = a->port; + break; + case NA_IP: + ((struct sockaddr_in *)s)->sin_family = AF_INET; + ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip; + ((struct sockaddr_in *)s)->sin_port = a->port; + break; +#ifdef _WIN32 + case NA_IPX: + s->sa_family = AF_IPX; + Q_memcpy(s->sa_data, a->ipx, 10); + *(unsigned short *)&s->sa_data[10] = a->port; + break; + case NA_BROADCAST_IPX: + s->sa_family = AF_IPX; + Q_memset(&s->sa_data, 0, 4); + Q_memset(&s->sa_data[4], 255, 6); + *(unsigned short *)&s->sa_data[10] = a->port; + break; +#endif // _WIN32 + default: + break; + } +} + +/* ../engine/net_ws.c:228 */ +void SockadrToNetadr(const struct sockaddr *s, netadr_t *a) +{ + if (s->sa_family == AF_INET) + { + a->type = NA_IP; + *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr; + a->port = ((struct sockaddr_in *)s)->sin_port; + } +#ifdef _WIN32 + else if (s->sa_family == AF_IPX) + { + a->type = NA_IPX; + Q_memcpy(a->ipx, s->sa_data, 10); + a->port = *(unsigned short *)&s->sa_data[10]; + } +#endif // _WIN32 +} + +/* ../engine/net_ws.c:247 */ +NOXREF short unsigned int NET_HostToNetShort(short unsigned int us_in) +{ + NOXREFCHECK; + + return htons(us_in); +} + +/* ../engine/net_ws.c:252 */ +qboolean NET_CompareAdr(netadr_t a, netadr_t b) +{ + if (a.type != b.type) + { + return FALSE; + } + if (a.type == NA_LOOPBACK) + { + return TRUE; + } + + if (a.type == NA_IP) + { + if (a.ip[0] == b.ip[0] && + a.ip[1] == b.ip[1] && + a.ip[2] == b.ip[2] && + a.ip[3] == b.ip[3] && + a.port == b.port) + return TRUE; + } +#ifdef _WIN32 + else if (a.type == NA_IPX) + { + if (Q_memcmp(a.ipx, b.ipx, 10) == 0 && + a.port == b.port) + return TRUE; + } +#endif // _WIN32 + + return FALSE; +} + +/* ../engine/net_ws.c:277 */ +qboolean NET_CompareClassBAdr(netadr_t a, netadr_t b) +{ + if (a.type != b.type) + { + return FALSE; + } + if (a.type == NA_LOOPBACK) + { + return TRUE; + } + + if (a.type == NA_IP) + { + if (a.ip[0] == b.ip[0] && + a.ip[1] == b.ip[1]) + return TRUE; + } +#ifdef _WIN32 + else if (a.type == NA_IPX) + { + return TRUE; + } +#endif // _WIN32 + + return FALSE; +} + +/* ../engine/net_ws.c:302 */ +qboolean NET_IsReservedAdr(netadr_t a) +{ + if (a.type == NA_LOOPBACK) + { + return TRUE; + } + if (a.type == NA_IP) + { + if (a.ip[0] == 10 || a.ip[0] == 127) + { + return TRUE; + } + if (a.ip[0] == 172 && a.ip[1] >= 16) + { + if (a.ip[1] >= 32) + { + return FALSE; + } + return TRUE; + } + if (a.ip[0] == 192 && a.ip[1] >= 168) + { + return TRUE; + } + return FALSE; + } +#ifdef _WIN32 + else if (a.type == NA_IPX) + { + return TRUE; + } +#endif // _WIN32 + + return FALSE; +} + +/* ../engine/net_ws.c:332 */ +qboolean NET_CompareBaseAdr(netadr_t a, netadr_t b) +{ + if (a.type != b.type) + { + return FALSE; + } + if (a.type == NA_LOOPBACK) + { + return TRUE; + } + + if (a.type == NA_IP) + { + if (a.ip[0] == b.ip[0] && + a.ip[1] == b.ip[1] && + a.ip[2] == b.ip[2] && + a.ip[3] == b.ip[3]) + return TRUE; + } +#ifdef _WIN32 + else if (a.type == NA_IPX) + { + if (Q_memcmp(a.ipx, b.ipx, 10) == 0) + return TRUE; + } +#endif // _WIN32 + + return FALSE; +} + +/* ../engine/net_ws.c:357 */ +char *NET_AdrToString(netadr_t a) +{ + static char s[64]; + + Q_memset(s, 0, sizeof(s)); + + if (a.type == NA_LOOPBACK) + Q_snprintf(s, sizeof(s), "loopback"); + else if (a.type == NA_IP) + Q_snprintf(s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port)); +#ifdef _WIN32 + else + Q_snprintf(s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port)); +#endif // _WIN32 + + return s; +} + +/* ../engine/net_ws.c:375 */ +char *NET_BaseAdrToString(netadr_t a) +{ + static char s[64]; + + if (a.type == NA_LOOPBACK) + { + Q_snprintf(s, sizeof(s), "loopback"); + } + else if (a.type == NA_IP) + { + Q_snprintf(s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); + } +#ifdef _WIN32 + else + { + Q_snprintf(s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9]); + } +#endif // _WIN32 + + return s; +} + +/* ../engine/net_ws.c:410 */ +qboolean NET_StringToSockaddr(const char *s, struct sockaddr *sadr) +{ + struct hostent *h; + char *colon; + int val; + char copy[128]; + + Q_memset(sadr, 0, sizeof(*sadr)); +#ifdef _WIN32 + if (Q_strlen(s) >= 24 && s[8] == ':' && s[21] == ':') + { + sadr->sa_family = AF_IPX; + + copy[2] = 0; + + copy[0] = s[0]; + copy[1] = s[1]; + sscanf(copy, "%x", &val); + sadr->sa_data[0] = (char)val; + + copy[0] = s[2]; + copy[1] = s[3]; + sscanf(copy, "%x", &val); + sadr->sa_data[1] = (char)val; + + copy[0] = s[4]; + copy[1] = s[5]; + sscanf(copy, "%x", &val); + sadr->sa_data[2] = (char)val; + + copy[0] = s[6]; + copy[1] = s[7]; + sscanf(copy, "%x", &val); + sadr->sa_data[3] = (char)val; + + copy[0] = s[9]; + copy[1] = s[10]; + sscanf(copy, "%x", &val); + sadr->sa_data[4] = (char)val; + + copy[0] = s[11]; + copy[1] = s[12]; + sscanf(copy, "%x", &val); + sadr->sa_data[5] = (char)val; + + copy[0] = s[13]; + copy[1] = s[14]; + sscanf(copy, "%x", &val); + sadr->sa_data[6] = (char)val; + + copy[0] = s[15]; + copy[1] = s[16]; + sscanf(copy, "%x", &val); + sadr->sa_data[7] = (char)val; + + copy[0] = s[17]; + copy[1] = s[18]; + sscanf(copy, "%x", &val); + sadr->sa_data[8] = (char)val; + + copy[0] = s[19]; + copy[1] = s[20]; + sscanf(copy, "%x", &val); + sadr->sa_data[9] = (char)val; + + sscanf(s + 22, "%u", &val); + *(uint16_t *)&sadr->sa_data[10] = htons(val); + + return TRUE; + } +#endif // _WIN32 + + ((sockaddr_in *)sadr)->sin_family = AF_INET; + ((sockaddr_in *)sadr)->sin_port = 0; + + Q_strncpy(copy, s, sizeof(copy) - 1); + copy[sizeof(copy) - 1] = 0; + + // Parse port + colon = copy; + while (*colon != 0) + { + if (*colon == ':') + { + *colon = 0; + val = atoi(colon + 1); + ((sockaddr_in *)sadr)->sin_port = htons(val); + } + colon++; + } + + // Parse address + ((sockaddr_in *)sadr)->sin_addr.s_addr = inet_addr(copy); + if (((sockaddr_in *)sadr)->sin_addr.s_addr == INADDR_NONE) + { + h = CRehldsPlatformHolder::get()->gethostbyname(copy); + + if (h == NULL || h->h_addr == NULL) + { + return FALSE; + } + ((sockaddr_in *)sadr)->sin_addr.s_addr = *(uint32_t *)h->h_addr; + } + return TRUE; +} + +/* ../engine/net_ws.c:483 */ +qboolean NET_StringToAdr(const char *s, netadr_t *a) +{ + struct sockaddr sadr; + + if (Q_strcmp(s, "localhost")) + { + if (!NET_StringToSockaddr(s, &sadr)) + { + return FALSE; + } + SockadrToNetadr(&sadr, a); + } + else + { + Q_memset(a, 0, sizeof(netadr_t)); + a->type = NA_LOOPBACK; + } + return TRUE; +} + +/* ../engine/net_ws.c:502 */ +qboolean NET_IsLocalAddress(netadr_t adr) +{ + return adr.type == NA_LOOPBACK ? TRUE : FALSE; +} + +/* ../engine/net_ws.c:570 */ +char *NET_ErrorString(int code) +{ +#ifdef _WIN32 + switch (code) + { + case WSAEINTR: return "WSAEINTR"; + case WSAEBADF: return "WSAEBADF"; + case WSAEACCES: return "WSAEACCES"; + case WSAEFAULT: return "WSAEFAULT"; + + case WSAEINVAL: return "WSAEINVAL"; + case WSAEMFILE: return "WSAEMFILE"; + case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK"; + case WSAEINPROGRESS: return "WSAEINPROGRESS"; + case WSAEALREADY: return "WSAEALREADY"; + case WSAENOTSOCK: return "WSAENOTSOCK"; + case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ"; + + case WSAEMSGSIZE: return "WSAEMSGSIZE"; + case WSAEPROTOTYPE: return "WSAEPROTOTYPE"; + case WSAENOPROTOOPT: return "WSAENOPROTOOPT"; + case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT"; + case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT"; + case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP"; + case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT"; + case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT"; + case WSAEADDRINUSE: return "WSAEADDRINUSE"; + case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL"; + case WSAENETDOWN: return "WSAENETDOWN"; + + case WSAENETUNREACH: return "WSAENETUNREACH"; + case WSAENETRESET: return "WSAENETRESET"; + case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR"; + case WSAECONNRESET: return "WSAECONNRESET"; + case WSAENOBUFS: return "WSAENOBUFS"; + case WSAEISCONN: return "WSAEISCONN"; + case WSAENOTCONN: return "WSAENOTCONN"; + case WSAESHUTDOWN: return "WSAESHUTDOWN"; + case WSAETOOMANYREFS: return "WSAETOOMANYREFS"; + case WSAETIMEDOUT: return "WSAETIMEDOUT"; + case WSAECONNREFUSED: return "WSAECONNREFUSED"; + case WSAELOOP: return "WSAELOOP"; + case WSAENAMETOOLONG: return "WSAENAMETOOLONG"; + case WSAEHOSTDOWN: return "WSAEHOSTDOWN"; + + case WSASYSNOTREADY: return "WSASYSNOTREADY"; + case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED"; + case WSANOTINITIALISED: return "WSANOTINITIALISED"; + case WSAEDISCON: return "WSAEDISCON"; + + case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND"; + case WSATRY_AGAIN: return "WSATRY_AGAIN"; + case WSANO_RECOVERY: return "WSANO_RECOVERY"; + case WSANO_DATA: return "WSANO_DATA"; + + default: return "NO ERROR"; + } +#else // _WIN32 + return strerror(code); +#endif // _WIN32 +} + +/* ../engine/net_ws.c:583 */ +void NET_TransferRawData(sizebuf_t *msg, unsigned char *pStart, int nSize) +{ +#ifdef REHLDS_CHECKS + if (msg->maxsize < nSize) + { + Sys_Error(__FUNCTION__ ": data size is bigger than sizebuf maxsize"); + } +#endif // REHLDS_CHECKS + Q_memcpy(msg->data, pStart, nSize); + msg->cursize = nSize; +} + +/* ../engine/net_ws.c:589 */ +qboolean NET_GetLoopPacket(netsrc_t sock, netadr_t *in_from_, sizebuf_t *msg) +{ + int i; + loopback_t *loop; + + loop = &loopbacks[sock]; + + if (loop->send - loop->get > 4) + { + loop->get = loop->send - 4; + } + + if (loop->get < loop->send) + { + i = loop->get & (MAX_LOOPBACK - 1); + loop->get++; + + NET_TransferRawData(msg, loop->msgs[i].data, loop->msgs[i].datalen); + + Q_memset(in_from_, 0, sizeof(netadr_t)); + in_from_->type = NA_LOOPBACK; + + return TRUE; + } + return FALSE; +} + +/* ../engine/net_ws.c:612 */ +void NET_SendLoopPacket(netsrc_t sock, int length, void *data, netadr_t to) +{ + int i; + loopback_t *loop; + + NET_ThreadLock(); + + loop = &loopbacks[sock ^ 1]; + + i = loop->send & (MAX_LOOPBACK - 1); + loop->send++; + +#ifdef REHLDS_CHECKS + if (sizeof(loop->msgs[i].data) < length) + { + Sys_Error(__FUNCTION__ ": data size is bigger than message storage size"); + } +#endif // REHLDS_CHECKS + + Q_memcpy(loop->msgs[i].data, data, length); + loop->msgs[i].datalen = length; + + NET_ThreadUnlock(); +} + +/* ../engine/net_ws.c:639 */ +void NET_RemoveFromPacketList(packetlag_t *pPacket) +{ + pPacket->pPrev->pNext = pPacket->pNext; + pPacket->pNext->pPrev = pPacket->pPrev; + pPacket->pPrev = 0; + pPacket->pNext = 0; +} + +/* ../engine/net_ws.c:647 */ +NOXREF int NET_CountLaggedList(packetlag_t *pList) +{ + NOXREFCHECK; + + int c; + packetlag_t *p; + + c = 0; + p = pList->pNext; + while (p && p != pList) + { + c++; + p = p->pNext; + } + + return c; +} + +/* ../engine/net_ws.c:666 */ +void NET_ClearLaggedList(packetlag_t *pList) +{ + packetlag_t *p, *n; + + p = pList->pNext; + while (p && p != pList) + { + n = p->pNext; + NET_RemoveFromPacketList(p); + if (p->pPacketData) + { + Mem_Free(p->pPacketData); + p->pPacketData = NULL; + } + Mem_Free(p); + p = n; + } + + pList->pPrev = pList; + pList->pNext = pList; +} + +/* ../engine/net_ws.c:695 */ +void NET_AddToLagged(netsrc_t sock, packetlag_t *pList, packetlag_t *pPacket, netadr_t *net_from_, sizebuf_t messagedata, float timestamp) +{ + unsigned char *pStart; + + if (pPacket->pPrev || pPacket->pNext) + { + Con_Printf("Packet already linked\n"); + return; + } + + pPacket->pPrev = pList->pPrev; + pList->pPrev->pNext = pPacket; + pList->pPrev = pPacket; + pPacket->pNext = pList; + + pStart = (unsigned char *)Mem_Malloc(messagedata.cursize); + Q_memcpy(pStart, messagedata.data, messagedata.cursize); + pPacket->pPacketData = pStart; + pPacket->nSize = messagedata.cursize; + pPacket->receivedTime = timestamp; + memcpy(&pPacket->net_from_, net_from_, sizeof(netadr_t)); +} + +/* ../engine/net_ws.c:731 */ +void NET_AdjustLag(void) +{ + static double lasttime = realtime; + double dt; + float diff; + float converge; + + dt = realtime - lasttime; + if (dt <= 0.0) + { + dt = 0.0; + } + else + { + if (dt > 0.1) + { + dt = 0.1; + } + } + lasttime = realtime; + + if (allow_cheats || fakelag.value == 0.0) + { + if (fakelag.value != gFakeLag) + { + diff = fakelag.value - gFakeLag; + converge = dt * 200.0; + if (fabs(diff) < converge) + converge = fabs(diff); + if (diff < 0.0) + converge = -converge; + gFakeLag = gFakeLag + converge; + } + } + else + { + Con_Printf("Server must enable cheats to activate fakelag\n"); + Cvar_SetValue("fakelag", 0.0); + gFakeLag = 0; + } +} + +/* ../engine/net_ws.c:784 */ +qboolean NET_LagPacket(qboolean newdata, netsrc_t sock, netadr_t *from, sizebuf_t *data) +{ + packetlag_t *pNewPacketLag; + packetlag_t *pPacket; + float curtime; + int ninterval; + static int losscount[3]; + + if (gFakeLag <= 0.0) + { + NET_ClearLagData(TRUE, TRUE); + return newdata; + } + + curtime = realtime; + if (newdata) + { + if (fakeloss.value != 0.0) + { + if (allow_cheats) + { + ++losscount[sock]; + if (fakeloss.value <= 0.0f) + { + ninterval = fabs(fakeloss.value); + if (ninterval < 2) + ninterval = 2; + if ((losscount[sock] % ninterval) == 0) + return FALSE; + } + else + { + if (RandomLong(0, 100) <= fakeloss.value) + return FALSE; + } + } + else + { + Cvar_SetValue("fakeloss", 0.0); + } + } + pNewPacketLag = (packetlag_t *)Mem_ZeroMalloc(0x28u); + NET_AddToLagged(sock, &g_pLagData[sock], pNewPacketLag, from, *data, curtime); + } + pPacket = g_pLagData[sock].pNext; + + while (pPacket != &g_pLagData[sock]) + { + if (pPacket->receivedTime <= curtime - gFakeLag / 1000.0) + break; + + pPacket = pPacket->pNext; + } + if (pPacket == &g_pLagData[sock]) + return FALSE; + + NET_RemoveFromPacketList(pPacket); + NET_TransferRawData(&in_message, pPacket->pPacketData, pPacket->nSize); + memcpy(&in_from, &pPacket->net_from_, sizeof(in_from)); + if (pPacket->pPacketData) + free(pPacket->pPacketData); + + Mem_Free(pPacket); + return TRUE; +} + +/* ../engine/net_ws.c:869 */ +void NET_FlushSocket(netsrc_t sock) +{ + struct sockaddr from; + socklen_t fromlen; + int net_socket; + unsigned char buf[4010]; + + net_socket = ip_sockets[sock]; + if (net_socket) + { + fromlen = 16; + while (CRehldsPlatformHolder::get()->recvfrom(net_socket, (char*)buf, 4010, 0, &from, &fromlen) > 0) + ; + } +} + +/* ../engine/net_ws.c:911 */ +qboolean NET_GetLong(unsigned char *pData, int size, int *outSize) +{ + int packetNumber; // 913 + int packetCount; // 913 + int sequenceNumber; // 913 + unsigned char packetID; // 914 + static int gNetSplitFlags[NET_WS_MAX_FRAGMENTS]; // 918 + SPLITPACKET *pHeader = (SPLITPACKET *) pData; // 915 + + + sequenceNumber = pHeader->sequenceNumber; + packetID = pHeader->packetID; + packetCount = packetID & 0xF; + packetNumber = (unsigned int)packetID >> 4; + if (packetNumber >= NET_WS_MAX_FRAGMENTS || packetCount > NET_WS_MAX_FRAGMENTS) + { + Con_Printf("Malformed packet number (%i)\n", packetID >> 4); + return FALSE; + } + if (gNetSplit.currentSequence == -1 || sequenceNumber != gNetSplit.currentSequence) + { + gNetSplit.currentSequence = pHeader->sequenceNumber; + gNetSplit.splitCount = packetID & 0xF; + if (net_showpackets.value == 4.0f) + Con_Printf("<-- Split packet restart %i count %i seq\n", gNetSplit.splitCount, sequenceNumber); + } + + int packetPayloadSize = size - sizeof(SPLITPACKET); + if (gNetSplitFlags[packetNumber] == sequenceNumber) + { + Con_Printf( "NET_GetLong: Ignoring duplicated split packet %i of %i ( %i bytes )\n", + packetNumber + 1, packetCount, packetPayloadSize + ); + } + else + { + if (packetNumber == packetCount - 1) + gNetSplit.totalSize = packetPayloadSize + SPLIT_SIZE * (packetCount - 1); + + --gNetSplit.splitCount; + gNetSplitFlags[packetNumber] = sequenceNumber; + + if (net_showpackets.value == 4.0f) + { + Con_Printf("<-- Split packet %i of %i, %i bytes %i seq\n", + packetNumber + 1, packetCount, packetPayloadSize, sequenceNumber + ); + } + + if (SPLIT_SIZE * packetNumber + packetPayloadSize > 4010) + { + Con_Printf("Malformed packet size (%i, %i)\n", SPLIT_SIZE * packetNumber, packetPayloadSize); + return FALSE; + } + + memcpy(&gNetSplit.buffer[SPLIT_SIZE * packetNumber], pHeader + 1, packetPayloadSize); + } + + if (gNetSplit.splitCount > 0) + return FALSE; + + if (packetCount > 0) + { + int i = 0; + while (gNetSplitFlags[i] == gNetSplit.currentSequence && i < packetCount) + ++i; + + if (i < packetCount) + { + Con_Printf( + "Split packet without all %i parts, part %i had wrong sequence %i/%i\n", + packetCount, + i + 1, + gNetSplitFlags[i], + gNetSplit.currentSequence); + return FALSE; + } + } + + gNetSplit.currentSequence = -1; + if (gNetSplit.totalSize <= 4010) + { + memcpy(pData, gNetSplit.buffer, gNetSplit.totalSize); + *outSize = gNetSplit.totalSize; + return TRUE; + } + else + { + Con_Printf("Split packet too large! %d bytes\n", gNetSplit.totalSize); + return FALSE; + } + +} + +/* ../engine/net_ws.c:1021 */ +qboolean NET_QueuePacket(netsrc_t sock) +{ + int ret; // 1023 + struct sockaddr from; // 1024 + socklen_t fromlen; // 1025 + int net_socket; // 1026 + int protocol; // 1027 + int err; // 1028 + unsigned char buf[4010]; // 1029 + +#ifdef _WIN32 + for (protocol = 0; protocol < 2; protocol++) +#else + for (protocol = 0; protocol < 1; protocol++) +#endif // _WIN32 + { + if (protocol == 0) + net_socket = ip_sockets[sock]; +#ifdef _WIN32 + else + net_socket = ipx_sockets[sock]; +#endif // _WIN32 + + if (!net_socket) + continue; + + fromlen = sizeof(from); + ret = CRehldsPlatformHolder::get()->recvfrom(net_socket, (char *)buf, 4010, 0, &from, &fromlen); + if (ret == -1) + { +#ifdef _WIN32 + err = CRehldsPlatformHolder::get()->WSAGetLastError(); + if (err != WSAENETRESET && err != WSAEWOULDBLOCK && err != WSAECONNRESET && err != WSAECONNREFUSED) +#else // _WIN32 + err = errno; + if (err != EAGAIN && err != ECONNRESET && err != ECONNREFUSED) +#endif // _WIN32 + { +#ifdef _WIN32 + if (err == WSAEMSGSIZE) +#else // _WIN32 + if (err == EMSGSIZE) +#endif // _WIN32 + { + Con_DPrintf("NET_QueuePacket: Ignoring oversized network message\n"); + } + else + { + if (g_pcls.state != ca_dedicated) + Sys_Error("NET_QueuePacket: %s", NET_ErrorString(err)); + else + Con_Printf("NET_QueuePacket: %s\n", NET_ErrorString(err)); + } + } + continue; + } + SockadrToNetadr(&from, &in_from); + if (ret != 4010) + break; + + Con_Printf("NET_QueuePacket: Oversize packet from %s\n", NET_AdrToString(in_from)); + } + + if (ret == -1 || ret == 4010) { + return NET_LagPacket(0, sock, 0, 0); + } + + NET_TransferRawData(&in_message, buf, ret); + if (*(uint32_t *)in_message.data == 0xFFFFFFFE) + { + if (in_message.cursize >= 9) + { + return NET_GetLong(in_message.data, ret, &in_message.cursize); + } + else + { + Con_Printf("Invalid split packet length %i\n", in_message.cursize); + return FALSE; + } + } + else + { + return NET_LagPacket(1, sock, &in_from, &in_message); + } +} + +/* ../engine/net_ws.c:1145 */ +int NET_Sleep_Timeout(void) +{ + fd_set fdset; + struct timeval tv; + int number; + int fps; + static int32 lasttime; + static int numFrames; + static int staggerFrames; + int32 curtime; + + fps = (int) sys_ticrate.value; + curtime = (int) Sys_FloatTime(); + if (lasttime) + { + if (curtime - lasttime > 1) + { + lasttime = curtime; + numFrames = fps; + staggerFrames = fps / 100 + 1; + } + } + else + { + lasttime = curtime; + } + + FD_ZERO(&fdset); + number = 0; + + for (int i = 0; i < 3; i++) + { + int sock = ip_sockets[i]; + + if (sock >= 0) + FD_SET(sock, &fdset); + + if (number < sock) + number = sock; + +#ifdef _WIN32 + sock = ipx_sockets[i]; + + if (sock >= 0) + FD_SET(sock, &fdset); + + if (number < sock) + number = sock; +#endif // _WIN32 + } + + tv.tv_sec = 0; + tv.tv_usec = 1000 * 1000 / fps; + if (tv.tv_usec == 0) + tv.tv_usec = 1; + + if (numFrames > 0 && numFrames % staggerFrames) + { + int res = select(number + 1, &fdset, 0, 0, &tv); + --numFrames; + return res; + } + else + { + int res = select(0, 0, 0, 0, &tv); + --numFrames; + return res; + } +} + +/* ../engine/net_ws.c:1211 */ +int NET_Sleep(void) +{ + fd_set fdset; + struct timeval tv; + int number; + + FD_ZERO(&fdset); + number = 0; + + for (int i = 0; i < 3; i++) + { + int sock = ip_sockets[i]; + + if (sock >= 0) + FD_SET(sock, &fdset); + + if (number < sock) + number = sock; + +#ifdef _WIN32 + sock = ipx_sockets[i]; + + if (sock >= 0) + FD_SET(sock, &fdset); + + if (number < sock) + number = sock; +#endif // _WIN32 + } + + tv.tv_sec = 0; + tv.tv_usec = 20 * 1000; + + return select(number + 1, &fdset, 0, 0, net_sleepforever == 0 ? &tv : NULL); +} + +/* ../engine/net_ws.c:1308 */ +void NET_StartThread(void) +{ + if (use_thread) + { + if (!net_thread_initialized) + { + net_thread_initialized = TRUE; + Sys_Error("-net_thread is not reversed yet"); +#ifdef _WIN32 + /* + InitializeCriticalSection(&net_cs); + hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)NET_ThreadMain, 0, 0, &ThreadId); + if (!hThread) + { + DeleteCriticalSection(&net_cs); + net_thread_initialized = 0; + use_thread = 0; + Sys_Error("Couldn't initialize network thread, run without -net_thread\n"); + } + */ +#endif // _WIN32 + } + } +} + +/* ../engine/net_ws.c:1333 */ +void NET_StopThread(void) +{ + if (use_thread) + { + if (net_thread_initialized) + { +#ifdef _WIN32 + /* + TerminateThread(hThread, 0); + DeleteCriticalSection(&net_cs); + */ +#endif // _WIN32 + net_thread_initialized = FALSE; + Sys_Error("-net_thread is not reversed yet"); + } + } +} + +/* ../engine/net_ws.c:1348 */ +void *net_malloc(size_t size) +{ + return Mem_ZeroMalloc(size); +} + +/* ../engine/net_ws.c:1355 */ +net_messages_t *NET_AllocMsg(int size) +{ + net_messages_t *pmsg; + if (size <= MSG_QUEUE_SIZE && normalqueue) + { + pmsg = normalqueue->next; + normalqueue->buffersize = size; + normalqueue = pmsg; + } + else + { + pmsg = (net_messages_t *)net_malloc(sizeof(net_messages_t)); + pmsg->buffer = (unsigned char *)net_malloc(size); + pmsg->buffersize = size; + pmsg->preallocated = FALSE; + } + + return pmsg; +} + +/* ../engine/net_ws.c:1377 */ +void NET_FreeMsg(net_messages_t *pmsg) +{ + if (pmsg->preallocated) + { + net_messages_t* tmp = normalqueue; + normalqueue = pmsg; + pmsg->next = tmp; + } + else + { + Mem_Free(pmsg->buffer); + Mem_Free(pmsg); + } +} + +/* ../engine/net_ws.c:1391 */ +qboolean NET_GetPacket_internal(netsrc_t sock) +{ + net_messages_t *pmsg; // 1393 + qboolean bret; // 1396 + + NET_AdjustLag(); + NET_ThreadLock(); + if (NET_GetLoopPacket(sock, &in_from, &in_message)) + { + bret = NET_LagPacket(1, sock, &in_from, &in_message); + } + else + { + if (!use_thread) + { + bret = NET_QueuePacket(sock); + if (!bret) + bret = NET_LagPacket(0, sock, 0, 0); + } + else + { + bret = NET_LagPacket(0, sock, 0, 0); + } + } + + if (bret) + { + Q_memcpy(net_message.data, in_message.data, in_message.cursize); + net_message.cursize = in_message.cursize; + memcpy(&net_from, &in_from, 0x14u); + NET_ThreadUnlock(); + return bret; + } + + pmsg = messages[sock]; + if (pmsg) + { + net_message.cursize = pmsg->buffersize; + messages[sock] = pmsg->next; + Q_memcpy(net_message.data, pmsg->buffer, net_message.cursize); + net_from = pmsg->from; + msg_readcount = 0; + NET_FreeMsg(pmsg); + bret = 1; + } + NET_ThreadUnlock(); + return bret; +} + +bool NET_GetPacketPreprocessor(uint8_t* data, unsigned int len, const netadr_t& srcAddr) { + return true; +} + +qboolean NET_GetPacket(netsrc_t sock) { + qboolean getRes = NET_GetPacket_internal(sock); + while (getRes) { + bool pass = g_RehldsHookchains.m_PreprocessPacket.callChain(NET_GetPacketPreprocessor, net_message.data, net_message.cursize, net_from); + if (pass) { + return 1; + } + + //packet was consumed by 3rd party plugin, try to read another one + getRes = NET_GetPacket_internal(sock); + } + + return 0; +} + +/* ../engine/net_ws.c:1454 */ +void NET_AllocateQueues(void) +{ + net_messages_t *p; + for (int i = 0; i < NUM_MSG_QUEUES; i++) + { + p = (net_messages_t *)Mem_ZeroMalloc(sizeof(net_messages_t)); + p->buffer = (unsigned char *)Mem_ZeroMalloc(MSG_QUEUE_SIZE); + p->preallocated = 1; + p->next = normalqueue; + normalqueue = p; + } + + NET_StartThread(); +} + +/* ../engine/net_ws.c:1473 */ +void NET_FlushQueues(void) +{ + for (int i = 0; i < 3; i++) + { + net_messages_t *p = messages[i]; + while (p) { + net_messages_t *n = p->next; + Mem_Free(p->buffer); + Mem_Free(p); + p = n; + } + + messages[i] = NULL; + } + + net_messages_t *p = normalqueue; + while (p) { + net_messages_t *n = p->next; + Mem_Free(p->buffer); + Mem_Free(p); + p = n; + } + normalqueue = NULL; +} + +/* ../engine/net_ws.c:1504 */ +int NET_SendLong(netsrc_t sock, int s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen) +{ + static long gSequenceNumber = 1; + + // Do we need to break this packet up? + if (sock == NS_SERVER && len > MAX_ROUTEABLE_PACKET) + { + // yep + char packet[MAX_ROUTEABLE_PACKET]; + int totalSent, ret, size, packetCount, packetNumber; + SPLITPACKET *pPacket; + + gSequenceNumber++; + if (gSequenceNumber < 0) + { + gSequenceNumber = 1; + } + + pPacket = (SPLITPACKET *)packet; + pPacket->netID = -2; + pPacket->sequenceNumber = gSequenceNumber; + packetNumber = 0; + totalSent = 0; + packetCount = (len + SPLIT_SIZE - 1) / SPLIT_SIZE; + + while (len > 0) + { + size = min(SPLIT_SIZE, len); + + pPacket->packetID = (packetNumber << 4) + packetCount; + + memcpy(packet + sizeof(SPLITPACKET), buf + (packetNumber * SPLIT_SIZE), size); + + if (net_showpackets.value == 4.0f) + { + netadr_t adr; + memset(&adr, 0, sizeof(adr)); + + SockadrToNetadr((struct sockaddr *)to, &adr); + + Con_DPrintf("Sending split %i of %i with %i bytes and seq %i to %s\n", + packetNumber + 1, + packetCount, + size, + gSequenceNumber, + NET_AdrToString(adr)); + } + + ret = CRehldsPlatformHolder::get()->sendto(s, packet, size + sizeof(SPLITPACKET), flags, to, tolen); + if (ret < 0) + { + return ret; + } + + if (ret >= size) + { + totalSent += size; + } + + len -= size; + packetNumber++; + } + + return totalSent; + } + else + { + int nSend = 0; + nSend = CRehldsPlatformHolder::get()->sendto(s, buf, len, flags, to, tolen); + return nSend; + } +} + +void NET_SendPacket_api(unsigned int length, void *data, const netadr_t &to) { + NET_SendPacket(NS_SERVER, length, data, to); +} + +/* ../engine/net_ws.c:1599 */ +void NET_SendPacket(netsrc_t sock, int length, void *data, netadr_t to) +{ + int ret; + struct sockaddr addr; + int net_socket; + + if (to.type == NA_LOOPBACK) + { + NET_SendLoopPacket(sock, length, data, to); + return; + } + + if (to.type == NA_BROADCAST) + { + net_socket = ip_sockets[sock]; + if (!net_socket) + return; + } + else if (to.type == NA_IP) + { + net_socket = ip_sockets[sock]; + if (!net_socket) + return; + } +#ifdef _WIN32 + else if (to.type == NA_IPX) + { + net_socket = ipx_sockets[sock]; + if (!net_socket) + return; + } + else if (to.type == NA_BROADCAST_IPX) + { + net_socket = ipx_sockets[sock]; + if (!net_socket) + return; + } +#endif // _WIN32 + else + { + Sys_Error(__FUNCTION__ ": bad address type"); + return; + } + + NetadrToSockadr(&to, &addr); + + ret = NET_SendLong(sock, net_socket, (const char *)data, length, 0, &addr, sizeof(addr)); + if (ret == -1) + { + int err; + +#ifdef _WIN32 + err = WSAGetLastError(); +#else // _WIN32 + err = errno; +#endif // _WIN32 + // wouldblock is silent + if (err == WSAEWOULDBLOCK) + return; + + if (err == WSAECONNREFUSED || err == WSAECONNRESET) + return; + + // some PPP links dont allow broadcasts + if (err == WSAEADDRNOTAVAIL && (to.type == NA_BROADCAST +#ifdef _WIN32 + || to.type == NA_BROADCAST_IPX +#endif // _WIN32 + )) + return; + + if (g_pcls.state == ca_dedicated) // let dedicated servers continue after errors + { + Con_Printf(__FUNCTION__ " ERROR: %s\n", NET_ErrorString(err)); + } + else + { + if (err == WSAEADDRNOTAVAIL || err == WSAENOBUFS) + { + Con_DPrintf(__FUNCTION__ " Warning: %s : %s\n", NET_ErrorString(err), NET_AdrToString(to)); + } + else + { + Sys_Error(__FUNCTION__ " ERROR: %s\n", NET_ErrorString(err)); + } + } + } +} + +/* ../engine/net_ws.c:1700 */ +int NET_IPSocket(char *net_interface, int port, qboolean multicast) +{ + int newsocket; + struct sockaddr_in address; + qboolean _true = TRUE; + int i = 1; + int err; + +#ifdef _WIN32 + if ((newsocket = CRehldsPlatformHolder::get()->socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) +#else + if ((newsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) +#endif // _WIN32 + { + +#ifdef _WIN32 + err = CRehldsPlatformHolder::get()->WSAGetLastError(); +#else + err = errno; +#endif // _WIN32 + if (err != WSAEAFNOSUPPORT) + Con_Printf("WARNING: UDP_OpenSocket: port: %d socket: %s", port, NET_ErrorString(err)); + return 0; + } +#ifdef _WIN32 + if (CRehldsPlatformHolder::get()->ioctlsocket(newsocket, FIONBIO, (u_long *)&_true) == SOCKET_ERROR) +#else + if (SOCKET_FIONBIO(newsocket, _true) == SOCKET_ERROR) +#endif // _WIN32 + { +#ifdef _WIN32 + err = CRehldsPlatformHolder::get()->WSAGetLastError(); +#else + err = errno; +#endif // _WIN32 + Con_Printf("WARNING: UDP_OpenSocket: port: %d ioctl FIONBIO: %s\n", port, NET_ErrorString(err)); + return 0; + } +#ifdef _WIN32 + if (CRehldsPlatformHolder::get()->setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == SOCKET_ERROR) +#else + if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == SOCKET_ERROR) +#endif + { +#ifdef _WIN32 + err = CRehldsPlatformHolder::get()->WSAGetLastError(); +#else + err = errno; +#endif // _WIN32 + Con_Printf ("WARNING: UDP_OpenSocket: port: %d setsockopt SO_BROADCAST: %s\n", port, NET_ErrorString(err)); + return 0; + } + if (COM_CheckParm("-reuse") || multicast) + { +#ifdef _WIN32 + if (CRehldsPlatformHolder::get()->setsockopt(newsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&_true, sizeof(qboolean)) == SOCKET_ERROR) +#else + if (setsockopt(newsocket, SOL_SOCKET, SO_REUSEADDR, (char *)&_true, sizeof(qboolean)) == SOCKET_ERROR) +#endif // _WIN32 + { +#ifdef _WIN32 + err = CRehldsPlatformHolder::get()->WSAGetLastError(); +#else + err = errno; +#endif // _WIN32 + Con_Printf ("WARNING: UDP_OpenSocket: port: %d setsockopt SO_REUSEADDR: %s\n", port, NET_ErrorString(err)); + return 0; + } + } +#ifndef _WIN32 + if (COM_CheckParm("-tos")) + { + i = 16; + Con_Printf("Enabling LOWDELAY TOS option\n"); + if (setsockopt(newsocket, IPPROTO_IP, IP_TOS, (char *)&i, sizeof(i)) == SOCKET_ERROR) + { + err = errno; + if (err != WSAENOPROTOOPT) + Con_Printf("WARNING: UDP_OpenSocket: port: %d setsockopt IP_TOS: %s\n", port, NET_ErrorString(err)); + return 0; + } + } +#endif // _WIN32 + if (net_interface && *net_interface && Q_stricmp(net_interface, "localhost")) + NET_StringToSockaddr(net_interface, (sockaddr *)&address); + else + address.sin_addr.s_addr = INADDR_ANY; + + if (port == -1) + address.sin_port = 0; + else address.sin_port = htons((u_short)port); + + address.sin_family = AF_INET; +#ifdef _WIN32 + if (CRehldsPlatformHolder::get()->bind(newsocket, (struct sockaddr *)&address, sizeof(address)) == SOCKET_ERROR) +#else + if (bind(newsocket, (struct sockaddr *)&address, sizeof(address)) == SOCKET_ERROR) +#endif // _WIN32 + { +#ifdef _WIN32 + err = CRehldsPlatformHolder::get()->WSAGetLastError(); +#else + err = errno; +#endif // _WIN32 + Con_Printf("WARNING: UDP_OpenSocket: port: %d bind: %s\n", port, NET_ErrorString(err)); +#ifdef _WIN32 + CRehldsPlatformHolder::get()->closesocket(newsocket); +#else + SOCKET_CLOSE(newsocket); +#endif // _WIN32 + return 0; + } + i = COM_CheckParm("-loopback") != 0; +#ifdef _WIN32 + if (CRehldsPlatformHolder::get()->setsockopt(newsocket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&i, sizeof(i)) == SOCKET_ERROR) +#else + if (setsockopt(newsocket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&i, sizeof(i)) == SOCKET_ERROR) +#endif // _WIN32 + { +#ifdef _WIN32 + err = CRehldsPlatformHolder::get()->WSAGetLastError(); +#else + err = errno; +#endif // _WIN32 + Con_DPrintf("WARNING: UDP_OpenSocket: port %d setsockopt IP_MULTICAST_LOOP: %s\n", port, NET_ErrorString(err)); + } + return newsocket; +} + +/* ../engine/net_ws.c:1842 */ +void NET_OpenIP(void) +{ + //cvar_t *ip;//unused? + int port; + int dedicated; + int sv_port = 0; + int cl_port = 0; + //int mc_port;//unused? + static qboolean bFirst = TRUE; + + port = 0; + dedicated = g_pcls.state == ca_dedicated; + + NET_ThreadLock(); + + if (!ip_sockets[NS_SERVER]) + { + port = (int)iphostport.value; + + if (!port) + { + port = (int)hostport.value; + if (!port) + { + port = (int)defport.value; + hostport.value = defport.value; + } + } + ip_sockets[NS_SERVER] = NET_IPSocket(ipname.string, port, FALSE); + + if (!ip_sockets[NS_SERVER] && dedicated) + { + Sys_Error("Couldn't allocate dedicated server IP port %d.", port); + } + sv_port = port; + } + NET_ThreadUnlock(); + + if (dedicated) + return; + + NET_ThreadLock(); + if (!ip_sockets[NS_CLIENT]) + { + port = (int)ip_clientport.value; + + if (!port) + { + port = (int)clientport.value; + if (!port) + port = -1; + } + ip_sockets[NS_CLIENT] = NET_IPSocket(ipname.string, port, FALSE); + if (!ip_sockets[NS_CLIENT]) + ip_sockets[NS_CLIENT] = NET_IPSocket(ipname.string, -1, FALSE); + cl_port = port; + } + if (!ip_sockets[NS_MULTICAST]) + { + ip_sockets[NS_MULTICAST] = NET_IPSocket(ipname.string, multicastport.value, TRUE); + if (!ip_sockets[NS_MULTICAST] && !dedicated) + Con_Printf("Warning! Couldn't allocate multicast IP port.\n"); + } + NET_ThreadUnlock(); + + if (bFirst) + { + bFirst = FALSE; + Con_Printf("NET Ports: server %i, client %i\n", sv_port, cl_port); + } +} + +#ifdef _WIN32 + +/* ../engine/net_ws.c */ +int NET_IPXSocket(int hostshort) +{ + int err; + u_long optval = 1; + SOCKET newsocket; + SOCKADDR_IPX address; + + if((newsocket = CRehldsPlatformHolder::get()->socket(PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == INVALID_SOCKET) + { + err = CRehldsPlatformHolder::get()->WSAGetLastError(); + + if (err != WSAEAFNOSUPPORT) + Con_Printf("WARNING: IPX_Socket: port: %d socket: %s\n", hostshort, NET_ErrorString(err)); + return 0; + } + if (CRehldsPlatformHolder::get()->ioctlsocket(newsocket, FIONBIO, &optval) == SOCKET_ERROR) + { + err = CRehldsPlatformHolder::get()->WSAGetLastError(); + Con_Printf("WARNING: IPX_Socket: port: %d ioctl FIONBIO: %s\n", hostshort, NET_ErrorString(err)); + return 0; + } + if (CRehldsPlatformHolder::get()->setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (const char *)&optval, sizeof(optval)) == SOCKET_ERROR) + { + err = CRehldsPlatformHolder::get()->WSAGetLastError(); + Con_Printf("WARNING: IPX_Socket: port: %d setsockopt SO_BROADCAST: %s\n", hostshort, NET_ErrorString(err)); + return 0; + } + if (CRehldsPlatformHolder::get()->setsockopt(newsocket, SOL_SOCKET, 4, (const char *)&optval, sizeof(optval)) == SOCKET_ERROR) + { + err = CRehldsPlatformHolder::get()->WSAGetLastError(); + return 0; + } + + address.sa_family = AF_IPX; + Q_memset(address.sa_netnum, 0, 4); + Q_memset(address.sa_nodenum, 0, 6); + + if (hostshort == -1) + address.sa_socket = 0; + else address.sa_socket = htons((u_short)hostshort); + + if (CRehldsPlatformHolder::get()->bind(newsocket, (struct sockaddr *)&address, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR) + { + err = CRehldsPlatformHolder::get()->WSAGetLastError(); + Con_Printf("WARNING: IPX_Socket: port: %d bind: %s\n", hostshort, NET_ErrorString(err)); + CRehldsPlatformHolder::get()->closesocket(newsocket); + return 0; + } + return newsocket; +} + +/* ../engine/net_ws.c */ +void NET_OpenIPX(void) +{ + int port; + int dedicated; + + dedicated = g_pcls.state == ca_dedicated; + NET_ThreadLock(); + if (!ipx_sockets[NS_SERVER]) + { + port = ipx_hostport.value; + if (!port) + { + port = hostport.value; + if (!port) + { + hostport.value = defport.value; + port = defport.value; + } + } + ipx_sockets[NS_SERVER] = NET_IPXSocket(port); + } + NET_ThreadUnlock(); + if(!dedicated) + { + NET_ThreadLock(); + if (!ipx_sockets[NS_CLIENT]) + { + port = ipx_clientport.value; + if (!port) + { + port = clientport.value; + if (!port) + port = -1; + } + ipx_sockets[NS_CLIENT] = NET_IPXSocket(port); + + if (!ipx_sockets[NS_CLIENT]) + ipx_sockets[NS_CLIENT] = NET_IPXSocket(-1); + } + NET_ThreadUnlock(); + } +} + +#endif // _WIN32 + +/* ../engine/net_ws.c:2076 */ +void NET_GetLocalAddress(void) +{ + char buff[512]; + struct sockaddr_in address; + int namelen; + int net_error; + + Q_memset(&net_local_adr, 0, sizeof(netadr_t)); + +#ifdef _WIN32 + Q_memset(&net_local_ipx_adr, 0, sizeof(netadr_t)); +#endif // _WIN32 + + if (noip) + { + Con_Printf("TCP/IP Disabled.\n"); + } + else + { + if (Q_strcmp(ipname.string, "localhost")) + Q_strncpy(buff, ipname.string, 511); + else + { +#ifdef _WIN32 + CRehldsPlatformHolder::get()->gethostname(buff, 512); +#else + gethostname(buff, 512); +#endif // _WIN32 + } + + buff[511] = 0; + NET_StringToAdr(buff, &net_local_adr); + namelen = sizeof(address); +#ifdef _WIN32 + if (CRehldsPlatformHolder::get()->getsockname((SOCKET)ip_sockets[NS_SERVER], (struct sockaddr *)&address, (socklen_t *)&namelen) == SOCKET_ERROR) +#else + if (getsockname((SOCKET)ip_sockets[NS_SERVER], (struct sockaddr *)&address, (socklen_t *)&namelen) == SOCKET_ERROR) +#endif // _WIN32 + { + noip = TRUE; +#ifdef _WIN32 + net_error = CRehldsPlatformHolder::get()->WSAGetLastError(); +#else + net_error = errno; +#endif // _WIN32 + Con_Printf("Could not get TCP/IP address, TCP/IP disabled\nReason: %s\n", NET_ErrorString(net_error)); + } + else + { + net_local_adr.port = address.sin_port; + Con_Printf("Server IP address %s\n", NET_AdrToString(net_local_adr)); + Cvar_Set("net_address", va(NET_AdrToString(net_local_adr))); + } + } + +#ifdef _WIN32 + if (noipx) + { + Con_Printf("No IPX Support.\n"); + } + else + { + namelen = 14; + if (CRehldsPlatformHolder::get()->getsockname(ipx_sockets[NS_SERVER], (struct sockaddr *)&address, (socklen_t *)&namelen) == SOCKET_ERROR) + { + noipx = TRUE; + net_error = CRehldsPlatformHolder::get()->WSAGetLastError(); + } + else + { + SockadrToNetadr((struct sockaddr *)&address, &net_local_ipx_adr); + Con_Printf("Server IPX address %s\n", NET_AdrToString(net_local_ipx_adr)); + } + } +#endif //_WIN32 +} + +/* ../engine/net_ws.c:2170 */ +int NET_IsConfigured(void) +{ + return net_configured; +} + +/* ../engine/net_ws.c:2182 */ +void NET_Config(qboolean multiplayer) +{ + int i; + static qboolean old_config; + static qboolean bFirst = TRUE; + + if (old_config == multiplayer) + { + return; + } + + old_config = multiplayer; + + if (multiplayer) + { + if (!noip) + NET_OpenIP(); +#ifdef _WIN32 + if (!noipx) + NET_OpenIPX(); +#endif //_WIN32 + if (bFirst) + { + bFirst = FALSE; + NET_GetLocalAddress(); + } + } + else + { + + NET_ThreadLock(); + for (i = 0; i < 3; i++) + { + if (ip_sockets[i]) + { +#ifdef _WIN32 + CRehldsPlatformHolder::get()->closesocket(ip_sockets[i]); +#else + SOCKET_CLOSE(ip_sockets[i]); +#endif //_WIN32 + ip_sockets[i] = 0; + } +#ifdef _WIN32 + if (ipx_sockets[i]) + { + CRehldsPlatformHolder::get()->closesocket(ipx_sockets[i]); + ipx_sockets[i] = 0; + } +#endif //_WIN32 + } + NET_ThreadUnlock(); + } + net_configured = multiplayer ? 1 : 0; +} + +/* ../engine/net_ws.c:2259 */ +void MaxPlayers_f(void) +{ + if (Cmd_Argc() != 2) + { + Con_Printf("\"maxplayers\" is \"%u\"\n", g_psvs.maxclients); + return; + + } + + if (g_psv.active) + { + Con_Printf("maxplayers cannot be changed while a server is running.\n"); + return; + } + + + int n = Q_atoi(Cmd_Argv(1)); + if (n < 1) + n = 1; + + if (n > g_psvs.maxclientslimit) + { + n = g_psvs.maxclientslimit; + Con_Printf("\"maxplayers\" set to \"%u\"\n", g_psvs.maxclientslimit); + } + g_psvs.maxclients = n; + + if (n == 1) + Cvar_Set("deathmatch", "0"); + else + Cvar_Set("deathmatch", "1"); +} + +/* ../engine/net_ws.c:2315 */ +void NET_Init(void) +{ +#ifdef HOOK_ENGINE + Cmd_AddCommand("maxplayers", (xcommand_t)GetOriginalFuncAddrOrDefault("MaxPlayers_f", (void *)MaxPlayers_f)); +#else + Cmd_AddCommand("maxplayers", MaxPlayers_f); +#endif // HOOK_ENGINE + + Cvar_RegisterVariable(&net_address); + Cvar_RegisterVariable(&ipname); + Cvar_RegisterVariable(&iphostport); + Cvar_RegisterVariable(&hostport); + Cvar_RegisterVariable(&defport); + Cvar_RegisterVariable(&ip_clientport); + Cvar_RegisterVariable(&clientport); + Cvar_RegisterVariable(&clockwindow); + Cvar_RegisterVariable(&multicastport); +#ifdef _WIN32 + Cvar_RegisterVariable(&ipx_hostport); + Cvar_RegisterVariable(&ipx_clientport); +#endif // _WIN32 + Cvar_RegisterVariable(&fakelag); + Cvar_RegisterVariable(&fakeloss); + Cvar_RegisterVariable(&net_graph); + Cvar_RegisterVariable(&net_graphwidth); + Cvar_RegisterVariable(&net_scale); + Cvar_RegisterVariable(&net_graphpos); + + if (COM_CheckParm("-netthread")) + use_thread = 1; + + if (COM_CheckParm("-netsleep")) + net_sleepforever = 0; + +#ifdef _WIN32 + if (COM_CheckParm("-noipx")) + noipx = TRUE; +#endif // _WIN32 + + if (COM_CheckParm("-noip")) + noip = TRUE; + + int port = COM_CheckParm("-port"); + if (port) + Cvar_SetValue("hostport", atof(com_argv[port + 1])); + + int clockwindow_ = COM_CheckParm("-clockwindow"); + if (clockwindow_) + Cvar_SetValue("clockwindow", atof(com_argv[clockwindow_ + 1])); + + net_message.data = (byte *)&net_message_buffer; + net_message.maxsize = sizeof(net_message_buffer); + net_message.flags = 0; + net_message.buffername = "net_message"; + + in_message.data = (byte *)&in_message_buf; + in_message.maxsize = sizeof(in_message_buf); + in_message.flags = 0; + in_message.buffername = "in_message"; + + for (int i = 0; i < 3; i++) + { + g_pLagData[i].pPrev = &g_pLagData[i]; + g_pLagData[i].pNext = &g_pLagData[i]; + } + + NET_AllocateQueues(); + Con_DPrintf("Base networking initialized.\n"); +} + +/* ../engine/net_ws.c:2424 */ +void NET_ClearLagData(qboolean bClient, qboolean bServer) +{ + NET_ThreadLock(); + + if (bClient) + { + NET_ClearLaggedList(&g_pLagData[0]); + NET_ClearLaggedList(&g_pLagData[2]); + } + + if (bServer) + { + NET_ClearLaggedList(&g_pLagData[1]); + } + + NET_ThreadUnlock(); +} + +/* ../engine/net_ws.c:2449 */ +void NET_Shutdown(void) +{ + NET_ThreadLock(); + + NET_ClearLaggedList(g_pLagData); + NET_ClearLaggedList(&g_pLagData[1]); + + NET_ThreadUnlock(); + + NET_Config(FALSE); + NET_FlushQueues(); +} + +/* ../engine/net_ws.c:2470 */ +qboolean NET_JoinGroup(netsrc_t sock, netadr_t addr) +{ + ip_mreq mreq; + int net_socket = ip_sockets[sock]; + SIN_SET_ADDR(&mreq.imr_multiaddr, *(unsigned int*)&addr.ip[0]); + SIN_SET_ADDR(&mreq.imr_interface, 0); + + if (CRehldsPlatformHolder::get()->setsockopt(net_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) == SOCKET_ERROR) + { +#ifdef _WIN32 + int err = WSAGetLastError(); + if (err != WSAEAFNOSUPPORT) +#else + int err = errno; + if (err != EAFNOSUPPORT) +#endif // _WIN32 + { + Con_Printf("WARNING: NET_JoinGroup: IP_ADD_MEMBERSHIP: %s", NET_ErrorString(err)); + } + return FALSE; + } + + return TRUE; +} + +/* ../engine/net_ws.c:2504 */ +qboolean NET_LeaveGroup(netsrc_t sock, netadr_t addr) +{ + ip_mreq mreq; + int net_socket = ip_sockets[sock]; + SIN_SET_ADDR(&mreq.imr_multiaddr, *(unsigned int*)&addr.ip[0]); + SIN_SET_ADDR(&mreq.imr_interface, 0); + + if (CRehldsPlatformHolder::get()->setsockopt(net_socket, 0, 6, (char *)&mreq, sizeof(mreq)) != SOCKET_ERROR) + { +#ifdef _WIN32 + int err = WSAGetLastError(); + if (err != WSAEAFNOSUPPORT) +#else + int err = errno; + if (err != EAFNOSUPPORT) +#endif // _WIN32 + { + return FALSE; + } + } + + return TRUE; +} diff --git a/rehlds/engine/net_ws.h b/rehlds/engine/net_ws.h new file mode 100644 index 0000000..ea7d7c7 --- /dev/null +++ b/rehlds/engine/net_ws.h @@ -0,0 +1,281 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef NET_WS_H +#define NET_WS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "enums.h" +#include "common.h" +#include "netadr.h" + +#ifndef _WIN32 + +#define WSAEWOULDBLOCK EWOULDBLOCK /* EAGAIN 11 */ +#define WSAEMSGSIZE EMSGSIZE /* 90 */ +#define WSAEADDRNOTAVAIL EADDRNOTAVAIL /* 99 */ +#define WSAEAFNOSUPPORT EAFNOSUPPORT /* 97 */ +#define WSAECONNRESET ECONNRESET /* 104 */ +#define WSAECONNREFUSED ECONNREFUSED /* 111 */ +#define WSAEADDRINUSE EADDRINUSE /* 98 */ +#define WSAENOBUFS ENOBUFS /* 105 */ + +#endif // _WIN32 + + +#define MAX_ROUTEABLE_PACKET 1400 + +//1400 - 9 = 1391 +#define SPLIT_SIZE (MAX_ROUTEABLE_PACKET - sizeof(SPLITPACKET)) + + + +/* ../engine/net_ws.c:137 */ +typedef struct loopmsg_s +{ + unsigned char data[NET_MAX_MESSAGE]; + int datalen; +} loopmsg_t; + +#define MAX_LOOPBACK 4 + +/* ../engine/net_ws.c:143 */ +typedef struct loopback_s +{ + loopmsg_t msgs[MAX_LOOPBACK]; + int get; + int send; +} loopback_t; + +/* ../engine/net_ws.c:151 */ +typedef struct packetlag_s +{ + unsigned char *pPacketData; // Raw stream data is stored. + int nSize; + netadr_t net_from_; + float receivedTime; + struct packetlag_s *pNext; + struct packetlag_s *pPrev; +} packetlag_t; + +/* ../engine/net_ws.c:1118 */ +typedef struct net_messages_s +{ + struct net_messages_s *next; + qboolean preallocated; + unsigned char *buffer; + netadr_t from; + int buffersize; +} net_messages_t; + +/* ../engine/net_ws.c:886 */ +// Split long packets. Anything over 1460 is failing on some routers. +typedef struct LONGPACKET_t +{ + int currentSequence; + int splitCount; + int totalSize; + // TODO: It should be NET_MAX_MESSAGE, but value differs + char buffer[4010]; // This has to be big enough to hold the largest message +} LONGPACKET; + +/* ../engine/net_ws.c:900 */ +// Use this to pick apart the network stream, must be packed +#pragma pack(push, 1) +typedef struct SPLITPACKET_t +{ + int netID; + int sequenceNumber; + unsigned char packetID; +} SPLITPACKET; +#pragma pack(pop) + + +#define NET_WS_MAX_FRAGMENTS 5 + +#ifdef HOOK_ENGINE +#define net_thread_initialized (*pnet_thread_initialized) +#define net_address (*pnet_address) +#define ipname (*pipname) +#define defport (*pdefport) +#define ip_clientport (*pip_clientport) +#define clientport (*pclientport) +#define net_sleepforever (*pnet_sleepforever) +#define loopbacks (*ploopbacks) +#define g_pLagData (*pg_pLagData) +#define gFakeLag (*pgFakeLag) +#define net_configured (*pnet_configured) +#define net_message (*pnet_message) +#ifdef _WIN32 +#define net_local_ipx_adr (*pnet_local_ipx_adr) +#endif // _WIN32 +#define net_local_adr (*pnet_local_adr) +#define net_from (*pnet_from) +#define noip (*pnoip) +#ifdef _WIN32 +#define noipx (*pnoipx) +#endif // _WIN32 +#define clockwindow (*pclockwindow) +#define use_thread (*puse_thread) +#define iphostport (*piphostport) +#define hostport (*phostport) +#define multicastport (*pmulticastport) +#ifdef _WIN32 +#define ipx_hostport (*pipx_hostport) +#define ipx_clientport (*pipx_clientport) +#endif // _WIN32 +#define fakelag (*pfakelag) +#define fakeloss (*pfakeloss) + +#define net_graph (*pnet_graph) +#define net_graphwidth (*pnet_graphwidth) +#define net_scale (*pnet_scale) +#define net_graphpos (*pnet_graphpos) +#define net_message_buffer (*pnet_message_buffer) +#define in_message_buf (*pin_message_buf) + +#define in_message (*pin_message) +#define in_from (*pin_from) +#define ip_sockets (*pip_sockets) +#ifdef _WIN32 +#define ipx_sockets (*pipx_sockets) +#endif // _WIN32 +#define gNetSplit (*pgNetSplit) +#define messages (*pmessages) +#define normalqueue (*pnormalqueue) +#endif // HOOK_ENGINE + + +extern qboolean net_thread_initialized; +extern cvar_t net_address; +extern cvar_t ipname; +extern cvar_t defport; +extern cvar_t ip_clientport; +extern cvar_t clientport; +extern int net_sleepforever; +extern loopback_t loopbacks[2]; +extern packetlag_t g_pLagData[3]; +extern float gFakeLag; +extern int net_configured; +#ifdef _WIN32 +extern netadr_t net_local_ipx_adr; +#endif // _WIN32 +extern netadr_t net_local_adr; +extern netadr_t net_from; +extern qboolean noip; +#ifdef _WIN32 +extern qboolean noipx; +#endif // _WIN32 +extern sizebuf_t net_message; +extern cvar_t clockwindow; +extern int use_thread; +extern cvar_t iphostport; +extern cvar_t hostport; +#ifdef _WIN32 +extern cvar_t ipx_hostport; +extern cvar_t ipx_clientport; +#endif // _WIN32 +extern cvar_t multicastport; +extern cvar_t fakelag; +extern cvar_t fakeloss; +extern cvar_t net_graph; +extern cvar_t net_graphwidth; +extern cvar_t net_scale; +extern cvar_t net_graphpos; +extern unsigned char net_message_buffer[65536]; +extern unsigned char in_message_buf[65536]; +extern sizebuf_t in_message; +extern netadr_t in_from; +extern int ip_sockets[3]; +#ifdef _WIN32 +extern int ipx_sockets[3]; +#endif // _WIN32 +extern LONGPACKET gNetSplit; +extern net_messages_t *messages[3]; +extern net_messages_t *normalqueue; + + +void NET_ThreadLock(void); +void NET_ThreadUnlock(void); +short unsigned int Q_ntohs(short unsigned int netshort); +void NetadrToSockadr(netadr_t *a, struct sockaddr *s); +void SockadrToNetadr(const struct sockaddr *s, netadr_t *a); +NOXREF short unsigned int NET_HostToNetShort(short unsigned int us_in); +qboolean NET_CompareAdr(netadr_t a, netadr_t b); +qboolean NET_CompareClassBAdr(netadr_t a, netadr_t b); +qboolean NET_IsReservedAdr(netadr_t a); +qboolean NET_CompareBaseAdr(netadr_t a, netadr_t b); +char *NET_AdrToString(netadr_t a); +char *NET_BaseAdrToString(netadr_t a); +qboolean NET_StringToSockaddr(const char *s, struct sockaddr *sadr); +qboolean NET_StringToAdr(const char *s, netadr_t *a); +qboolean NET_IsLocalAddress(netadr_t adr); +char *NET_ErrorString(int code); +void NET_TransferRawData(sizebuf_t *msg, unsigned char *pStart, int nSize); +qboolean NET_GetLoopPacket(netsrc_t sock, netadr_t *in_from_, sizebuf_t *msg); +void NET_SendLoopPacket(netsrc_t sock, int length, void *data, netadr_t to); +void NET_RemoveFromPacketList(packetlag_t *pPacket); +NOXREF int NET_CountLaggedList(packetlag_t *pList); +void NET_ClearLaggedList(packetlag_t *pList); +void NET_AddToLagged(netsrc_t sock, packetlag_t *pList, packetlag_t *pPacket, netadr_t *net_from_, sizebuf_t messagedata, float timestamp); +void NET_AdjustLag(void); +qboolean NET_LagPacket(qboolean newdata, netsrc_t sock, netadr_t *from, sizebuf_t *data); +void NET_FlushSocket(netsrc_t sock); +qboolean NET_GetLong(unsigned char *pData, int size, int *outSize); +qboolean NET_QueuePacket(netsrc_t sock); +int NET_Sleep_Timeout(void); +int NET_Sleep(void); +void NET_StartThread(void); +void NET_StopThread(void); +void *net_malloc(size_t size); +net_messages_t *NET_AllocMsg(int size); +void NET_FreeMsg(net_messages_t *pmsg); +qboolean NET_GetPacket(netsrc_t sock); +void NET_AllocateQueues(void); +void NET_FlushQueues(void); +int NET_SendLong(netsrc_t sock, int s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen); +void NET_SendPacket_api(unsigned int length, void *data, const netadr_t &to); +void NET_SendPacket(netsrc_t sock, int length, void *data, netadr_t to); +int NET_IPSocket(char *net_interface, int port, qboolean multicast); +void NET_OpenIP(void); +int NET_IPXSocket(int hostshort); +void NET_OpenIPX(void); +void NET_GetLocalAddress(void); +int NET_IsConfigured(void); +void NET_Config(qboolean multiplayer); +void MaxPlayers_f(void); +void NET_Init(void); +void NET_ClearLagData(qboolean bClient, qboolean bServer); +void NET_Shutdown(void); +qboolean NET_JoinGroup(netsrc_t sock, netadr_t addr); +qboolean NET_LeaveGroup(netsrc_t sock, netadr_t addr); + +#endif // NET_WS_H diff --git a/rehlds/engine/pmove.cpp b/rehlds/engine/pmove.cpp new file mode 100644 index 0000000..cf702d4 --- /dev/null +++ b/rehlds/engine/pmove.cpp @@ -0,0 +1,182 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + + + +playermove_t *pmove; +movevars_t movevars; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t pm_showclip = { "pm_showclip", "0", 0, 0.0f, NULL }; +vec_t player_mins[4][3] = { + { -16.0f, -16.0f, -36.0f, }, + { -16.0f, -16.0f, -18.0f, }, + { 0.0f, 0.0f, 0.0f, }, + { -32.0f, -32.0f, -32.0f, } +}; +vec_t player_maxs[4][3] = { + { 16.0f, 16.0f, 36.0f, }, + { 16.0f, 16.0f, 18.0f, }, + { 0.0f, 0.0f, 0.0f, }, + { 32.0f, 32.0f, 32.0f, } +}; +#else //HOOK_ENGINE + +cvar_t pm_showclip; +vec_t player_mins[4][3]; // vec_t player_mins[4][3]; +vec_t player_maxs[4][3]; // vec_t player_maxs[4][3]; + +#endif //HOOK_ENGINE + +/* <69bcf> ../engine/pmove.c:36 */ +qboolean PM_AddToTouched(pmtrace_t tr, vec_t *impactvelocity) +{ + int i; + + for (i = 0; i < pmove->numtouch; i++) + { + if (pmove->touchindex[i].ent == tr.ent) + { + return FALSE; + } + } + + if (pmove->numtouch >= MAX_PHYSENTS) + { + pmove->Con_DPrintf("Too many entities were touched!\n"); +#ifdef REHLDS_FIXES + return FALSE; // FIXED: added for preventing buffer overrun +#endif + } + + tr.deltavelocity[0] = impactvelocity[0]; + tr.deltavelocity[1] = impactvelocity[1]; + tr.deltavelocity[2] = impactvelocity[2]; + + pmove->touchindex[pmove->numtouch++] = tr; + + return TRUE; +} + +/* <69b96> ../engine/pmove.c:63 */ +void PM_StuckTouch(int hitent, pmtrace_t *ptraceresult) +{ +#ifdef REHLDS_CHECKS + if (hitent >= MAX_PHYSENTS) // FIXED: added for preventing buffer overrun + { + return; + } +#endif + + if (pmove->server) + { + int n = pmove->physents[hitent].info; + edict_t *info = EDICT_NUM(n); // looks like just entity index check + PM_AddToTouched(*ptraceresult, pmove->velocity); + } +} + +/* <69c7e> ../engine/pmove.c:79 */ +void PM_Init(playermove_t *ppm) +{ + PM_InitBoxHull(); + for (int i = 0; i < 4; i++) + { + ppm->_player_mins[i][0] = player_mins[i][0]; + ppm->_player_mins[i][1] = player_mins[i][1]; + ppm->_player_mins[i][2] = player_mins[i][2]; + ppm->_player_maxs[i][0] = player_maxs[i][0]; + ppm->_player_maxs[i][1] = player_maxs[i][1]; + ppm->_player_maxs[i][2] = player_maxs[i][2]; + } + + ppm->_movevars = &movevars; + +#ifdef HOOK_ENGINE + *(size_t*)&ppm->PM_Info_ValueForKey = (size_t)GetOriginalFuncAddrOrDefault("Info_ValueForKey", (void *)Info_ValueForKey); + *(size_t*)&ppm->PM_Particle = (size_t)GetOriginalFuncAddrOrDefault("CL_Particle", (void *)CL_Particle); + *(size_t*)&ppm->PM_TestPlayerPosition = (size_t)GetOriginalFuncAddrOrDefault("PM_TestPlayerPosition", (void *)PM_TestPlayerPosition); + *(size_t*)&ppm->Con_NPrintf = (size_t)GetFuncRefAddrOrDefault("Con_NPrintf", (void *)Con_NPrintf); + *(size_t*)&ppm->Con_DPrintf = (size_t)GetFuncRefAddrOrDefault("Con_DPrintf", (void *)Con_DPrintf); + *(size_t*)&ppm->Con_Printf = (size_t)GetFuncRefAddrOrDefault("Con_Printf", (void *)Con_Printf); + *(size_t*)&ppm->Sys_FloatTime = (size_t)GetOriginalFuncAddrOrDefault("Sys_FloatTime", (void *)Sys_FloatTime); + *(size_t*)&ppm->PM_StuckTouch = (size_t)GetOriginalFuncAddrOrDefault("PM_StuckTouch", (void *)PM_StuckTouch); + *(size_t*)&ppm->PM_PointContents = (size_t)GetOriginalFuncAddrOrDefault("PM_PointContents", (void *)PM_PointContents); + *(size_t*)&ppm->PM_TruePointContents = (size_t)GetOriginalFuncAddrOrDefault("PM_TruePointContents", (void *)PM_TruePointContents); + *(size_t*)&ppm->PM_HullPointContents = (size_t)GetOriginalFuncAddrOrDefault("PM_HullPointContents", (void *)PM_HullPointContents); + *(size_t*)&ppm->PM_PlayerTrace = (size_t)GetOriginalFuncAddrOrDefault("PM_PlayerTrace", (void *)PM_PlayerTrace); + *(size_t*)&ppm->PM_TraceLine = (size_t)GetOriginalFuncAddrOrDefault("PM_TraceLine", (void *)PM_TraceLine); + *(size_t*)&ppm->PM_TraceModel = (size_t)GetOriginalFuncAddrOrDefault("PM_TraceModel", (void *)PM_TraceModel); + *(size_t*)&ppm->RandomLong = (size_t)GetOriginalFuncAddrOrDefault("RandomLong", (void *)RandomLong); + *(size_t*)&ppm->RandomFloat = (size_t)GetOriginalFuncAddrOrDefault("RandomFloat", (void *)RandomFloat); + *(size_t*)&ppm->PM_GetModelType = (size_t)GetOriginalFuncAddrOrDefault("PM_GetModelType", (void *)PM_GetModelType); + *(size_t*)&ppm->PM_HullForBsp = (size_t)GetOriginalFuncAddrOrDefault("PM_HullForBsp", (void *)PM_HullForBsp); + *(size_t*)&ppm->PM_GetModelBounds = (size_t)GetOriginalFuncAddrOrDefault("PM_GetModelBounds", (void *)PM_GetModelBounds); + *(size_t*)&ppm->COM_FileSize = (size_t)GetOriginalFuncAddrOrDefault("COM_FileSize", (void *)COM_FileSize); + *(size_t*)&ppm->COM_LoadFile = (size_t)GetOriginalFuncAddrOrDefault("COM_LoadFile", (void *)COM_LoadFile); + *(size_t*)&ppm->COM_FreeFile = (size_t)GetOriginalFuncAddrOrDefault("COM_FreeFile", (void *)COM_FreeFile); + *(size_t*)&ppm->memfgets = (size_t)GetOriginalFuncAddrOrDefault("memfgets", (void *)memfgets); + *(size_t*)&ppm->PM_PlayerTraceEx = (size_t)GetOriginalFuncAddrOrDefault("PM_PlayerTraceEx", (void *)PM_PlayerTraceEx); + *(size_t*)&ppm->PM_TestPlayerPositionEx = (size_t)GetOriginalFuncAddrOrDefault("PM_TestPlayerPositionEx", (void *)PM_TestPlayerPositionEx); + *(size_t*)&ppm->PM_TraceLineEx = (size_t)GetOriginalFuncAddrOrDefault("PM_TraceLineEx", (void *)PM_TraceLineEx); +#else + ppm->PM_Info_ValueForKey = Info_ValueForKey; + ppm->PM_Particle = CL_Particle; + ppm->PM_TestPlayerPosition = PM_TestPlayerPosition; + ppm->Con_NPrintf = (void(*)(int idx, char *fmt, ...))Con_NPrintf; + ppm->Con_DPrintf = (void(*)(char *fmt, ...))Con_DPrintf; + ppm->Con_Printf = (void (*)(char *fmt, ...))Con_Printf; + ppm->Sys_FloatTime = Sys_FloatTime; + ppm->PM_StuckTouch = PM_StuckTouch; + ppm->PM_PointContents = PM_PointContents; + ppm->PM_TruePointContents = PM_TruePointContents; + ppm->PM_HullPointContents = PM_HullPointContents; + ppm->PM_PlayerTrace = PM_PlayerTrace; + ppm->PM_TraceLine = PM_TraceLine; + ppm->PM_TraceModel = PM_TraceModel; + ppm->RandomLong = RandomLong; + ppm->RandomFloat = RandomFloat; + ppm->PM_GetModelType = PM_GetModelType; + ppm->PM_HullForBsp = (void *(__cdecl *)(physent_t *, float *))PM_HullForBsp; + ppm->PM_GetModelBounds = PM_GetModelBounds; + ppm->COM_FileSize = COM_FileSize; + ppm->COM_LoadFile = COM_LoadFile; + ppm->COM_FreeFile = COM_FreeFile; + ppm->memfgets = memfgets; + ppm->PM_PlayerTraceEx = PM_PlayerTraceEx; + ppm->PM_TestPlayerPositionEx = PM_TestPlayerPositionEx; + ppm->PM_TraceLineEx = PM_TraceLineEx; +#endif +} diff --git a/rehlds/engine/pmove.h b/rehlds/engine/pmove.h new file mode 100644 index 0000000..84b5c7f --- /dev/null +++ b/rehlds/engine/pmove.h @@ -0,0 +1,65 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef PMOVE_H +#define PMOVE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "cvar.h" +#include "pm_defs.h" +#include "pm_movevars.h" + + +#ifdef HOOK_ENGINE +#define pm_showclip (*ppm_showclip) + +#define player_mins (*pplayer_mins) +#define player_maxs (*pplayer_maxs) + +#define pmove (*ppmove) +#define movevars (*pmovevars) +#endif // HOOK_ENGINE + + +extern cvar_t pm_showclip; + +extern vec_t player_mins[4][3]; +extern vec_t player_maxs[4][3]; + +extern playermove_t *pmove; +extern movevars_t movevars; + + +qboolean PM_AddToTouched(pmtrace_t tr, vec_t *impactvelocity); +void PM_StuckTouch(int hitent, pmtrace_t *ptraceresult); +void PM_Init(playermove_t *ppm); + +#endif // PMOVE_H diff --git a/rehlds/engine/pmovetst.cpp b/rehlds/engine/pmovetst.cpp new file mode 100644 index 0000000..6cba04d --- /dev/null +++ b/rehlds/engine/pmovetst.cpp @@ -0,0 +1,789 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +int g_contentsresult; +hull_t box_hull_0; +box_clipnodes_t box_clipnodes_0; +box_planes_t box_planes_0; + + +/* <6fbe5> ../engine/pmovetst.c:30 */ +float PM_TraceModel(physent_t *pEnt, vec_t *start, vec_t *end, trace_t *trace) +{ + hull_t *pHull; // 32 + int saveHull; // 33 + vec3_t start_l; // 34 + vec3_t end_l; // 34 + vec3_t offset; // 34 + + saveHull = pmove->usehull; + pmove->usehull = 2; + pHull = PM_HullForBsp(pEnt, offset); + pmove->usehull = saveHull; + start_l[0] = *start - offset[0]; + start_l[1] = start[1] - offset[1]; + start_l[2] = start[2] - offset[2]; + end_l[0] = *end - offset[0]; + end_l[1] = end[1] - offset[1]; + end_l[2] = end[2] - offset[2]; + SV_RecursiveHullCheck(pHull, pHull->firstclipnode, 0.0, 1.0, start_l, end_l, trace); + trace->ent = 0; + return trace->fraction; +} + +/* <6f286> ../engine/pmovetst.c:50 */ +void PM_GetModelBounds(struct model_s *mod, vec_t *mins, vec_t *maxs) +{ + mins[0] = mod->mins[0]; + mins[1] = mod->mins[1]; + mins[2] = mod->mins[2]; + + maxs[0] = mod->maxs[0]; + maxs[1] = mod->maxs[1]; + maxs[2] = mod->maxs[2]; +} + +/* <6f2ca> ../engine/pmovetst.c:57 */ +int PM_GetModelType(struct model_s *mod) +{ + return mod->type; +} + +/* <6f2f5> ../engine/pmovetst.c:70 */ +void PM_InitBoxHull(void) +{ +// int i; // 72 +// int side; // 73 + box_hull_0.clipnodes = &box_clipnodes_0[0]; + box_hull_0.planes = &box_planes_0[0]; + box_hull_0.firstclipnode = 0; + box_hull_0.lastclipnode = 5; + + for (int i = 0; i < 6; i++) + { + int side = i & 1; + box_clipnodes_0[i].planenum = i; + box_clipnodes_0[i].children[side] = -1; + box_clipnodes_0[i].children[side ^ 1] = (i != 5) ? i + 1 : CONTENTS_SOLID; + box_planes_0[i].type = i >> 1; + box_planes_0[i].normal[i >> 1] = 1.0f; + } +} + +/* <6f03c> ../engine/pmovetst.c:105 */ +hull_t *PM_HullForBox(vec_t *mins, vec_t *maxs) +{ + box_planes_0[0].dist = maxs[0]; + box_planes_0[1].dist = mins[0]; + box_planes_0[2].dist = maxs[1]; + box_planes_0[3].dist = mins[1]; + box_planes_0[4].dist = maxs[2]; + box_planes_0[5].dist = mins[2]; + return &box_hull_0; +} + +/* <6f34f> ../engine/pmovetst.c:124 */ +int PM_HullPointContents(hull_t *hull, int num, vec_t *p) +{ + float d; + dclipnode_t *node; + mplane_t *plane; + + if (hull->firstclipnode >= hull->lastclipnode) + return -1; + + while (num >= 0) + { + if (num < hull->firstclipnode || num > hull->lastclipnode) + Sys_Error("PM_HullPointContents: bad node number"); + node = &hull->clipnodes[num]; + plane = &hull->planes[hull->clipnodes[num].planenum]; + + double tmpDist; + if (plane->type >= 3) + tmpDist = plane->normal[2] * p[2] + plane->normal[1] * p[1] + plane->normal[0] * *p; + else + tmpDist = p[plane->type]; + d = (float)(tmpDist - plane->dist); + if (d >= 0.0) + num = node->children[0]; + else + num = node->children[1]; + } + + return num; +} + +/* <6f6b2> ../engine/pmovetst.c:171 */ +int PM_LinkContents(vec_t *p, int *pIndex) +{ + physent_t *pe; + vec3_t test; + + for (int i = 1; i < pmove->numphysent; i++) { + pe = &pmove->physents[i]; + model_t* model = pmove->physents[i].model; + if (pmove->physents[i].solid || model == NULL) + continue; + + test[0] = p[0] - pe->origin[0]; + test[1] = p[1] - pe->origin[1]; + test[2] = p[2] - pe->origin[2]; + if (PM_HullPointContents(model->hulls, model->hulls[0].firstclipnode, test) != -1) { + if (pIndex) + *pIndex = pe->info; + return pe->skin; + } + } + + return -1; +} + +/* <6f740> ../engine/pmovetst.c:223 */ +int PM_PointContents(vec_t *p, int *truecontents) +{ +#ifndef SWDS + g_engdstAddrs.PM_PointContents(&p, &truecontents); +#endif + + if ((int)pmove->physents[0].model != -208) + { + int entityContents = PM_HullPointContents( + pmove->physents[0].model->hulls, + pmove->physents[0].model->hulls[0].firstclipnode, + p); + if (truecontents) + *truecontents = entityContents; + if (entityContents > -9 || entityContents < -14) + { + if (entityContents == -2) + return entityContents; + } + else + { + entityContents = -3; + } + int cont = PM_LinkContents(p, 0); + if (cont != -1) + return cont; + return entityContents; + } + if (truecontents) + *truecontents = -1; + return -2; +} + +/* <6f7b0> ../engine/pmovetst.c:265 */ +int PM_WaterEntity(vec_t *p) +{ + int cont; + int entityIndex; + +#ifndef SWDS + g_engdstAddrs.PM_WaterEntity(&p); +#endif + + model_t* model = pmove->physents[0].model; + cont = PM_HullPointContents(model->hulls, model->hulls[0].firstclipnode, p); + if (cont == -2) { + return -1; + } + + entityIndex = 0; + return PM_LinkContents(p, &entityIndex); +} + +/* <6f813> ../engine/pmovetst.c:299 */ +int PM_TruePointContents(vec_t *p) +{ + if ((int)pmove->physents[0].model == -208) + return -1; + else + return PM_HullPointContents(pmove->physents[0].model->hulls, pmove->physents[0].model->hulls[0].firstclipnode, p); +} + +/* <6f84f> ../engine/pmovetst.c:324 */ +hull_t *PM_HullForStudioModel(model_t *pModel, vec_t *offset, float frame, int sequence, const vec_t *angles, const vec_t *origin, const unsigned char *pcontroller, const unsigned char *pblending, int *pNumHulls) +{ + vec3_t size; // 335 + + size[0] = player_maxs[pmove->usehull][0] - player_mins[pmove->usehull][0]; + size[1] = player_maxs[pmove->usehull][1] - player_mins[pmove->usehull][1]; + size[2] = player_maxs[pmove->usehull][2] - player_mins[pmove->usehull][2]; + VectorScale(size, 0.5, size); + offset[0] = 0; + offset[1] = 0; + offset[2] = 0; + return R_StudioHull(pModel, frame, sequence, angles, origin, size, pcontroller, pblending, pNumHulls, 0, 0); +} + +/* <6fb99> ../engine/pmovetst.c:343 */ +hull_t *PM_HullForBsp(physent_t *pe, vec_t *offset) +{ + hull_t *hull; + + switch (pmove->usehull) { + case 1: + hull = &pe->model->hulls[3]; + break; + + case 2: + hull = &pe->model->hulls[0]; + break; + + case 3: + hull = &pe->model->hulls[2]; + break; + + default: + hull = &pe->model->hulls[1]; + break; + } + + offset[0] = hull->clip_mins[0] - player_mins[pmove->usehull][0]; + offset[1] = hull->clip_mins[1] - player_mins[pmove->usehull][1]; + offset[2] = hull->clip_mins[2] - player_mins[pmove->usehull][2]; + offset[0] += pe->origin[0]; + offset[1] += pe->origin[1]; + offset[2] += pe->origin[2]; + return hull; +} + +/* <6fc84> ../engine/pmovetst.c:381 */ +int _PM_TestPlayerPosition(vec_t *pos, pmtrace_t *ptrace, int(*pfnIgnore)(physent_t *)) +{ + hull_t *hull; + pmtrace_t tr; + vec3_t mins; + vec3_t maxs; + vec3_t offset; + int numhulls; + vec3_t test; + + tr = PM_PlayerTrace(pmove->origin, pmove->origin, 0, -1); + if (ptrace) + memcpy(ptrace, &tr, sizeof(tr)); + + for (int i = 0; i < pmove->numphysent; i++) + { + physent_t *pe = &pmove->physents[i]; + if (pfnIgnore && pfnIgnore(pe) || pe->model && !pe->solid && pe->skin) + continue; + + offset[0] = pe->origin[0]; + offset[1] = pe->origin[1]; + offset[2] = pe->origin[2]; + numhulls = 1; + + if (pe->model) + { + hull = PM_HullForBsp(pe, offset); + } + else + { + if (pe->studiomodel && pe->studiomodel->type == mod_studio && ((pe->studiomodel->flags & 0x200) || pmove->usehull == 2)) + { + hull = PM_HullForStudioModel(pe->studiomodel, offset, pe->frame, pe->sequence, pe->angles, pe->origin, pe->controller, pe->blending, &numhulls); + } + else + { + mins[0] = pe->mins[0] - player_maxs[pmove->usehull][0]; + mins[1] = pe->mins[1] - player_maxs[pmove->usehull][1]; + mins[2] = pe->mins[2] - player_maxs[pmove->usehull][2]; + maxs[0] = pe->maxs[0] - player_mins[pmove->usehull][0]; + maxs[1] = pe->maxs[1] - player_mins[pmove->usehull][1]; + maxs[2] = pe->maxs[2] - player_mins[pmove->usehull][2]; + hull = PM_HullForBox(mins, maxs); + } + } + test[0] = pos[0] - offset[0]; + test[1] = pos[1] - offset[1]; + test[2] = pos[2] - offset[2]; + if (pe->solid == 4 && (pe->angles[0] != 0.0 || pe->angles[1] != 0.0 || pe->angles[2] != 0.0)) + { + vec3_t forward, right, up, temp; + + AngleVectors(pe->angles, forward, right, up); + temp[0] = test[0]; temp[1] = test[1]; temp[2] = test[2]; + test[0] = forward[2] * test[2] + forward[1] * test[1] + forward[0] * test[0]; + test[1] = -(right[0] * temp[0] + right[2] * test[2] + right[1] * test[1]); + test[2] = up[1] * temp[1] + up[0] * temp[0] + up[2] * test[2]; + } + if (numhulls != 1) + { + for (int j = 0; j < numhulls; j++) + { + g_contentsresult = PM_HullPointContents(&hull[j], hull[j].firstclipnode, test); + if (g_contentsresult == -2) + return i; + } + } + else + { + g_contentsresult = PM_HullPointContents(hull, hull->firstclipnode, test); + if (g_contentsresult == -2) + return i; + } + } + + return -1; + +} + +/* <6fe2a> ../engine/pmovetst.c:507 */ +int PM_TestPlayerPosition(vec_t *pos, pmtrace_t *ptrace) +{ + return _PM_TestPlayerPosition(pos, ptrace, 0); +} + +/* <6fe67> ../engine/pmovetst.c:518 */ +int PM_TestPlayerPositionEx(vec_t *pos, pmtrace_t *ptrace, int(*pfnIgnore)(physent_t *)) +{ + return _PM_TestPlayerPosition(pos, ptrace, pfnIgnore); +} + +/* <6f065> ../engine/pmovetst.c:534 */ +pmtrace_t _PM_PlayerTrace(vec_t *start, vec_t *end, int traceFlags, int numphysent, physent_t *physents, int ignore_pe, int(*pfnIgnore)(physent_t *)) +{ + hull_t *hull; + pmtrace_t trace; + pmtrace_t testtrace; + pmtrace_t total; + vec3_t maxs; + vec3_t mins; + int closest; + bool rotated; + int pNumHulls; + vec_t end_l[3]; + vec_t start_l[3]; + vec3_t offset; + + Q_memset(&trace, 0, sizeof(trace)); + trace.fraction = 1.0f; + trace.ent = -1; + trace.endpos[0] = end[0]; + trace.endpos[1] = end[1]; + trace.endpos[2] = end[2]; + + for (int i = 0; i < numphysent; i++) + { + physent_t* pe = &physents[i]; + if (i > 0 && (traceFlags & FL_CLIENT)) + break; + + if (pfnIgnore) + { + if (pfnIgnore(pe)) + continue; + } + else + { + if (ignore_pe != -1 && i == ignore_pe) + continue; + } + + if ((pe->model && !pe->solid && pe->skin) || ((traceFlags & FL_CONVEYOR) && pe->rendermode)) + continue; + + + offset[0] = pe->origin[0]; + offset[1] = pe->origin[1]; + offset[2] = pe->origin[2]; + pNumHulls = 1; + if (pe->model) + { + switch (pmove->usehull) + { + case 1: + hull = &pe->model->hulls[3]; + break; + case 2: + hull = &pe->model->hulls[0]; + break; + case 3: + hull = &pe->model->hulls[2]; + break; + default: + hull = &pe->model->hulls[1]; + break; + } + offset[0] = hull->clip_mins[0] - player_mins[pmove->usehull][0]; + offset[1] = hull->clip_mins[1] - player_mins[pmove->usehull][1]; + offset[2] = hull->clip_mins[2] - player_mins[pmove->usehull][2]; + offset[0] = offset[0] + pe->origin[0]; + offset[1] = offset[1] + pe->origin[1]; + offset[2] = offset[2] + pe->origin[2]; + } + else + { + hull = NULL; + if (pe->studiomodel) + { + if (traceFlags & FL_FLY) + continue; + + + if (pe->studiomodel->type == mod_studio && (pe->studiomodel->flags & 0x200 || (pmove->usehull == 2 && !(traceFlags & FL_SWIM)))) + { + hull = PM_HullForStudioModel(pe->studiomodel, offset, pe->frame, pe->sequence, pe->angles, pe->origin, pe->controller, pe->blending, &pNumHulls); + } + } + + if (!hull) + { + mins[0] = pe->mins[0] - player_maxs[pmove->usehull][0]; + mins[1] = pe->mins[1] - player_maxs[pmove->usehull][1]; + mins[2] = pe->mins[2] - player_maxs[pmove->usehull][2]; + maxs[0] = pe->maxs[0] - player_mins[pmove->usehull][0]; + maxs[1] = pe->maxs[1] - player_mins[pmove->usehull][1]; + maxs[2] = pe->maxs[2] - player_mins[pmove->usehull][2]; + hull = PM_HullForBox(mins, maxs); + } + } + + start_l[0] = start[0] - offset[0]; + start_l[1] = start[1] - offset[1]; + start_l[2] = start[2] - offset[2]; + end_l[0] = end[0] - offset[0]; + end_l[1] = end[1] - offset[1]; + end_l[2] = end[2] - offset[2]; + + if (pe->solid == SOLID_BSP && (pe->angles[0] != 0.0 || pe->angles[1] != 0.0 || pe->angles[2] != 0.0)) + { + vec3_t temp, forward, right, up; + rotated = true; + AngleVectors(pe->angles, forward, right, up); + temp[0] = start_l[0]; temp[1] = start_l[1]; temp[2] = start_l[2]; + start_l[0] = forward[2] * start_l[2] + forward[1] * start_l[1] + forward[0] * start_l[0]; + start_l[1] = -(right[0] * temp[0] + right[2] * start_l[2] + right[1] * start_l[1]); + start_l[2] = up[1] * temp[1] + up[0] * temp[0] + up[2] * start_l[2]; + + temp[0] = end_l[0]; temp[1] = end_l[1]; temp[2] = end_l[2]; + end_l[0] = forward[2] * end_l[2] + forward[1] * end_l[1] + forward[0] * end_l[0]; + end_l[1] = -(right[0] * temp[0] + right[2] * end_l[2] + right[1] * end_l[1]); + end_l[2] = up[1] * temp[1] + up[0] * temp[0] + up[2] * end_l[2]; + } + else + { + rotated = false; + } + + Q_memset(&total, 0, sizeof(total)); + total.endpos[0] = end[0]; + total.endpos[1] = end[1]; + total.endpos[2] = end[2]; + total.fraction = 1.0f; + total.allsolid = 1; + if (pNumHulls <= 0) + { + total.allsolid = 0; + } + else + { + if (pNumHulls == 1) + { + PM_RecursiveHullCheck(hull, hull->firstclipnode, 0.0, 1.0, start_l, end_l, &total); + } + else + { + closest = 0; + for (int j = 0; j < pNumHulls; j++) + { + Q_memset(&testtrace, 0, 0x44u); + testtrace.endpos[0] = end[0]; + testtrace.endpos[1] = end[1]; + testtrace.endpos[2] = end[2]; + testtrace.fraction = 1.0f; + testtrace.allsolid = 1; + PM_RecursiveHullCheck(&hull[j], hull[j].firstclipnode, 0.0, 1.0, start_l, end_l, &testtrace); + if (j == 0 || testtrace.allsolid || testtrace.startsolid || testtrace.fraction < total.fraction) + { + bool remember = (total.startsolid == 0); + memcpy(&total, &testtrace, sizeof(total)); + if (!remember) + total.startsolid = 1; + closest = j; + } + total.hitgroup = SV_HitgroupForStudioHull(closest); + } + } + + if (total.allsolid) + total.startsolid = 1; + + } + + if (total.startsolid) + total.fraction = 0; + + if (total.fraction != 1.0) + { + if (rotated) + { + vec3_t temp, forward, right, up; + AngleVectorsTranspose(pe->angles, forward, right, up); + + temp[0] = total.plane.normal[0]; temp[1] = total.plane.normal[1]; temp[2] = total.plane.normal[2]; + total.plane.normal[0] = forward[2] * total.plane.normal[2] + forward[1] * total.plane.normal[1] + forward[0] * total.plane.normal[0]; + total.plane.normal[1] = right[2] * total.plane.normal[2] + right[1] * total.plane.normal[1] + right[0] * temp[0]; + total.plane.normal[2] = up[2] * total.plane.normal[2] + up[1] * temp[1] + up[0] * temp[0]; + } + total.endpos[0] = (end[0] - start[0]) * total.fraction + start[0]; + total.endpos[1] = (end[1] - start[1]) * total.fraction + start[1]; + total.endpos[2] = (end[2] - start[2]) * total.fraction + start[2]; + } + + if (total.fraction < trace.fraction) + { + memcpy(&trace, &total, sizeof(trace)); + trace.ent = i; + } + } + + return trace; +} + +/* <6f237> ../engine/pmovetst.c:787 */ +pmtrace_t PM_PlayerTrace(vec_t *start, vec_t *end, int traceFlags, int ignore_pe) +{ + pmtrace_t tr = _PM_PlayerTrace(start, end, traceFlags, pmove->numphysent, pmove->physents, ignore_pe, 0); + return tr; +} + +/* <6f1e8> ../engine/pmovetst.c:794 */ +pmtrace_t PM_PlayerTraceEx(vec_t *start, vec_t *end, int traceFlags, int(*pfnIgnore)(physent_t *)) +{ + pmtrace_t tr = _PM_PlayerTrace(start, end, traceFlags, pmove->numphysent, pmove->physents, -1, pfnIgnore); + return tr; +} + +struct pmtrace_s *PM_TraceLine(float *start, float *end, int flags, int usehull, int ignore_pe) +{ + int oldhull; + static pmtrace_t tr; + +#ifndef SWDS + g_engdstAddrs.PM_TraceLine(&start, &end, &flags, &usehull, &ignore_pe); +#endif + + oldhull = pmove->usehull; + pmove->usehull = usehull; + if (flags) + { + if (flags == 1) + { + tr = _PM_PlayerTrace(start, end, 0, pmove->numvisent, pmove->visents, ignore_pe, 0); + pmove->usehull = oldhull; + } + else + { + pmove->usehull = oldhull; + } + } + else + { + tr = _PM_PlayerTrace(start, end, 0, pmove->numphysent, pmove->physents, ignore_pe, 0); + pmove->usehull = oldhull; + } + + return &tr; +} + +/* <70238> ../engine/pmovetst.c:824 */ +struct pmtrace_s *PM_TraceLineEx(float *start, float *end, int flags, int usehull, int(*pfnIgnore)(physent_t *)) +{ + int oldhull; // 826 + static pmtrace_t tr; // 827 + + oldhull = pmove->usehull; + pmove->usehull = usehull; + if (flags) + { + tr = _PM_PlayerTrace(start, end, 0, pmove->numvisent, pmove->visents, -1, pfnIgnore); + pmove->usehull = oldhull; + + } + else + { + tr = PM_PlayerTraceEx(start, end, 0, pfnIgnore); + pmove->usehull = oldhull; + } + return &tr; +} + +/* <6ef4a> ../engine/pmovetst.c:844 */ +qboolean PM_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, pmtrace_t *trace) +{ + qboolean retval; + dclipnode_t *node; + mplane_t *plane; + vec3_t mid; + float pdif; + float frac; + float t1; + float t2; + float midf; + + if (num < 0) + { + if (num == -2) + { + trace->startsolid = 1; + retval = 1; + } + else + { + trace->allsolid = 0; + if (num == -1) + { + trace->inopen = 1; + retval = 1; + } + else + { + trace->inwater = 1; + retval = 1; + } + } + return retval; + } + + if (hull->firstclipnode >= hull->lastclipnode) + { + trace->allsolid = 0; + trace->inopen = 1; + return 1; + } + + node = &hull->clipnodes[num]; + plane = &hull->planes[node->planenum]; + if (plane->type >= 3u) + { + t1 = p1[2] * plane->normal[2] + p1[1] * plane->normal[1] + p1[0] * plane->normal[0] - plane->dist; + t2 = p2[2] * plane->normal[2] + p2[1] * plane->normal[1] + p2[0] * plane->normal[0] - plane->dist; + } + else + { + t1 = p1[plane->type] - plane->dist; + t2 = p2[plane->type] - plane->dist; + } + if (t1 >= 0.0 && t2 >= 0.0) + return PM_RecursiveHullCheck(hull, node->children[0], p1f, p2f, p1, p2, trace); + + if (t1 >= 0.0) + { + midf = t1 - 0.03125f; + } + else + { + if (t2 < 0.0) + return PM_RecursiveHullCheck(hull, node->children[1], p1f, p2f, p1, p2, trace); + + midf = t1 + 0.03125f; + } + midf = midf / (t1 - t2); + if (midf >= 0.0) + { + if (midf > 1.0) + midf = 1.0; + } + else + { + midf = 0.0; + } + + pdif = p2f - p1f; + frac = pdif * midf + p1f; + mid[0] = (p2[0] - p1[0]) * midf + p1[0]; + mid[1] = (p2[1] - p1[1]) * midf + p1[1]; + mid[2] = (p2[2] - p1[2]) * midf + p1[2]; + + int side = (t1 >= 0.0) ? 0 : 1; + + if (!PM_RecursiveHullCheck(hull, node->children[side], p1f, frac, p1, mid, trace)) + return 0; + + if (PM_HullPointContents(hull, node->children[side ^ 1], mid) != -2) + return PM_RecursiveHullCheck(hull, node->children[side ^ 1], frac, p2f, mid, p2, trace); + + if (trace->allsolid) + return 0; + + if (side) + { + trace->plane.normal[0] = vec3_origin[0] - plane->normal[0]; + trace->plane.normal[1] = vec3_origin[1] - plane->normal[1]; + trace->plane.normal[2] = vec3_origin[2] - plane->normal[2]; + trace->plane.dist = -plane->dist; + } + else + { + trace->plane.normal[0] = plane->normal[0]; + trace->plane.normal[1] = plane->normal[1]; + trace->plane.normal[2] = plane->normal[2]; + trace->plane.dist = plane->dist; + } + + if (PM_HullPointContents(hull, hull->firstclipnode, mid) != -2) + { + trace->fraction = frac; + trace->endpos[0] = mid[0]; + trace->endpos[1] = mid[1]; + trace->endpos[2] = mid[2]; + return 0; + } + + while (1) + { + midf = (float)(midf - 0.05); + if (midf < 0.0) + break; + + frac = pdif * midf + p1f; + mid[0] = (p2[0] - p1[0]) * midf + p1[0]; + mid[1] = (p2[1] - p1[1]) * midf + p1[1]; + mid[2] = (p2[2] - p1[2]) * midf + p1[2]; + if (PM_HullPointContents(hull, hull->firstclipnode, mid) != -2) + { + trace->fraction = frac; + trace->endpos[0] = mid[0]; + trace->endpos[1] = mid[1]; + trace->endpos[2] = mid[2]; + return 0; + } + } + + trace->fraction = frac; + trace->endpos[0] = mid[0]; + trace->endpos[1] = mid[1]; + trace->endpos[2] = mid[2]; + Con_DPrintf("Trace backed up past 0.0.\n"); + return 0; +} diff --git a/rehlds/engine/pmovetst.h b/rehlds/engine/pmovetst.h new file mode 100644 index 0000000..a41f271 --- /dev/null +++ b/rehlds/engine/pmovetst.h @@ -0,0 +1,77 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef PMOVETST_H +#define PMOVETST_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "pm_defs.h" +#include "model.h" +#include "world.h" + + +#ifdef HOOK_ENGINE +#define g_contentsresult (*pg_contentsresult) +#define box_hull_0 (*pbox_hull_0) +#define box_clipnodes_0 (*pbox_clipnodes_0) +#define box_planes_0 (*pbox_planes_0) +#endif // HOOK_ENGINE + +extern int g_contentsresult; +extern hull_t box_hull_0; +extern box_clipnodes_t box_clipnodes_0; +extern box_planes_t box_planes_0; + + + +float PM_TraceModel(physent_t *pEnt, vec_t *start, vec_t *end, trace_t *trace); +void PM_GetModelBounds(struct model_s *mod, vec_t *mins, vec_t *maxs); +int PM_GetModelType(struct model_s *mod); +void PM_InitBoxHull(void); +hull_t *PM_HullForBox(vec_t *mins, vec_t *maxs); +int PM_HullPointContents(hull_t *hull, int num, vec_t *p); +int PM_LinkContents(vec_t *p, int *pIndex); +int PM_PointContents(vec_t *p, int *truecontents); +int PM_WaterEntity(vec_t *p); +int PM_TruePointContents(vec_t *p); +hull_t *PM_HullForStudioModel(model_t *pModel, vec_t *offset, float frame, int sequence, const vec_t *angles, const vec_t *origin, const unsigned char *pcontroller, const unsigned char *pblending, int *pNumHulls); +hull_t *PM_HullForBsp(physent_t *pe, vec_t *offset); +int _PM_TestPlayerPosition(vec_t *pos, pmtrace_t *ptrace, int(*pfnIgnore)(physent_t *)); +int PM_TestPlayerPosition(vec_t *pos, pmtrace_t *ptrace); +int PM_TestPlayerPositionEx(vec_t *pos, pmtrace_t *ptrace, int(*pfnIgnore)(physent_t *)); +pmtrace_t _PM_PlayerTrace(vec_t *start, vec_t *end, int traceFlags, int numphysent, physent_t *physents, int ignore_pe, int(*pfnIgnore)(physent_t *)); +pmtrace_t PM_PlayerTrace(vec_t *start, vec_t *end, int traceFlags, int ignore_pe); +pmtrace_t PM_PlayerTraceEx(vec_t *start, vec_t *end, int traceFlags, int(*pfnIgnore)(physent_t *)); +struct pmtrace_s *PM_TraceLine(float *start, float *end, int flags, int usehull, int ignore_pe); +struct pmtrace_s *PM_TraceLineEx(float *start, float *end, int flags, int usehull, int(*pfnIgnore)(physent_t *)); +qboolean PM_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, pmtrace_t *trace); + +#endif // PMOVETST_H diff --git a/rehlds/engine/pr_cmds.cpp b/rehlds/engine/pr_cmds.cpp new file mode 100644 index 0000000..d993a3a --- /dev/null +++ b/rehlds/engine/pr_cmds.cpp @@ -0,0 +1,2783 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +vec_t gHullMins[4][3] = { + { 0.0f, 0.0f, 0.0f }, + { -16.0f, -16.0f, -36.0f }, + { -32.0f, -32.0f, -32.0f }, + { -16.0f, -16.0f, -18.0f }, +}; + +vec_t gHullMaxs[4][3] = { + { 0.0f, 0.0f, 0.0f }, + { 16.0f, 16.0f, 36.0f }, + { 32.0f, 32.0f, 32.0f }, + { 16.0f, 16.0f, 18.0f }, +}; + +unsigned char gMsgData[512]; + +edict_t *gMsgEntity; +int gMsgDest; +int gMsgType; +qboolean gMsgStarted; +vec3_t gMsgOrigin; +int32_t idum; +int g_groupop; +int g_groupmask; +unsigned char checkpvs[1024]; +int c_invis; +int c_notvis; + +// TODO: Move to sv_phys.cpp +vec3_t vec_origin; +int r_visframecount; + + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +sizebuf_t gMsgBuffer = { "MessageBegin/End", 0, gMsgData, sizeof(gMsgData), 0 }; + +#else //HOOK_ENGINE + +sizebuf_t gMsgBuffer; + +#endif //HOOK_ENGINE + +/* <782a3> ../engine/pr_cmds.c:53 */ +void PF_makevectors_I(const float *rgflVector) +{ + AngleVectors(rgflVector, gGlobalVariables.v_forward, gGlobalVariables.v_right, gGlobalVariables.v_up); +} + +/* <782cb> ../engine/pr_cmds.c:58 */ +float PF_Time(void) +{ + return Sys_FloatTime(); +} + +/* <782e4> ../engine/pr_cmds.c:74 */ +void PF_setorigin_I(edict_t *e, const float *org) +{ + if (!e) + return; + + e->v.origin[0] = org[0]; + e->v.origin[1] = org[1]; + e->v.origin[2] = org[2]; + SV_LinkEdict(e, FALSE); +} + +/* <78317> ../engine/pr_cmds.c:84 */ +void SetMinMaxSize(edict_t *e, const float *min, const float *max, qboolean rotate) +{ + for (int i = 0; i < 3; i++) + { + if (min[i] > max[i]) + Host_Error("backwards mins/maxs"); + } + + e->v.mins[0] = min[0]; + e->v.mins[1] = min[1]; + e->v.mins[2] = min[2]; + + e->v.maxs[0] = max[0]; + e->v.maxs[1] = max[1]; + e->v.maxs[2] = max[2]; + + e->v.size[0] = max[0] - min[0]; + e->v.size[1] = max[1] - min[1]; + e->v.size[2] = max[2] - min[2]; + SV_LinkEdict(e, 0); +} + +/* <7840f> ../engine/pr_cmds.c:169 */ +void PF_setsize_I(edict_t *e, const float *rgflMin, const float *rgflMax) +{ + SetMinMaxSize(e, rgflMin, rgflMax, 0); +} + +/* <78451> ../engine/pr_cmds.c:184 */ +void PF_setmodel_I(edict_t *e, const char *m) +{ + char** check = &g_psv.model_precache[0]; + int i = 0; + +#ifdef REHLDS_CHECKS + for (; *check && i < 512; i++, check++) +#else + for (; *check; i++, check++) +#endif + { + if (!Q_stricmp(*check, m)) + { + e->v.modelindex = i; + model_t *mod = g_psv.models[i]; + e->v.model = m - pr_strings; + if (mod) + { + SetMinMaxSize(e, mod->mins, mod->maxs, 1); + } + else + { + SetMinMaxSize(e, vec3_origin, vec3_origin, 1); + } + + return; + } + } + + Host_Error("no precache: %s\n", m); +} + +/* <784b4> ../engine/pr_cmds.c:210 */ +int PF_modelindex(const char *pstr) +{ + return SV_ModelIndex(pstr); +} + +/* <784df> ../engine/pr_cmds.c:217 */ +int ModelFrames(int modelIndex) +{ + if (modelIndex <= 0 || modelIndex >= 512) + { + Con_DPrintf("Bad sprite index!\n"); + return 1; + } + + return ModelFrameCount(g_psv.models[modelIndex]); +} + +/* <7851a> ../engine/pr_cmds.c:239 */ +void PF_bprint(char *s) +{ + SV_BroadcastPrintf("%s", s); +} + +/* <78540> ../engine/pr_cmds.c:253 */ +void PF_sprint(char *s, int entnum) +{ + if (entnum <= 0 || entnum > g_psvs.maxclients) + { + Con_Printf("tried to sprint to a non-client\n"); + return; + } + + client_t* client = &g_psvs.clients[entnum - 1]; + if (!client->fakeclient) + { + MSG_WriteChar(&client->netchan.message, svc_print); + MSG_WriteString(&client->netchan.message, s); + } +} + +/* <78589> ../engine/pr_cmds.c:280 */ +void ServerPrint(const char *szMsg) +{ + Con_Printf("%s", szMsg); +} + +/* <785b3> ../engine/pr_cmds.c:293 */ +void ClientPrintf(edict_t *pEdict, PRINT_TYPE ptype, const char *szMsg) +{ + client_t *client; + int entnum; + + entnum = NUM_FOR_EDICT(pEdict); + if (entnum < 1 || entnum > g_psvs.maxclients) + { + Con_Printf("tried to sprint to a non-client\n"); + return; + } + + client = &g_psvs.clients[entnum - 1]; + if (client->fakeclient) + return; + + switch (ptype) + { + case print_center: + MSG_WriteChar(&client->netchan.message, svc_centerprint); + MSG_WriteString(&client->netchan.message, szMsg); + break; + + case print_chat: + case print_console: + MSG_WriteByte(&client->netchan.message, svc_print); + MSG_WriteString(&client->netchan.message, szMsg); + break; + + default: + Con_Printf("invalid PRINT_TYPE %i\n", ptype); + break; + } + +} + +/* <7861b> ../engine/pr_cmds.c:339 */ +float PF_vectoyaw_I(const float *rgflVector) +{ + float yaw = 0.0f; + if (rgflVector[1] == 0.0f && rgflVector[0] == 0.0f) + return 0.0f; + + yaw = (float)(int)floor(atan2((double)rgflVector[1], (double)rgflVector[0]) * 180.0 / M_PI); + if (yaw < 0.0) + yaw = yaw + 360.0; + + return yaw; +} + +/* <78659> ../engine/pr_cmds.c:363 */ +void PF_vectoangles_I(const float *rgflVectorIn, float *rgflVectorOut) +{ + VectorAngles(rgflVectorIn, rgflVectorOut); +} + +/* <78691> ../engine/pr_cmds.c:377 */ +void PF_particle_I(const float *org, const float *dir, float color, float count) +{ + SV_StartParticle(org, dir, color, count); +} + +/* <786e7> ../engine/pr_cmds.c:390 */ +void PF_ambientsound_I(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch) +{ + char **check; + int i; + int soundnum; + int ent; + sizebuf_t *pout; + + if (samp[0] == '!') + { + fFlags |= SND_FL_SENTENCE; + soundnum = Q_atoi(samp + 1); + if (soundnum >= CVOXFILESENTENCEMAX) + { + Con_Printf("invalid sentence number: %s", &samp[1]); + return; + } + } + else + { + i = 0; + check = g_psv.sound_precache; + while (*check && Q_stricmp(*check, samp)) { + i++; + check++; + } + if (!check[0]) + { + Con_Printf("no precache: %s\n", samp); + return; + } + + soundnum = i; + } + + ent = NUM_FOR_EDICT(entity); + pout = &g_psv.signon; + if (!(fFlags & SND_FL_SPAWNING)) + pout = &g_psv.datagram; + + MSG_WriteByte(pout, svc_spawnstaticsound); + MSG_WriteCoord(pout, pos[0]); + MSG_WriteCoord(pout, pos[1]); + MSG_WriteCoord(pout, pos[2]); + + MSG_WriteShort(pout, soundnum); + MSG_WriteByte(pout, (vol * 255.0)); + MSG_WriteByte(pout, (attenuation * 64.0)); + MSG_WriteShort(pout, ent); + MSG_WriteByte(pout, pitch); + MSG_WriteByte(pout, fFlags); +} + +/* <787c0> ../engine/pr_cmds.c:459 */ +void PF_sound_I(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch) +{ + if (volume < 0.0 || volume > 255.0) + Sys_Error("EMIT_SOUND: volume = %i", volume); + if (attenuation < 0.0 || attenuation > 4.0) + Sys_Error("EMIT_SOUND: attenuation = %f", attenuation); + if (channel < 0 || channel > 7) + Sys_Error("EMIT_SOUND: channel = %i", channel); + if (pitch < 0 || pitch > 255) + Sys_Error("EMIT_SOUND: pitch = %i", pitch); + SV_StartSound(0, entity, channel, sample, (int)(volume * 255), attenuation, fFlags, pitch); +} + +/* <78cdd> ../engine/pr_cmds.c:491 */ +void PF_traceline_Shared(const float *v1, const float *v2, int nomonsters, edict_t *ent) +{ + trace_t trace = SV_Move(v1, vec3_origin, vec3_origin, v2, nomonsters, ent, 0); + gGlobalVariables.trace_flags = 0; + SV_SetGlobalTrace(&trace); +} + +/* <78d1c> ../engine/pr_cmds.c:502 */ +void PF_traceline_DLL(const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) +{ + PF_traceline_Shared(v1, v2, fNoMonsters, pentToSkip ? pentToSkip : &g_psv.edicts[0]); + ptr->fAllSolid = (int)gGlobalVariables.trace_allsolid; + ptr->fStartSolid = (int) gGlobalVariables.trace_startsolid; + ptr->fInOpen = (int)gGlobalVariables.trace_inopen; + ptr->fInWater = (int)gGlobalVariables.trace_inwater; + ptr->flFraction = gGlobalVariables.trace_fraction; + ptr->flPlaneDist = gGlobalVariables.trace_plane_dist; + ptr->pHit = gGlobalVariables.trace_ent; + ptr->vecEndPos[0] = gGlobalVariables.trace_endpos[0]; + ptr->vecEndPos[1] = gGlobalVariables.trace_endpos[1]; + ptr->vecEndPos[2] = gGlobalVariables.trace_endpos[2]; + ptr->vecPlaneNormal[0] = gGlobalVariables.trace_plane_normal[0]; + ptr->vecPlaneNormal[1] = gGlobalVariables.trace_plane_normal[1]; + ptr->vecPlaneNormal[2] = gGlobalVariables.trace_plane_normal[2]; + ptr->iHitgroup = gGlobalVariables.trace_hitgroup; +} + +/* <78844> ../engine/pr_cmds.c:531 */ +void TraceHull(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr) +{ + hullNumber = hullNumber; + if (hullNumber < 0 || hullNumber > 3) + hullNumber = 0; + trace_t trace = SV_Move(v1, gHullMins[hullNumber], gHullMaxs[hullNumber], v2, fNoMonsters, pentToSkip, 0); + + ptr->fAllSolid = trace.allsolid; + ptr->fStartSolid = trace.startsolid; + ptr->fInOpen = trace.inopen; + ptr->fInWater = trace.inwater; + ptr->flFraction = trace.fraction; + ptr->flPlaneDist = trace.plane.dist; + ptr->pHit = trace.ent; + ptr->iHitgroup = trace.hitgroup; + ptr->vecEndPos[0] = trace.endpos[0]; + ptr->vecEndPos[1] = trace.endpos[1]; + ptr->vecEndPos[2] = trace.endpos[2]; + ptr->vecPlaneNormal[0] = trace.plane.normal[0]; + ptr->vecPlaneNormal[1] = trace.plane.normal[1]; + ptr->vecPlaneNormal[2] = trace.plane.normal[2]; +} + +/* <788c8> ../engine/pr_cmds.c:556 */ +void TraceSphere(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr) +{ + Sys_Error("TraceSphere not yet implemented!\n"); +} + +/* <7893a> ../engine/pr_cmds.c:578 */ +void TraceModel(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr) +{ + int oldMovetype, oldSolid; + + if (hullNumber < 0 || hullNumber > 3) + hullNumber = 0; + + model_t* pmodel = g_psv.models[pent->v.modelindex]; + if (pmodel && pmodel->type == mod_brush) + { + oldMovetype = pent->v.movetype; + oldSolid = pent->v.solid; + pent->v.solid = SOLID_BSP; + pent->v.movetype = MOVETYPE_PUSH; + } + trace_t trace = SV_ClipMoveToEntity(pent, v1, gHullMins[hullNumber], gHullMaxs[hullNumber], v2); + if (pmodel && pmodel->type == mod_brush) + { + pent->v.solid = oldSolid; + pent->v.movetype = oldMovetype; + } + + ptr->fAllSolid = trace.allsolid; + ptr->fStartSolid = trace.startsolid; + ptr->fInOpen = trace.inopen; + ptr->fInWater = trace.inwater; + ptr->flFraction = trace.fraction; + ptr->flPlaneDist = trace.plane.dist; + ptr->pHit = trace.ent; + ptr->iHitgroup = trace.hitgroup; + ptr->vecEndPos[0] = trace.endpos[0]; + ptr->vecEndPos[1] = trace.endpos[1]; + ptr->vecEndPos[2] = trace.endpos[2]; + ptr->vecPlaneNormal[0] = trace.plane.normal[0]; + ptr->vecPlaneNormal[1] = trace.plane.normal[1]; + ptr->vecPlaneNormal[2] = trace.plane.normal[2]; +} + +/* <789df> ../engine/pr_cmds.c:619 */ +msurface_t *SurfaceAtPoint(model_t *pModel, mnode_t *node, vec_t *start, vec_t *end) +{ + mplane_t *plane; + int s; + int t; + msurface_t *surf; + mtexinfo_t *tex; + int ds; + int dt; + vec3_t mid; + float back; + float front; + float frac; + + if (node->contents < 0) + return 0; + + plane = node->plane; + front = start[2] * plane->normal[2] + plane->normal[0] * start[0] + start[1] * plane->normal[1] - plane->dist; + back = plane->normal[0] * end[0] + plane->normal[2] * end[2] + plane->normal[1] * end[1] - plane->dist; + s = (front < 0.0f) ? 1 : 0; + t = (back < 0.0f) ? 1 : 0; + if (t == s) + return SurfaceAtPoint(pModel, node->children[s], start, end); + + frac = front / (front - back); + mid[0] = (end[0] - start[0]) * frac + start[0]; + mid[1] = (end[1] - start[1]) * frac + start[1]; + mid[2] = (end[2] - start[2]) * frac + start[2]; + surf = SurfaceAtPoint(pModel, node->children[s], start, mid); + if (surf) + return surf; + + if (t == s) + return NULL; + + for (int i = 0; i < node->numsurfaces; i++) + { + surf = &pModel->surfaces[node->firstsurface + i]; + tex = surf->texinfo; + ds = (int)(mid[2] * tex->vecs[0][2] + mid[1] * tex->vecs[0][1] + mid[0] * tex->vecs[0][0] + tex->vecs[0][3]); + dt = (int)(mid[2] * tex->vecs[1][2] + mid[1] * tex->vecs[1][1] + mid[0] * tex->vecs[1][0] + tex->vecs[1][3]); + if (ds >= surf->texturemins[0]) + { + if (dt >= surf->texturemins[1]) + { + if (ds - surf->texturemins[0] <= surf->extents[0] && dt - surf->texturemins[1] <= surf->extents[1]) + return surf; + } + } + } + + return SurfaceAtPoint(pModel, node->children[s ^ 1], mid, end); +} + +/* <78af9> ../engine/pr_cmds.c:688 */ +const char *TraceTexture(edict_t *pTextureEntity, const float *v1, const float *v2) +{ + int firstnode; + model_t *pmodel; + hull_t *phull; + msurface_t *psurf; + vec3_t up; + vec3_t right; + vec3_t forward; + vec3_t offset; + vec3_t temp; + vec3_t start; + vec3_t end; + + firstnode = 0; + if (pTextureEntity) + { + pmodel = g_psv.models[pTextureEntity->v.modelindex]; + if (!pmodel || pmodel->type) + return NULL; + + phull = SV_HullForBsp(pTextureEntity, vec3_origin, vec3_origin, offset); + start[0] = v1[0] - offset[0]; + start[1] = v1[1] - offset[1]; + start[2] = v1[2] - offset[2]; + end[0] = v2[0] - offset[0]; + end[1] = v2[1] - offset[1]; + end[2] = v2[2] - offset[2]; + + firstnode = phull->firstclipnode; + if (pTextureEntity->v.angles[0] != 0.0 || pTextureEntity->v.angles[1] != 0.0 || pTextureEntity->v.angles[2] != 0.0) + { + AngleVectors(pTextureEntity->v.angles, forward, right, up); + + temp[0] = start[0]; temp[1] = start[1]; temp[2] = start[2]; + start[0] = forward[2] * start[2] + forward[1] * start[1] + forward[0] * start[0]; + start[1] = -(right[0] * temp[0] + right[2] * start[2] + right[1] * start[1]); + start[2] = up[1] * temp[1] + up[0] * temp[0] + up[2] * start[2]; + + temp[0] = end[0]; temp[1] = end[1]; temp[2] = end[2]; + end[0] = forward[2] * end[2] + forward[1] * end[1] + forward[0] * end[0]; + end[1] = -(right[0] * temp[0] + right[2] * end[2] + right[1] * end[1]); + end[2] = up[1] * temp[1] + up[0] * temp[0] + up[2] * end[2]; + } + } + else + { + pmodel = g_psv.worldmodel; + start[0] = v1[0]; + start[1] = v1[1]; + start[2] = v1[2]; + end[0] = v2[0]; + end[1] = v2[1]; + end[2] = v2[2]; + } + + if (!pmodel || pmodel->type != mod_brush || !pmodel->nodes) + return NULL; + + psurf = SurfaceAtPoint(pmodel, &pmodel->nodes[firstnode], start, end); + if (psurf) + return psurf->texinfo->texture->name; + + return NULL; +} + +/* <78c30> ../engine/pr_cmds.c:749 */ +void PF_TraceToss_Shared(edict_t *ent, edict_t *ignore) +{ + trace_t trace = SV_Trace_Toss(ent, ignore); + SV_SetGlobalTrace(&trace); +} + +/* <78c06> ../engine/pr_cmds.c:758 */ +void SV_SetGlobalTrace(trace_t *ptrace) +{ + gGlobalVariables.trace_fraction = ptrace->fraction; + gGlobalVariables.trace_allsolid = (float)ptrace->allsolid; + gGlobalVariables.trace_startsolid = (float)ptrace->startsolid; + gGlobalVariables.trace_endpos[0] = ptrace->endpos[0]; + gGlobalVariables.trace_endpos[1] = ptrace->endpos[1]; + gGlobalVariables.trace_endpos[2] = ptrace->endpos[2]; + gGlobalVariables.trace_plane_normal[0] = ptrace->plane.normal[0]; + gGlobalVariables.trace_plane_normal[2] = ptrace->plane.normal[2]; + gGlobalVariables.trace_plane_normal[1] = ptrace->plane.normal[1]; + gGlobalVariables.trace_inwater = (float)ptrace->inwater; + gGlobalVariables.trace_inopen = (float)ptrace->inopen; + gGlobalVariables.trace_plane_dist = ptrace->plane.dist; + if (ptrace->ent) + { + gGlobalVariables.trace_ent = ptrace->ent; + gGlobalVariables.trace_hitgroup = ptrace->hitgroup; + } + else + { + gGlobalVariables.trace_hitgroup = ptrace->hitgroup; + gGlobalVariables.trace_ent = &g_psv.edicts[0]; + } +} + +/* <78dc1> ../engine/pr_cmds.c:775 */ +void PF_TraceToss_DLL(edict_t *pent, edict_t *pentToIgnore, TraceResult *ptr) +{ + PF_TraceToss_Shared(pent, pentToIgnore ? pentToIgnore : &g_psv.edicts[0]); + + ptr->fAllSolid = (int) gGlobalVariables.trace_allsolid; + ptr->fStartSolid = (int)gGlobalVariables.trace_startsolid; + ptr->fInOpen = (int)gGlobalVariables.trace_inopen; + ptr->fInWater = (int)gGlobalVariables.trace_inwater; + ptr->flFraction = gGlobalVariables.trace_fraction; + ptr->flPlaneDist = gGlobalVariables.trace_plane_dist; + ptr->pHit = gGlobalVariables.trace_ent; + ptr->vecEndPos[0] = gGlobalVariables.trace_endpos[0]; + ptr->vecEndPos[1] = gGlobalVariables.trace_endpos[1]; + ptr->vecEndPos[2] = gGlobalVariables.trace_endpos[2]; + ptr->vecPlaneNormal[0] = gGlobalVariables.trace_plane_normal[0]; + ptr->vecPlaneNormal[1] = gGlobalVariables.trace_plane_normal[1]; + ptr->vecPlaneNormal[2] = gGlobalVariables.trace_plane_normal[2]; + ptr->iHitgroup = gGlobalVariables.trace_hitgroup; +} + +/* <78e3a> ../engine/pr_cmds.c:791 */ +int TraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr) +{ + qboolean monsterClip = (pEdict->v.flags & FL_MONSTERCLIP) ? 1 : 0; + trace_t trace = SV_Move(v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip, monsterClip); + if (ptr) + { + ptr->fAllSolid = trace.allsolid; + ptr->fStartSolid = trace.startsolid; + ptr->fInOpen = trace.inopen; + ptr->fInWater = trace.inwater; + ptr->flPlaneDist = trace.plane.dist; + ptr->pHit = trace.ent; + ptr->iHitgroup = trace.hitgroup; + ptr->vecEndPos[0] = trace.endpos[0]; + ptr->vecEndPos[1] = trace.endpos[1]; + ptr->vecEndPos[2] = trace.endpos[2]; + ptr->vecPlaneNormal[0] = trace.plane.normal[0]; + ptr->vecPlaneNormal[1] = trace.plane.normal[1]; + ptr->flFraction = trace.fraction; + ptr->vecPlaneNormal[2] = trace.plane.normal[2]; + } + + return trace.allsolid || trace.fraction != 1.0f; +} + +/* <78ed1> ../engine/pr_cmds.c:830 */ +int PF_newcheckclient(int check) +{ + int i; + unsigned char *pvs; + edict_t *ent; + mleaf_t *leaf; + vec3_t org; + + if (check < 1) + check = 1; + if (check > g_psvs.maxclients) + check = g_psvs.maxclients; + i = 1; + if (check != g_psvs.maxclients) + i = check + 1; + while (1) + { + if (i == g_psvs.maxclients + 1) + i = 1; + + ent = &g_psv.edicts[i]; + if (i == check) + break; + if (!ent->free && ent->pvPrivateData && !(ent->v.flags & FL_NOTARGET)) + break; + ++i; + } + org[0] = ent->v.view_ofs[0] + ent->v.origin[0]; + org[1] = ent->v.view_ofs[1] + ent->v.origin[1]; + org[2] = ent->v.view_ofs[2] + ent->v.origin[2]; + leaf = Mod_PointInLeaf(org, g_psv.worldmodel); + pvs = Mod_LeafPVS(leaf, g_psv.worldmodel); + Q_memcpy(checkpvs, pvs, (g_psv.worldmodel->numleafs + 7) >> 3); + return i; +} + +/* <78f53> ../engine/pr_cmds.c:898 */ +edict_t *PF_checkclient_I(edict_t *pEdict) +{ + edict_t *ent; + mleaf_t *leaf; + int l; + vec3_t view; + + if (g_psv.time - g_psv.lastchecktime >= 0.1) + { + g_psv.lastcheck = PF_newcheckclient(g_psv.lastcheck); + g_psv.lastchecktime = g_psv.time; + } + + ent = &g_psv.edicts[g_psv.lastcheck]; + if (!ent->free && ent->pvPrivateData) + { + view[0] = pEdict->v.view_ofs[0] + pEdict->v.origin[0]; + view[1] = pEdict->v.view_ofs[1] + pEdict->v.origin[1]; + view[2] = pEdict->v.view_ofs[2] + pEdict->v.origin[2]; + leaf = Mod_PointInLeaf(view, g_psv.worldmodel); + l = (leaf - g_psv.worldmodel->leafs) - 1; + if (l >= 0 && ((1 << (l & 7)) & checkpvs[l >> 3])) + { + ++c_invis; + return ent; + } + else + { + ++c_notvis; + return &g_psv.edicts[0]; + } + } + return &g_psv.edicts[0]; +} + +/* <78fbe> ../engine/pr_cmds.c:942 */ +mnode_t *PVSNode(mnode_t *node, vec_t *emins, vec_t *emaxs) +{ + mplane_t *splitplane; + int sides; + mnode_t *splitNode; + + if (node->visframe != r_visframecount) + return NULL; + + if (node->contents < 0) + return node->contents != CONTENT_SOLID ? node : NULL; + + + splitplane = node->plane; + if (splitplane->type >= 3u) + { + sides = BoxOnPlaneSide(emins, emaxs, splitplane); + } + else + { + if (splitplane->dist > emins[splitplane->type]) + { + if (splitplane->dist < emaxs[splitplane->type]) + sides = 3; + else + sides = 2; + } + else + { + sides = 1; + } + } + + if (sides & 1) + { + splitNode = PVSNode(node->children[0], emins, emaxs); + if (splitNode) + return splitNode; + } + + if (sides & 2) + return PVSNode(node->children[1], emins, emaxs); + + return NULL; +} + +/* <7903a> ../engine/pr_cmds.c:976 */ +void PVSMark(model_t *pmodel, unsigned char *ppvs) +{ + ++r_visframecount; + for (int i = 0; i < pmodel->numleafs; i++) + { + if ((1 << (i & 7)) & ppvs[i >> 3]) + { + mnode_t *node = (mnode_t *) &pmodel->leafs[i + 1]; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +} + +/* <790b0> ../engine/pr_cmds.c:1009 */ +edict_t *PVSFindEntities(edict_t *pplayer) +{ + edict_t *pent; + edict_t *pchain; + edict_t *pentPVS; + vec3_t org; + unsigned char *ppvs; + mleaf_t *pleaf; + + org[0] = pplayer->v.view_ofs[0] + pplayer->v.origin[0]; + org[1] = pplayer->v.view_ofs[1] + pplayer->v.origin[1]; + org[2] = pplayer->v.view_ofs[2] + pplayer->v.origin[2]; + pleaf = Mod_PointInLeaf(org, g_psv.worldmodel); + ppvs = Mod_LeafPVS(pleaf, g_psv.worldmodel); + PVSMark(g_psv.worldmodel, ppvs); + pchain = g_psv.edicts; + + for (int i = 1; i < g_psv.num_edicts; i++) + { + pent = &g_psv.edicts[i]; + if (pent->free) + continue; + + pentPVS = pent; + if (pent->v.movetype == MOVETYPE_FOLLOW && pent->v.aiment) + pentPVS = pent->v.aiment; + + if (PVSNode(g_psv.worldmodel->nodes, pentPVS->v.absmin, pentPVS->v.absmax)) + { + pent->v.chain = pchain; + pchain = pent; + } + + } + + if (g_pcl.worldmodel) + { + //r_oldviewleaf = NULL; //clientside only + R_MarkLeaves(); + } + return pchain; +} + +/* <79182> ../engine/pr_cmds.c:1055 */ +qboolean ValidCmd(const char *pCmd) +{ + int len = Q_strlen(pCmd); + return len && (pCmd[len - 1] == '\n' || pCmd[len - 1] == ';'); +} + +/* <791d5> ../engine/pr_cmds.c:1079 */ +void PF_stuffcmd_I(edict_t *pEdict, char *szFmt, ...) +{ + int entnum; + client_t *old; + va_list argptr; + static char szOut[1024]; + + va_start(argptr, szFmt); + entnum = NUM_FOR_EDICT(pEdict); + Q_vsnprintf(szOut, sizeof(szOut), szFmt, argptr); + va_end(argptr); + + szOut[1023] = 0; + if (entnum < 1 || entnum > g_psvs.maxclients) + { + Con_Printf( + "\n!!!\n\nStuffCmd: Some entity tried to stuff '%s' to console buffer of entity %i when maxclients was set to %i, ignoring\n\n", + szOut, + entnum, + g_psvs.maxclients); + } + else + { + if (ValidCmd(szOut)) + { + old = host_client; + host_client = &g_psvs.clients[entnum - 1]; + Host_ClientCommands("%s", szOut); + host_client = old; + } + else + { + Con_Printf("Tried to stuff bad command %s\n", szOut); + } + } +} + +/* <79292> ../engine/pr_cmds.c:1119 */ +void PF_localcmd_I(char *str) +{ + if (ValidCmd(str)) + Cbuf_AddText(str); + else + Con_Printf("Error, bad server command %s\n", str); +} + +/* <792e8> ../engine/pr_cmds.c:1137 */ +void PF_localexec_I(void) +{ + Cbuf_Execute(); +} + +/* <792fd> ../engine/pr_cmds.c:1154 */ +edict_t *FindEntityInSphere(edict_t *pEdictStartSearchAfter, const float *org, float rad) +{ + int e = pEdictStartSearchAfter ? NUM_FOR_EDICT(pEdictStartSearchAfter) : 0; + + for (int i = e + 1; i < g_psv.num_edicts; i++) + { + edict_t* ent = &g_psv.edicts[i]; + if (ent->free || !ent->v.classname) + continue; + + if (i <= g_psvs.maxclients && !g_psvs.clients[i - 1].active) + continue; + + + float distSquared = 0.0; + for (int j = 0; j < 3 && distSquared <= (rad * rad); j++) + { + float eorg; + if (org[j] >= ent->v.absmin[j]) + eorg = (org[j] <= ent->v.absmax[j]) ? 0.0f : org[j] - ent->v.absmax[j]; + else + eorg = org[j] - ent->v.absmin[j]; + distSquared = eorg * eorg + distSquared; + } + + if (distSquared <= ((rad * rad))) + return ent; + } + + return &g_psv.edicts[0]; +} + +/* <793a2> ../engine/pr_cmds.c:1219 */ +edict_t *PF_Spawn_I(void) +{ + return ED_Alloc(); +} + +/* <793cc> ../engine/pr_cmds.c:1226 */ +edict_t *CreateNamedEntity(int className) +{ + edict_t *pedict; + ENTITYINIT pEntityInit; + + if (!className) + Sys_Error("Spawned a NULL entity!"); + + pedict = ED_Alloc(); + pedict->v.classname = className; + pEntityInit = GetEntityInit(&pr_strings[className]); + if (pEntityInit) + { + pEntityInit(&pedict->v); + return pedict; + } + else + { + ED_Free(pedict); + Con_DPrintf("Can't create entity: %s\n", &pr_strings[className]); + return NULL; + } +} + +/* <7941a> ../engine/pr_cmds.c:1253 */ +void PF_Remove_I(edict_t *ed) +{ + ED_Free(ed); +} + +/* <7820f> ../engine/pr_cmds.c:1263 */ +edict_t *PF_find_Shared(int eStartSearchAfter, int iFieldToMatch, const char *szValueToFind) +{ + for (int e = eStartSearchAfter + 1; e < g_psv.num_edicts; e++) + { + edict_t* ed = &g_psv.edicts[e]; + if (ed->free) + continue; + + char* t = &pr_strings[*(string_t*)((size_t)&ed->v + iFieldToMatch)]; + if (t == 0 || t == &pr_strings[0]) + continue; + + if (!Q_strcmp(t, szValueToFind)) + return ed; + + } + return &g_psv.edicts[0]; + +} + +/* <79442> ../engine/pr_cmds.c:1290 */ + +int iGetIndex(const char *pszField) +{ + char sz[512]; + + Q_strncpy(sz, pszField, sizeof(sz) - 1); + sz[sizeof(sz) - 1] = 0; + Q_strlwr(sz); + + #define IGETINDEX_CHECK_FIELD(f) if (!Q_strcmp(sz, #f)) return offsetof(entvars_t, f); + + IGETINDEX_CHECK_FIELD(classname); + IGETINDEX_CHECK_FIELD(model); + IGETINDEX_CHECK_FIELD(viewmodel); + IGETINDEX_CHECK_FIELD(weaponmodel); + IGETINDEX_CHECK_FIELD(netname); + IGETINDEX_CHECK_FIELD(target); + IGETINDEX_CHECK_FIELD(targetname); + IGETINDEX_CHECK_FIELD(message); + IGETINDEX_CHECK_FIELD(noise); + IGETINDEX_CHECK_FIELD(noise1); + IGETINDEX_CHECK_FIELD(noise2); + IGETINDEX_CHECK_FIELD(noise3); + IGETINDEX_CHECK_FIELD(globalname); + + return -1; + +} + +/* <7949b> ../engine/pr_cmds.c:1332 */ +edict_t *FindEntityByString(edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue) +{ + if (!pszValue) + return NULL; + + int iField = iGetIndex(pszField); + if (iField == -1) + return NULL; + + return PF_find_Shared(pEdictStartSearchAfter ? NUM_FOR_EDICT(pEdictStartSearchAfter) : 0, iField, pszValue); +} + +/* <79540> ../engine/pr_cmds.c:1348 */ +int GetEntityIllum(edict_t *pEnt) +{ + if (!pEnt) + return -1; + + if (NUM_FOR_EDICT(pEnt) <= g_psvs.maxclients) + { + return pEnt->v.light_level; + } + else + { + if (g_pcls.state == ca_connected || g_pcls.state == ca_uninitialized || g_pcls.state == ca_active) + return 0x80; + else + return 0; + } +} + +/* <78265> ../engine/pr_cmds.c:1383 */ +qboolean PR_IsEmptyString(const char *s) +{ + return s[0] < ' '; +} + +/* <795b5> ../engine/pr_cmds.c:1397 */ +int PF_precache_sound_I(char *s) +{ + int i; + + if (!s) + Host_Error("PF_precache_sound_I: NULL pointer"); + + if (PR_IsEmptyString(s)) + Host_Error("PF_precache_sound_I: Bad string '%s'", s); + + if (s[0] == '!') + Host_Error("PF_precache_sound_I: '%s' do not precache sentence names!", s); + + if (g_psv.state == ss_loading) + { + g_psv.sound_precache_hashedlookup_built = 0; + i = 0; + while (1) + { + if (!g_psv.sound_precache[i]) + break; + + if (!Q_stricmp(g_psv.sound_precache[i], s)) + return i; + + ++i; + if (i >= 512) + Host_Error( + "PF_precache_sound_I: Sound '%s' failed to precache because the item count is over the %d limit.\nReduce the number of brush models and/or regular models in the map to correct this.", + s, + 512); + } + g_psv.sound_precache[i] = s; + } + else + { + i = 0; + while (1) + { + if (g_psv.sound_precache[i]) + { + if (!Q_stricmp(g_psv.sound_precache[i], s)) + break; + } + ++i; + if (i >= 512) + Host_Error("PF_precache_sound_I: '%s' Precache can only be done in spawn functions", s); + } + } + + return i; +} + +/* <79609> ../engine/pr_cmds.c:1455 */ +short unsigned int EV_Precache(int type, const char *psz) +{ + if (!psz) + Host_Error("EV_Precache: NULL pointer"); + + if (PR_IsEmptyString(psz)) + Host_Error("EV_Precache: Bad string '%s'", psz); + + if (g_psv.state == ss_loading) + { + for (int i = 1; i < 256; i++) + { + struct event_s* ev = &g_psv.event_precache[i]; + if (!ev->filename) + { + if (type != 1) + Host_Error("EV_Precache: only file type 1 supported currently\n"); + + char szpath[260]; + _snprintf(szpath, 0x104u, "%s", psz); + COM_FixSlashes(szpath); + + int scriptSize = 0; + char* evScript = (char*) COM_LoadFile(szpath, 5, &scriptSize); + if (!evScript) + Host_Error("EV_Precache: file %s missing from server\n", psz); + + g_psv.event_precache[i].filename = psz; + g_psv.event_precache[i].filesize = scriptSize; + g_psv.event_precache[i].pszScript = evScript; + g_psv.event_precache[i].index = i; + + return i; + } + + if (!Q_stricmp(ev->filename, psz)) + return i; + } + Host_Error("EV_Precache: '%s' overflow", psz); + } + else + { + for (int i = 1; i < 256; i++) + { + struct event_s* ev = &g_psv.event_precache[i]; + if (!Q_stricmp(ev->filename, psz)) + return i; + } + + Host_Error("EV_Precache: '%s' Precache can only be done in spawn functions", psz); + } +} + +/* <796ae> ../engine/pr_cmds.c:1531 */ +void EV_PlayReliableEvent(client_t *cl, int entindex, short unsigned int eventindex, float delay, event_args_t *pargs) +{ +// unsigned char data; // 1533 +// sizebuf_t msg; // 1534 +// event_args_t eargs; // 1536 +// event_args_t nullargs; // 1537 + + unsigned char data[1024]; // [sp+4h] [bp-4A4h]@2 + event_args_t from; // [sp+404h] [bp-A4h]@2 + event_args_t to; // [sp+44Ch] [bp-5Ch]@2 + sizebuf_t msg; // [sp+494h] [bp-14h]@2 + + if (cl->fakeclient) + return; + + Q_memset(&msg, 0, sizeof(msg)); + msg.buffername = "Reliable Event"; + msg.data = data; + msg.cursize = 0; + msg.maxsize = sizeof(data); + + Q_memset(&from, 0, sizeof(from)); + to = *pargs; + to.entindex = entindex; + + MSG_WriteByte(&msg, svc_event_reliable); + MSG_StartBitWriting(&msg); + MSG_WriteBits(eventindex, 10); + DELTA_WriteDelta((unsigned char *)&from, (unsigned char *)&to, 1, g_peventdelta, 0); + if (delay == 0.0) + { + MSG_WriteBits(0, 1); + } + else + { + MSG_WriteBits(1, 1); + MSG_WriteBits((int)(delay * 100.0f), 16); + } + MSG_EndBitWriting(&msg); + + if (msg.cursize + cl->netchan.message.cursize <= cl->netchan.message.maxsize) + SZ_Write(&cl->netchan.message, msg.data, msg.cursize); + else + Netchan_CreateFragments(1, &cl->netchan, &msg); + +} + +/* <79769> ../engine/pr_cmds.c:1595 */ +void EV_Playback(int flags, const edict_t *pInvoker, short unsigned int eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2) +{ + client_t *cl; + signed int j; + event_args_t eargs; + vec3_t event_origin; + int invoker; + int slot; + int leafnum; + + if (flags & FEV_CLIENT) + return; + + invoker = -1; + Q_memset(&eargs, 0, sizeof(eargs)); + if (!VectorCompare(origin, vec3_origin)) + { + eargs.origin[2] = origin[2]; + eargs.origin[0] = origin[0]; + eargs.origin[1] = origin[1]; + eargs.flags |= FEVENT_ORIGIN; + } + if (!VectorCompare(angles, vec3_origin)) + { + eargs.angles[2] = angles[2]; + eargs.angles[0] = angles[0]; + eargs.angles[1] = angles[1]; + eargs.flags |= FEVENT_ANGLES; + } + eargs.fparam1 = fparam1; + eargs.fparam2 = fparam2; + eargs.iparam1 = iparam1; + eargs.iparam2 = iparam2; + eargs.bparam1 = bparam1; + eargs.bparam2 = bparam2; + + if (eventindex < 1u || eventindex >= 0x100u) + { + Con_DPrintf("EV_Playback: index out of range %i\n", eventindex); + return; + } + + if (!g_psv.event_precache[eventindex].pszScript) + { + Con_DPrintf("EV_Playback: no event for index %i\n", eventindex); + return; + } + + if (pInvoker) + { + event_origin[0] = pInvoker->v.origin[0]; + event_origin[1] = pInvoker->v.origin[1]; + event_origin[2] = pInvoker->v.origin[2]; + invoker = NUM_FOR_EDICT(pInvoker); + if (invoker >= 1) + { + if (invoker <= g_psvs.maxclients) + { + if (pInvoker->v.flags & FL_DUCKING) + eargs.ducking = 1; + } + } + if (!(eargs.flags & FEVENT_ORIGIN)) + { + eargs.origin[0] = pInvoker->v.origin[0]; + eargs.origin[1] = pInvoker->v.origin[1]; + eargs.origin[2] = pInvoker->v.origin[2]; + } + if (!(eargs.flags & FEVENT_ANGLES)) + { + eargs.angles[0] = pInvoker->v.angles[0]; + eargs.angles[1] = pInvoker->v.angles[1]; + eargs.angles[2] = pInvoker->v.angles[2]; + } + } + else + { + event_origin[0] = eargs.origin[0]; + event_origin[1] = eargs.origin[1]; + event_origin[2] = eargs.origin[2]; + } + + leafnum = SV_PointLeafnum(event_origin); + + for (slot = 0; slot < g_psvs.maxclients; slot++) + { + cl = &g_psvs.clients[slot]; + if (!cl->active || !cl->spawned || !cl->connected || !cl->fully_connected || cl->fakeclient) + continue; + + if (pInvoker) + { + if (pInvoker->v.groupinfo) + { + if (cl->edict->v.groupinfo) + { + if (g_groupop) + { + if (g_groupop == GROUP_OP_NAND && (cl->edict->v.groupinfo & pInvoker->v.groupinfo)) + continue; + } + else + { + if (!(cl->edict->v.groupinfo & pInvoker->v.groupinfo)) + continue; + } + } + } + } + + if (pInvoker && !(flags & FEV_GLOBAL)) + { + if (!SV_ValidClientMulticast(cl, leafnum, 4)) + continue; + } + + if (cl == host_client && (flags & FEV_NOTHOST) && cl->lw || (flags & FEV_HOSTONLY) && cl->edict != pInvoker) + continue; + + if (flags & FEV_RELIABLE) + { + EV_PlayReliableEvent(cl, pInvoker ? NUM_FOR_EDICT(pInvoker) : 0, eventindex, delay, &eargs); + continue; + } + + if (flags & FEV_UPDATE) + { + for (j = 0; j < MAX_EVENT_QUEUE; j++) + { + event_info_s *ei = &cl->events.ei[j]; + if (ei->index == eventindex && invoker != -1 && ei->entity_index == invoker) + break; + } + + if (j < MAX_EVENT_QUEUE) + { + event_info_s *ei = &cl->events.ei[j]; + ei->entity_index = -1; + ei->index = eventindex; + ei->packet_index = -1; + if (pInvoker) + ei->entity_index = invoker; + memcpy(&ei->args, &eargs, sizeof(ei->args)); + ei->fire_time = delay; + continue; + } + } + + for (j = 0; j < MAX_EVENT_QUEUE; j++) + { + event_info_s *ei = &cl->events.ei[j]; + if (ei->index == 0) + break; + } + + if (j < MAX_EVENT_QUEUE) + { + event_info_s *ei = &cl->events.ei[j]; + ei->entity_index = -1; + ei->index = eventindex; + ei->packet_index = -1; + if (pInvoker) + ei->entity_index = invoker; + memcpy(&ei->args, &eargs, sizeof(ei->args)); + ei->fire_time = delay; + } + + } +} + +/* <798fb> ../engine/pr_cmds.c:1826 */ +void EV_SV_Playback(int flags, int clientindex, short unsigned int eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2) +{ + if (flags & FEV_CLIENT) + return; + + if (clientindex < 0 || clientindex >= g_psvs.maxclients) + Host_Error("EV_SV_Playback: Client index %i out of range\n", clientindex); + + edict_t *pEdict = g_psvs.clients[clientindex].edict; + EV_Playback(flags,pEdict, eventindex, delay, origin, angles, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2); +} + +/* <799da> ../engine/pr_cmds.c:1849 */ +int PF_precache_model_I(char *s) +{ + int iOptional = 0; + if (!s) + Host_Error("PF_precache_model_I: NULL pointer"); + + if (PR_IsEmptyString(s)) + Host_Error("PF_precache_model_I: Bad string '%s'", s); + + if (*s == '!') + { + s++; + iOptional = 1; + } + + if (g_psv.state == ss_loading) + { + for (int i = 0; i < 512; i++) + { + if (!g_psv.model_precache[i]) + { + g_psv.model_precache[i] = s; + g_psv.models[i] = Mod_ForName(s, 1, 1); + if (!iOptional) + g_psv.model_precache_flags[i] |= 1u; + return i; + } + + if (!Q_stricmp(g_psv.model_precache[i], s)) + return i; + } + Host_Error( + "PF_precache_model_I: Model '%s' failed to precache because the item count is over the %d limit.\nReduce the number of brush models and/or regular models in the map to correct this.", + s, + 512); + } + else + { + for (int i = 0; i < 512; i++) + { + if (!Q_stricmp(g_psv.model_precache[i], s)) + return i; + } + Host_Error("PF_precache_model_I: '%s' Precache can only be done in spawn functions", s); + } +} + +/* <79a3f> ../engine/pr_cmds.c:1903 */ +int PF_precache_generic_I(char *s) +// TODO: Call to Con_Printf is replaced with Host_Error in 6153 +{ + if (!s) + Host_Error("PF_precache_generic_I: NULL pointer"); + + if (PR_IsEmptyString(s)) + Host_Error("PF_precache_generic_I: Bad string '%s'", s); + + if (g_psv.state == ss_loading) + { + for (int i = 0; i < 512; i++) + { + if (!g_psv.generic_precache[i]) + { + g_psv.generic_precache[i] = s; + return i; + } + + if (!Q_stricmp(g_psv.generic_precache[i], s)) + return i; + } + Host_Error( + "PF_precache_generic_I: Generic item '%s' failed to precache because the item count is over the %d limit.\nReduce the number of brush models and/or regular models in the map to correct this.", + s, + 512); + } + else + { + for (int i = 0; i < 512; i++) + { + if (!Q_stricmp(g_psv.generic_precache[i], s)) + return i; + } + Host_Error("PF_precache_generic_I: '%s' Precache can only be done in spawn functions", s); + } + +} + +/* <79a93> ../engine/pr_cmds.c:1944 */ +int PF_IsMapValid_I(char *mapname) +{ + char cBuf[260]; + if (!mapname || strlen(mapname) == 0) + return 0; + + + _snprintf(cBuf, sizeof(cBuf), "maps/%.32s.bsp", mapname); + return FS_FileExists(cBuf); +} + +/* <79ad1> ../engine/pr_cmds.c:1955 */ +int PF_NumberOfEntities_I(void) +{ + int ent_count = 0; + for (int i = 1; i < g_psv.num_edicts; i++) + { + if (!g_psv.edicts[i].free) + ++ent_count; + } + + return ent_count; +} + +/* <79b0e> ../engine/pr_cmds.c:1977 */ +char *PF_GetInfoKeyBuffer_I(edict_t *e) +{ + int e1; + char *value; + + if (e) + { + e1 = NUM_FOR_EDICT(e); + if (e1) + { +#ifdef REHLDS_FIXES + if (e1 <= 0 || e1 > g_psvs.maxclients) // FIXED: Check against correct amount of clients +#else // REHLDS_FIXES + if (e1 > 32) +#endif // REHLDS_FIXES + value = (char *)""; + else + value = (char *)&g_psvs.clients[e1 - 1].userinfo; + } + else + { + value = Info_Serverinfo(); + } + } + else + { + value = localinfo; + } + + return value; +} + +/* <79b55> ../engine/pr_cmds.c:2012 */ +char *PF_InfoKeyValue_I(char *infobuffer, char *key) +{ + return (char *)Info_ValueForKey(infobuffer, key); +} + +/* <79b91> ../engine/pr_cmds.c:2022 */ +void PF_SetKeyValue_I(char *infobuffer, char *key, char *value) +{ + if (infobuffer == localinfo) + { + Info_SetValueForKey(infobuffer, key, value, MAX_INFO_STRING * 128); + } + else + { + if (infobuffer != Info_Serverinfo()) + { + Sys_Error("Can't set client keys with SetKeyValue"); + } +#ifdef REHLDS_FIXES + Info_SetValueForKey(infobuffer, key, value, MAX_INFO_STRING); // Use correct length +#else // REHLDS_FIXES + Info_SetValueForKey(infobuffer, key, value, 512); +#endif // REHLDS_FIXES + } +} + +/* <79bd9> ../engine/pr_cmds.c:2037 */ +void PF_RemoveKey_I(char *s, const char *key) +{ + Info_RemoveKey(s, key); +} + +/* <79c0f> ../engine/pr_cmds.c:2047 */ +void PF_SetClientKeyValue_I(int clientIndex, char *infobuffer, char *key, char *value) +{ + client_t *pClient; + + if (infobuffer == localinfo || + infobuffer == Info_Serverinfo() || + clientIndex <= 0 || + clientIndex > g_psvs.maxclients) + { + return; + } + + if (Q_strcmp(Info_ValueForKey(infobuffer, key), value)) + { + Info_SetValueForStarKey(infobuffer, key, value, MAX_INFO_STRING); + pClient = &g_psvs.clients[clientIndex - 1]; + pClient->sendinfo = TRUE; + pClient->sendinfo_time = 0.0f; + } +} + +/* <79c74> ../engine/pr_cmds.c:2078 */ +int PF_walkmove_I(edict_t *ent, float yaw, float dist, int iMode) +{ + vec3_t move; + + if (ent->v.flags & (FL_SWIM | FL_FLY | FL_ONGROUND)) + { + move[0] = cos(yaw * 2.0 * M_PI / 360.0) * dist; + move[1] = sin(yaw * 2.0 * M_PI / 360.0) * dist; + move[2] = 0; + + switch (iMode) { + case 1: + return SV_movetest(ent, move, 1); + + case 2: + return SV_movestep(ent, move, 0); + + default: + return SV_movestep(ent, move, 1); + } + } + return 0; +} + +/* <79cef> ../engine/pr_cmds.c:2120 */ +int PF_droptofloor_I(edict_t *ent) +{ + vec3_t end; + trace_t trace; + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0; + + end[0] = ent->v.origin[0]; + end[1] = ent->v.origin[1]; + end[2] = ent->v.origin[2] - 256.0; + trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, 0, ent, monsterClip); + if (trace.allsolid) + return -1; + + if (trace.fraction == 1.0f) + return 0; + + ent->v.origin[0] = trace.endpos[0]; + ent->v.origin[1] = trace.endpos[1]; + ent->v.origin[2] = trace.endpos[2]; + SV_LinkEdict(ent, 0); + ent->v.flags |= FL_ONGROUND; + ent->v.groundentity = trace.ent; + + return 1; +} + +/* <79d4c> ../engine/pr_cmds.c:2158 */ +int PF_DecalIndex(const char *name) +{ + for (int i = 0; i < sv_decalnamecount; i++) + { + if (!Q_stricmp(sv_decalnames[i].name, name)) + return i; + } + + return -1; +} + +/* <79d88> ../engine/pr_cmds.c:2180 */ +void PF_lightstyle_I(int style, char *val) +{ + g_psv.lightstyles[style] = val; + if (g_psv.state != ss_active) + return; + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t* cl = &g_psvs.clients[i]; + if ((cl->active || cl->spawned) && !cl->fakeclient) + { + MSG_WriteChar(&cl->netchan.message, svc_lightstyle); + MSG_WriteChar(&cl->netchan.message, style); + MSG_WriteString(&cl->netchan.message, val); + } + } +} + +/* <79ddf> ../engine/pr_cmds.c:2209 */ +int PF_checkbottom_I(edict_t *pEdict) +{ + return SV_CheckBottom(pEdict); +} + +/* <79e0c> ../engine/pr_cmds.c:2221 */ +int PF_pointcontents_I(const float *rgflVector) +{ + return SV_PointContents(rgflVector); +} + +/* <79e39> ../engine/pr_cmds.c:2237 */ +void PF_aim_I(edict_t *ent, float speed, float *rgflReturn) +{ + vec3_t start; // 2240 + vec3_t dir; // 2240 + vec3_t end; // 2240 + vec3_t bestdir; // 2240 + int j; // 2241 + trace_t tr; // 2242 + float dist; // 2243 + float bestdist; // 2243 + + if (!ent || (ent->v.flags & FL_FAKECLIENT)) + { + rgflReturn[0] = gGlobalVariables.v_forward[0]; + rgflReturn[1] = gGlobalVariables.v_forward[1]; + rgflReturn[2] = gGlobalVariables.v_forward[2]; + return; + } + + start[0] = ent->v.origin[0]; + start[1] = ent->v.origin[1]; + start[2] = ent->v.origin[2]; + + dir[0] = gGlobalVariables.v_forward[0]; + dir[1] = gGlobalVariables.v_forward[1]; + dir[2] = gGlobalVariables.v_forward[2]; + + start[0] += ent->v.view_ofs[0]; + start[1] += ent->v.view_ofs[1]; + start[2] += ent->v.view_ofs[2]; + VectorMA(start, 2048.0, dir, end); + tr = SV_Move(start, vec3_origin, vec3_origin, end, 0, ent, 0); + + if (tr.ent && tr.ent->v.takedamage == 2.0f && (ent->v.team <= 0 || ent->v.team != tr.ent->v.team)) + { + rgflReturn[0] = gGlobalVariables.v_forward[0]; + rgflReturn[1] = gGlobalVariables.v_forward[1]; + rgflReturn[2] = gGlobalVariables.v_forward[2]; + return; + } + + bestdir[1] = dir[1]; + bestdir[2] = dir[2]; + bestdir[0] = dir[0]; + bestdist = sv_aim.value; + + for (int i = 1; i < g_psv.num_edicts; i++) + { + edict_t* check = &g_psv.edicts[i]; + if (check->v.takedamage != 2.0f || (check->v.flags & FL_FAKECLIENT) || check == ent) + continue; + + if (ent->v.team > 0 && ent->v.team == check->v.team) + continue; + + for (j = 0; j < 3; j++) + { + end[j] = (check->v.maxs[j] + check->v.mins[j]) * 0.75 + check->v.origin[j] + ent->v.view_ofs[j] * 0.0; + } + + dir[0] = end[0] - start[0]; + dir[1] = end[1] - start[1]; + dir[2] = end[2] - start[2]; + VectorNormalize(dir); + dist = gGlobalVariables.v_forward[2] * dir[2] + + gGlobalVariables.v_forward[1] * dir[1] + + gGlobalVariables.v_forward[0] * dir[0]; + + if (dist >= bestdist) + { + tr = SV_Move(start, vec3_origin, vec3_origin, end, 0, ent, 0); + if (tr.ent == check) + { + bestdist = dist; + bestdir[0] = dir[0]; + bestdir[1] = dir[1]; + bestdir[2] = dir[2]; + } + } + } + + rgflReturn[0] = bestdir[0]; + rgflReturn[1] = bestdir[1]; + rgflReturn[2] = bestdir[2]; +} + +/* <79f2a> ../engine/pr_cmds.c:2313 */ +void PF_changeyaw_I(edict_t *ent) +{ + float ideal; + float current; + float move; + float speed; + + current = anglemod(ent->v.angles[1]); + ideal = ent->v.ideal_yaw; + speed = ent->v.yaw_speed; + if (current == ideal) + return; + + move = ideal - current; + if (ideal <= current) + { + if (move <= -180.0) + move += 360.0; + } + else + { + if (move >= 180.0) + move -= 360.0; + } + + if (move <= 0.0f) + { + if (move < -speed) + move = -speed; + } + else + { + if (move > speed) + move = speed; + } + + ent->v.angles[1] = anglemod(move + current); +} + +/* <79f94> ../engine/pr_cmds.c:2355 */ +void PF_changepitch_I(edict_t *ent) +{ + float ideal; + float current; + float move; + float speed; + + current = anglemod(ent->v.angles[0]); + ideal = ent->v.idealpitch; + speed = ent->v.pitch_speed; + if (current == ideal) + return; + + move = ideal - current; + if (ideal <= (double)current) + { + if (move <= -180.0) + move += 360.0; + } + else + { + if (move >= 180.0) + move -= 360; + } + + if (move <= 0.0) + { + if (move < -speed) + move = -speed; + } + else + { + if (move > speed) + move = speed; + } + + ent->v.angles[0] = anglemod(move + current); +} + +/* <79ffe> ../engine/pr_cmds.c:2398 */ +void PF_setview_I(const edict_t *clientent, const edict_t *viewent) +{ + int clientnum = NUM_FOR_EDICT(clientent); + if (clientnum < 1 || clientnum > g_psvs.maxclients) + Host_Error("PF_setview_I: not a client"); + + client_t * client = &g_psvs.clients[clientnum - 1]; + if (!client->fakeclient) + { + client->pViewEntity = viewent; + MSG_WriteByte(&client->netchan.message, svc_setview); + MSG_WriteShort(&client->netchan.message, NUM_FOR_EDICT(viewent)); + } +} + +/* <7a057> ../engine/pr_cmds.c:2426 */ +void PF_crosshairangle_I(const edict_t *clientent, float pitch, float yaw) +{ + int clientnum = NUM_FOR_EDICT(clientent); + if (clientnum < 1 || clientnum > g_psvs.maxclients) + return; + + + client_t* client = &g_psvs.clients[clientnum - 1]; + if (!client->fakeclient) + { + if (pitch > 180.0) + pitch -= 360.0; + + if (pitch < -180.0) + pitch += 360.0; + + if (yaw > 180.0) + yaw -= 360.0; + + if (yaw < -180.0) + yaw += 360.0; + + MSG_WriteByte(&client->netchan.message, svc_crosshairangle); + MSG_WriteChar(&client->netchan.message, (int)(pitch * 5.0)); + MSG_WriteChar(&client->netchan.message, (int)(yaw * 5.0)); + } +} + +/* <7a0c1> ../engine/pr_cmds.c:2457 */ +edict_t *PF_CreateFakeClient_I(const char *netname) +{ + client_t *fakeclient; + edict_t *ent; + + int i = 0; + fakeclient = g_psvs.clients; + for (i = 0; i < g_psvs.maxclients; i++, fakeclient++) + { + if (!fakeclient->active && !fakeclient->spawned && !fakeclient->connected) + break; + } + + if (i >= g_psvs.maxclients) + return NULL; + + ent = EDICT_NUM(i + 1); + if (fakeclient->frames) + SV_ClearFrames(&fakeclient->frames); + + Q_memset(fakeclient, 0, sizeof(client_t)); + fakeclient->resourcesneeded.pPrev = &fakeclient->resourcesneeded; + fakeclient->resourcesneeded.pNext = &fakeclient->resourcesneeded; + fakeclient->resourcesonhand.pPrev = &fakeclient->resourcesonhand; + fakeclient->resourcesonhand.pNext = &fakeclient->resourcesonhand; + + Q_strncpy(fakeclient->name, netname, sizeof(fakeclient->name) - 1); + fakeclient->name[sizeof(fakeclient->name) - 1] = 0; + + fakeclient->active = 1; + fakeclient->spawned = 1; + fakeclient->fully_connected = 1; + fakeclient->connected = 1; + fakeclient->fakeclient = 1; + fakeclient->userid = g_userid++; + fakeclient->uploading = 0; + fakeclient->edict = ent; + ent->v.netname = (size_t)fakeclient->name - (size_t)pr_strings; + ent->v.pContainingEntity = ent; + ent->v.flags = FL_FAKECLIENT | FL_CLIENT; + + Info_SetValueForKey(fakeclient->userinfo, "name", netname, 256); + Info_SetValueForKey(fakeclient->userinfo, "model", "gordon", 256); + Info_SetValueForKey(fakeclient->userinfo, "topcolor", "1", 256); + Info_SetValueForKey(fakeclient->userinfo, "bottomcolor", "1", 256); + fakeclient->sendinfo = 1; + SV_ExtractFromUserinfo(fakeclient); + + fakeclient->network_userid.m_SteamID = ISteamGameServer_CreateUnauthenticatedUserConnection(); + fakeclient->network_userid.idtype = AUTH_IDTYPE_STEAM; + ISteamGameServer_BUpdateUserData(fakeclient->network_userid.m_SteamID, netname, 0); + + return ent; +} + +/* <7a12b> ../engine/pr_cmds.c:2519 */ +void PF_RunPlayerMove_I(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, short unsigned int buttons, unsigned char impulse, unsigned char msec) +{ + usercmd_t cmd; + edict_t *oldclient; + client_t *old; + int entnum; + + oldclient = sv_player; + old = host_client; + entnum = NUM_FOR_EDICT(fakeclient); + sv_player = fakeclient; + host_client = &g_psvs.clients[entnum - 1]; + + host_client->svtimebase = host_frametime + g_psv.time - msec / 1000.0; + Q_memset(&cmd, 0, sizeof(cmd)); + cmd.lightlevel = 0; + pmove = &g_svmove; + + cmd.viewangles[0] = viewangles[0]; + cmd.viewangles[1] = viewangles[1]; + cmd.viewangles[2] = viewangles[2]; + cmd.forwardmove = forwardmove; + cmd.sidemove = sidemove; + cmd.upmove = upmove; + cmd.buttons = buttons; + cmd.impulse = impulse; + cmd.msec = msec; + + SV_PreRunCmd(); + SV_RunCmd(&cmd, 0); + memcpy(&host_client->lastcmd, &cmd, sizeof(host_client->lastcmd)); + + sv_player = oldclient; + host_client = old; +} + +/* <7a1fe> ../engine/pr_cmds.c:2578 */ +sizebuf_t *WriteDest_Parm(int dest) +{ + int entnum; + + switch (dest) + { + case MSG_BROADCAST: + return &g_psv.datagram; + case MSG_ONE: + case MSG_ONE_UNRELIABLE: + entnum = NUM_FOR_EDICT(gMsgEntity); + if (entnum <= 0 || entnum > g_psvs.maxclients) + { + Host_Error("WriteDest_Parm: not a client"); + } + if (dest == MSG_ONE) + { + return &g_psvs.clients[entnum - 1].netchan.message; + } + else + { + return &g_psvs.clients[entnum - 1].datagram; + } + case MSG_INIT: + return &g_psv.signon; + case MSG_ALL: + return &g_psv.reliable_datagram; + case MSG_PVS: + case MSG_PAS: + return &g_psv.multicast; + case MSG_SPEC: + return &g_psv.spectator; + default: + Host_Error("WriteDest_Parm: bad destination=%d", dest); + } +} + +/* <7a23d> ../engine/pr_cmds.c:2624 */ +void PF_MessageBegin_I(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +{ + if (msg_dest == MSG_ONE || msg_dest == MSG_ONE_UNRELIABLE) + { + if (!ed) + Sys_Error("MSG_ONE or MSG_ONE_UNRELIABLE with no target entity\n"); + } + else + { + if (ed) + Sys_Error("Invalid message; cannot use broadcast message with a target entity"); + } + + if (gMsgStarted) + Sys_Error("New message started when msg '%d' has not been sent yet", gMsgType); + + if (msg_type == 0) + Sys_Error("Tried to create a message with a bogus message type ( 0 )"); + + gMsgStarted = 1; + gMsgType = msg_type; + gMsgEntity = ed; + gMsgDest = msg_dest; + if (msg_dest == MSG_PVS || msg_dest == MSG_PAS) + { + if (pOrigin) + { + gMsgOrigin[0] = pOrigin[0]; + gMsgOrigin[1] = pOrigin[1]; + gMsgOrigin[2] = pOrigin[2]; + } + Host_IsSinglePlayerGame(); + } + + gMsgBuffer.flags = SIZEBUF_ALLOW_OVERFLOW; + gMsgBuffer.cursize = 0; +} + +/* <7a293> ../engine/pr_cmds.c:2669 */ +void PF_MessageEnd_I(void) +{ + qboolean MsgIsVarLength = 0; + if (!gMsgStarted) + Sys_Error("MESSAGE_END called with no active message\n"); + gMsgStarted = 0; + + if (gMsgEntity && (gMsgEntity->v.flags & FL_FAKECLIENT)) + return; + + if (gMsgBuffer.flags & SIZEBUF_OVERFLOWED) + Sys_Error("MESSAGE_END called, but message buffer from .dll had overflowed\n"); + + + if (gMsgType > svc_startofusermessages) + { + UserMsg* pUserMsg = sv_gpUserMsgs; + while (pUserMsg && pUserMsg->iMsg != gMsgType) + pUserMsg = pUserMsg->next; + + if (!pUserMsg && gMsgDest == MSG_INIT) + { + pUserMsg = sv_gpNewUserMsgs; + while (pUserMsg && pUserMsg->iMsg != gMsgType) + pUserMsg = pUserMsg->next; + } + + if (!pUserMsg) + { + Con_DPrintf("PF_MessageEnd_I: Unknown User Msg %d\n", gMsgType); + return; + } + + if (pUserMsg->iSize == -1) + { + MsgIsVarLength = 1; + if (gMsgBuffer.cursize > 192) + Host_Error( + "PF_MessageEnd_I: Refusing to send user message %s of %i bytes to client, user message size limit is %i bytes\n", + pUserMsg->szName, + gMsgBuffer.cursize, + 192 + ); + } + else + { + if (pUserMsg->iSize != gMsgBuffer.cursize) + Sys_Error( + "User Msg '%s': %d bytes written, expected %d\n", + pUserMsg->szName, + gMsgBuffer.cursize, + pUserMsg->iSize + ); + } + } + + sizebuf_t * pBuffer = WriteDest_Parm(gMsgDest); + if ((!gMsgDest && gMsgBuffer.cursize + pBuffer->cursize > pBuffer->maxsize) || !pBuffer->data) + return; + + if (gMsgType > svc_startofusermessages && (gMsgDest == MSG_ONE || gMsgDest == MSG_ONE_UNRELIABLE)) + { + int entnum = NUM_FOR_EDICT((const edict_t *)gMsgEntity); + if (entnum < 1 || entnum > g_psvs.maxclients) + Host_Error("WriteDest_Parm: not a client"); + + client_t* client = &g_psvs.clients[entnum - 1]; + if (client->fakeclient || !client->hasusrmsgs || (!client->active && !client->spawned)) + return; + } + + MSG_WriteByte(pBuffer, gMsgType); + if (MsgIsVarLength) + MSG_WriteByte(pBuffer, gMsgBuffer.cursize); + MSG_WriteBuf(pBuffer, gMsgBuffer.cursize, gMsgBuffer.data); + + switch (gMsgDest) + { + case MSG_PVS: + SV_Multicast((edict_t *)gMsgEntity, gMsgOrigin, MSG_FL_PVS, 0); + break; + + case MSG_PAS: + SV_Multicast((edict_t *)gMsgEntity, gMsgOrigin, MSG_FL_PAS, 0); + break; + + case MSG_PVS_R: + SV_Multicast((edict_t *)gMsgEntity, gMsgOrigin, MSG_FL_PAS, 1); //TODO: Should be MSG_FL_PVS, investigation needed + break; + + case MSG_PAS_R: + SV_Multicast((edict_t *)gMsgEntity, gMsgOrigin, MSG_FL_PAS, 1); + break; + + default: + return; + } +} + +/* <7a317> ../engine/pr_cmds.c:2802 */ +void PF_WriteByte_I(int iValue) +{ + if (!gMsgStarted) + Sys_Error("WRITE_BYTE called with no active message\n"); + MSG_WriteByte(&gMsgBuffer, iValue); +} + +/* <7a341> ../engine/pr_cmds.c:2810 */ +void PF_WriteChar_I(int iValue) +{ + if (!gMsgStarted) + Sys_Error("WRITE_CHAR called with no active message\n"); + MSG_WriteChar(&gMsgBuffer, iValue); +} + +/* <7a36b> ../engine/pr_cmds.c:2818 */ +void PF_WriteShort_I(int iValue) +{ + if (!gMsgStarted) + Sys_Error("WRITE_SHORT called with no active message\n"); + MSG_WriteShort(&gMsgBuffer, iValue); +} + +/* <7a395> ../engine/pr_cmds.c:2826 */ +void PF_WriteLong_I(int iValue) +{ + if (!gMsgStarted) + Sys_Error("PF_WriteLong_I called with no active message\n"); + MSG_WriteLong(&gMsgBuffer, iValue); +} + +/* <7a3bf> ../engine/pr_cmds.c:2834 */ +void PF_WriteAngle_I(float flValue) +{ + if (!gMsgStarted) + Sys_Error("PF_WriteAngle_I called with no active message\n"); + MSG_WriteAngle(&gMsgBuffer, flValue); +} + +/* <7a3e9> ../engine/pr_cmds.c:2842 */ +void PF_WriteCoord_I(float flValue) +{ + if (!gMsgStarted) + Sys_Error("PF_WriteCoord_I called with no active message\n"); + MSG_WriteShort(&gMsgBuffer, (int)(flValue * 8.0)); +} + +/* <7a413> ../engine/pr_cmds.c:2851 */ +void PF_WriteString_I(const char *sz) +{ + if (!gMsgStarted) + Sys_Error("PF_WriteString_I called with no active message\n"); + MSG_WriteString(&gMsgBuffer, sz); +} + +/* <7a43c> ../engine/pr_cmds.c:2859 */ +void PF_WriteEntity_I(int iValue) +{ + if (!gMsgStarted) + Sys_Error("PF_WriteEntity_I called with no active message\n"); + MSG_WriteShort(&gMsgBuffer, iValue); +} + +/* <7a466> ../engine/pr_cmds.c:2874 */ +void PF_makestatic_I(edict_t *ent) +{ + MSG_WriteByte(&g_psv.signon, svc_spawnstatic); + MSG_WriteShort(&g_psv.signon, SV_ModelIndex(&pr_strings[ent->v.model])); + MSG_WriteByte(&g_psv.signon, ent->v.sequence); + MSG_WriteByte(&g_psv.signon, (int)ent->v.frame); + MSG_WriteWord(&g_psv.signon, ent->v.colormap); + MSG_WriteByte(&g_psv.signon, ent->v.skin); + + for (int i = 0; i < 3; i++) + { + MSG_WriteCoord(&g_psv.signon, ent->v.origin[i]); + MSG_WriteAngle(&g_psv.signon, ent->v.angles[i]); + } + + MSG_WriteByte(&g_psv.signon, ent->v.rendermode); + if (ent->v.rendermode) + { + MSG_WriteByte(&g_psv.signon, (int)ent->v.renderamt); + MSG_WriteByte(&g_psv.signon, (int)ent->v.rendercolor[0]); + MSG_WriteByte(&g_psv.signon, (int)ent->v.rendercolor[1]); + MSG_WriteByte(&g_psv.signon, (int)ent->v.rendercolor[2]); + MSG_WriteByte(&g_psv.signon, ent->v.renderfx); + } + + ED_Free(ent); +} + +/* <7a49e> ../engine/pr_cmds.c:2910 */ +void PF_StaticDecal(const float *origin, int decalIndex, int entityIndex, int modelIndex) +{ + MSG_WriteByte(&g_psv.signon, svc_temp_entity); + MSG_WriteByte(&g_psv.signon, TE_BSPDECAL); + MSG_WriteCoord(&g_psv.signon, *origin); + MSG_WriteCoord(&g_psv.signon, origin[1]); + MSG_WriteCoord(&g_psv.signon, origin[2]); + MSG_WriteShort(&g_psv.signon, decalIndex); + MSG_WriteShort(&g_psv.signon, entityIndex); + + if (entityIndex) + MSG_WriteShort(&g_psv.signon, modelIndex); +} + +/* <7a4f5> ../engine/pr_cmds.c:2935 */ +void PF_setspawnparms_I(edict_t *ent) +{ + int i = NUM_FOR_EDICT(ent); + if (i < 1 || i > g_psvs.maxclients) + Host_Error("Entity is not a client"); +} + +/* <7a539> ../engine/pr_cmds.c:2956 */ +void PF_changelevel_I(char *s1, char *s2) +{ + static int last_spawncount; + + if (g_psvs.spawncount != last_spawncount) + { + last_spawncount = g_psvs.spawncount; + SV_SkipUpdates(); + if (s2) + Cbuf_AddText(va("changelevel2 %s %s\n", s1, s2)); + else + Cbuf_AddText(va("changelevel %s\n", s1)); + } +} + +/* <7a582> ../engine/pr_cmds.c:2988 */ +void SeedRandomNumberGenerator(void) +{ + idum = -(int)CRehldsPlatformHolder::get()->time(NULL); + if (idum > 1000) + { + idum = -idum; + } + else if (idum > -1000) + { + idum -= 22261048; + } +} + +#define IA 16807 +#define IM 2147483647 +#define IQ 127773 +#define IR 2836 +#define NTAB 32 +#define NDIV (1+(IM-1)/NTAB) + +/* <7a598> ../engine/pr_cmds.c:3003 */ +int32_t ran1(void) +{ + int j; + long k; + static long iy = 0; + static long iv[NTAB]; + + if (idum <= 0 || !iy) + { + if (-(idum) < 1) idum = 1; + else idum = -(idum); + for (j = NTAB + 7; j >= 0; j--) + { + k = (idum) / IQ; + idum = IA*(idum - k*IQ) - IR*k; + if (idum < 0) idum += IM; + if (j < NTAB) iv[j] = idum; + } + iy = iv[0]; + } + k = (idum) / IQ; + idum = IA*(idum - k*IQ) - IR*k; + if (idum < 0) idum += IM; + j = iy / NDIV; + iy = iv[j]; + iv[j] = idum; + + return iy; +} + +#define AM (1.0/IM) +#define EPS 1.2e-7 +#define RNMX (1.0-EPS) + +/* <7a605> ../engine/pr_cmds.c:3038 */ +float fran1(void) +{ + float temp = (float)AM*ran1(); + if (temp > RNMX) return (float)RNMX; + else return temp; +} + +/* <7a644> ../engine/pr_cmds.c:3045 */ +float RandomFloat(float flLow, float flHigh) +{ +#ifndef SWDS + g_engdstAddrs.pfnRandomFloat(&flLow, &flHigh); +#endif + + float fl = fran1(); // float in [0,1) + return (fl * (flHigh - flLow)) + flLow; // float in [low,high) +} + +/* <7a6b2> ../engine/pr_cmds.c:3056 */ +int32_t RandomLong(int32_t lLow, int32_t lHigh) +{ +#ifndef SWDS + g_engdstAddrs.pfnRandomLong(&lLow, &lHigh); +#endif + + unsigned long maxAcceptable; + unsigned long x = lHigh - lLow + 1; + unsigned long n; + if (x <= 0 || MAX_RANDOM_RANGE < x - 1) + { + return lLow; + } + + // The following maps a uniform distribution on the interval [0,MAX_RANDOM_RANGE] + // to a smaller, client-specified range of [0,x-1] in a way that doesn't bias + // the uniform distribution unfavorably. Even for a worst case x, the loop is + // guaranteed to be taken no more than half the time, so for that worst case x, + // the average number of times through the loop is 2. For cases where x is + // much smaller than MAX_RANDOM_RANGE, the average number of times through the + // loop is very close to 1. + // + maxAcceptable = MAX_RANDOM_RANGE - ((MAX_RANDOM_RANGE + 1) % x); + do + { + n = ran1(); + } while (n > maxAcceptable); + + return lLow + (n % x); +} + +/* <7a71b> ../engine/pr_cmds.c:3089 */ +void PF_FadeVolume(const edict_t *clientent, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds) +{ + int entnum = NUM_FOR_EDICT(clientent); + if (entnum < 1 || entnum > g_psvs.maxclients) + { + Con_Printf("tried to PF_FadeVolume a non-client\n"); + return; + } + + client_t* client = &g_psvs.clients[entnum - 1]; + if (client->fakeclient) + return; + + MSG_WriteChar(&client->netchan.message, svc_soundfade); + MSG_WriteByte(&client->netchan.message, (uint8_t)fadePercent); + MSG_WriteByte(&client->netchan.message, (uint8_t)holdTime); + MSG_WriteByte(&client->netchan.message, (uint8_t)fadeOutSeconds); + MSG_WriteByte(&client->netchan.message, (uint8_t)fadeInSeconds); +} + +/* <7a7a1> ../engine/pr_cmds.c:3124 */ +void PF_SetClientMaxspeed(edict_t *clientent, float fNewMaxspeed) +{ + int entnum = NUM_FOR_EDICT(clientent); + if (entnum < 1 || entnum > g_psvs.maxclients) + Con_Printf("tried to PF_SetClientMaxspeed a non-client\n"); + + clientent->v.maxspeed = fNewMaxspeed; +} + +/* <7a80b> ../engine/pr_cmds.c:3149 */ +int PF_GetPlayerUserId(edict_t *e) +{ + if (!g_psv.active || !e) + return -1; + + for (int i = 0; i < g_psvs.maxclients; i++) { + if (g_psvs.clients[i].edict == e) { + return g_psvs.clients[i].userid; + } + } + + return -1; +} + +/* <7a854> ../engine/pr_cmds.c:3172 */ +unsigned int PF_GetPlayerWONId(edict_t *e) +{ + return 0xFFFFFFFF; +} + +/* <7a87f> ../engine/pr_cmds.c:3180 */ +const char *PF_GetPlayerAuthId(edict_t *e) +{ + static char szAuthID[5][64]; + static int count = 0; + client_t *cl; + int i; + + count = (count + 1) % 5; + szAuthID[count][0] = 0; + + if (!g_psv.active || e == NULL) + { + return szAuthID[count]; + } + + for (i = 0; i < g_psvs.maxclients; i++) + { + cl = &g_psvs.clients[i]; + if (cl->edict != e) + { + continue; + } + + if (cl->fakeclient) + { + Q_strcpy(szAuthID[count], "BOT"); + } +// AUTH_IDTYPE_LOCAL is handled inside SV_GetIDString(), no need to do it here +// else if (cl->network_userid.idtype == AUTH_IDTYPE_LOCAL) +// { +// Q_strcpy(szAuthID[count], "HLTV"); +// } + else + { + Q_snprintf(szAuthID[count], sizeof(szAuthID[count]) - 1, "%s", SV_GetClientIDString(cl)); + } + + break; + } + + return szAuthID[count]; +} + +/* <7a902> ../engine/pr_cmds.c:3229 */ +void PF_BuildSoundMsg_I(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed) +{ + PF_MessageBegin_I(msg_dest, msg_type, pOrigin, ed); + SV_BuildSoundMsg(entity, channel, sample, (int)volume, attenuation, fFlags, pitch, pOrigin, &gMsgBuffer); + PF_MessageEnd_I(); +} + +/* <7a9c1> ../engine/pr_cmds.c:3240 */ +int PF_IsDedicatedServer(void) +{ + return g_bIsDedicatedServer; +} + +/* <7a9da> ../engine/pr_cmds.c:3245 */ +const char *PF_GetPhysicsInfoString(const edict_t *pClient) +{ + int entnum = NUM_FOR_EDICT(pClient); + if (entnum < 1 || entnum > g_psvs.maxclients) + { + Con_Printf("tried to PF_GetPhysicsInfoString a non-client\n"); + return ""; + } + + client_t* client = &g_psvs.clients[entnum - 1]; + return client->physinfo; +} + +/* <7aa28> ../engine/pr_cmds.c:3259 */ +const char *PF_GetPhysicsKeyValue(const edict_t *pClient, const char *key) +{ + int entnum = NUM_FOR_EDICT(pClient); + if (entnum < 1 || entnum > g_psvs.maxclients) + { + Con_Printf("tried to PF_GetPhysicsKeyValue a non-client\n"); + return ""; + } + + client_t* client = &g_psvs.clients[entnum - 1]; + return Info_ValueForKey(client->physinfo, key); +} + +/* <7aa85> ../engine/pr_cmds.c:3273 */ +void PF_SetPhysicsKeyValue(const edict_t *pClient, const char *key, const char *value) +{ + int entnum = NUM_FOR_EDICT(pClient); + if (entnum < 1 || entnum > g_psvs.maxclients) + Con_Printf("tried to PF_SetPhysicsKeyValue a non-client\n"); + + client_t* client = &g_psvs.clients[entnum - 1]; + Info_SetValueForKey(client->physinfo, key, value, MAX_INFO_STRING); +} + +/* <7aaed> ../engine/pr_cmds.c:3287 */ +int PF_GetCurrentPlayer(void) +{ + int idx = host_client - g_psvs.clients; + if (idx < 0 || idx >= g_psvs.maxclients) + return -1; + + return idx; +} + +/* <7ab19> ../engine/pr_cmds.c:3296 */ +int PF_CanSkipPlayer(const edict_t *pClient) +{ + int entnum = NUM_FOR_EDICT(pClient); + if (entnum < 1 || entnum > g_psvs.maxclients) + { + Con_Printf("tried to PF_CanSkipPlayer a non-client\n"); + return 0; + } + + client_t* client = &g_psvs.clients[entnum - 1]; + return client->lw != 0; +} + +/* <7ab67> ../engine/pr_cmds.c:3313 */ +void PF_SetGroupMask(int mask, int op) +{ + g_groupmask = mask; + g_groupop = op; +} + +/* <7ab9e> ../engine/pr_cmds.c:3319 */ +int PF_CreateInstancedBaseline(int classname, struct entity_state_s *baseline) +{ + extra_baselines_t *bls = g_psv.instance_baselines; + if (bls->number >= NUM_BASELINES) + return 0; + + bls->classname[bls->number] = classname; + memcpy(&bls->baseline[bls->number], baseline, sizeof(struct entity_state_s)); + bls->number += 1; + return bls->number; +} + +/* <7abdb> ../engine/pr_cmds.c:3332 */ +void PF_Cvar_DirectSet(struct cvar_s *var, char *value) +{ + Cvar_DirectSet(var, value); +} + +/* <7ac13> ../engine/pr_cmds.c:3337 */ +void PF_ForceUnmodified(FORCE_TYPE type, float *mins, float *maxs, const char *filename) +{ + int i; + + if (!filename) + Host_Error("PF_ForceUnmodified: NULL pointer"); + + if (PR_IsEmptyString(filename)) + Host_Error("PF_ForceUnmodified: Bad string '%s'", filename); + + if (g_psv.state == ss_loading) + { + i = 0; + consistency_t* cnode = g_psv.consistency_list; + while (cnode->filename) + { + if (!Q_stricmp(cnode->filename, (char *)filename)) + return; + + ++cnode; + ++i; + + if (i >= 512) + Host_Error("ForceUnmodified: '%s' overflow", filename); + } + + cnode->check_type = type; + cnode->filename = (char *)filename; + if (mins) + { + cnode->mins[0] = mins[0]; + cnode->mins[1] = mins[1]; + cnode->mins[2] = mins[2]; + } + if (maxs) + { + cnode->maxs[0] = maxs[0]; + cnode->maxs[1] = maxs[1]; + cnode->maxs[2] = maxs[2]; + } + } + else + { + i = 0; + consistency_t* cnode = g_psv.consistency_list; + while (!cnode->filename || Q_stricmp(cnode->filename, filename)) + { + ++cnode; + ++i; + if (i >= 512) + Host_Error("ForceUnmodified: '%s' Precache can only be done in spawn functions", filename); + } + } +} + +/* <7ac92> ../engine/pr_cmds.c:3386 */ +void PF_GetPlayerStats(const edict_t *pClient, int *ping, int *packet_loss) +{ + *packet_loss = 0; + *ping = 0; + int c = NUM_FOR_EDICT(pClient); + if (c < 1 || c > g_psvs.maxclients) + { + Con_Printf("tried to PF_GetPlayerStats a non-client\n"); + return; + } + + client_t* client = &g_psvs.clients[c - 1]; + *packet_loss = client->packet_loss; + *ping = client->latency * 1000.0; +} + +/* <7ad3a> ../engine/pr_cmds.c:3408 */ +NOXREF void QueryClientCvarValueCmd(void) +{ + if (Cmd_Argc() <= 1) + { + Con_Printf("%s \n", Cmd_Argv(0)); + return; + } + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + + if (cl->active || cl->connected) + { + if (!Q_stricmp(cl->name, Cmd_Argv(1))) + { + QueryClientCvarValue(cl->edict, Cmd_Argv(2)); + break; + } + } + } +} + +/* <7adff> ../engine/pr_cmds.c:3433 */ +NOXREF void QueryClientCvarValueCmd2(void) +{ + int i; + client_t *cl; + int requestID; + + if (Cmd_Argc() < 3) + { + Con_Printf("%s ", Cmd_Argv(0)); + return; + } + requestID = atoi(Cmd_Argv(3)); + for (i = 0; i < g_psvs.maxclients; i++) + { + cl = &g_psvs.clients[i]; + + if (cl->active || cl->connected) + { + if (!Q_stricmp(cl->name, Cmd_Argv(1))) + { + QueryClientCvarValue2(cl->edict, Cmd_Argv(2), requestID); + break; + } + } + } +} + +/* <7acfa> ../engine/pr_cmds.c:3461 */ +void QueryClientCvarValue(const edict_t *player, const char *cvarName) +{ + + int entnum = NUM_FOR_EDICT(player); + if (entnum < 1 || entnum > g_psvs.maxclients) + { + if (gNewDLLFunctions.pfnCvarValue) + gNewDLLFunctions.pfnCvarValue(player, "Bad Player"); + + Con_Printf("tried to QueryClientCvarValue a non-client\n"); + return; + } + client_t *client = &g_psvs.clients[entnum - 1]; + MSG_WriteChar(&client->netchan.message, svc_sendcvarvalue); + MSG_WriteString(&client->netchan.message, cvarName); +} + +/* <7adb3> ../engine/pr_cmds.c:3485 */ +void QueryClientCvarValue2(const edict_t *player, const char *cvarName, int requestID) +{ + int entnum = NUM_FOR_EDICT(player); + if (entnum < 1 || entnum > g_psvs.maxclients) + { + if (gNewDLLFunctions.pfnCvarValue2) + gNewDLLFunctions.pfnCvarValue2(player, requestID, cvarName, "Bad Player"); + + Con_Printf("tried to QueryClientCvarValue a non-client\n"); + return; + } + client_t *client = &g_psvs.clients[entnum - 1]; + MSG_WriteChar(&client->netchan.message, svc_sendcvarvalue2); + MSG_WriteLong(&client->netchan.message, requestID); + MSG_WriteString(&client->netchan.message, cvarName); +} + +/* <7af41> ../engine/pr_cmds.c:3509 */ +int hudCheckParm(char *parm, char **ppnext) +{ +#ifndef SWDS + g_engdstAddrs.CheckParm(&parm, &ppnext); +#endif + + int i = COM_CheckParm(parm); + if (ppnext) + { + if (i && i < com_argc - 1) + *ppnext = com_argv[i + 1]; + else + *ppnext = 0; + } + return i; +} + +/* <7afa4> ../engine/pr_cmds.c:3532 */ +int EngCheckParm(const char *pchCmdLineToken, char **pchNextVal) +{ + return hudCheckParm((char*)pchCmdLineToken, pchNextVal); +} diff --git a/rehlds/engine/pr_cmds.h b/rehlds/engine/pr_cmds.h new file mode 100644 index 0000000..b277f90 --- /dev/null +++ b/rehlds/engine/pr_cmds.h @@ -0,0 +1,215 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef PR_CMDS_H +#define PR_CMDS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "const.h" +#include "eiface.h" +#include "model.h" +#include "common.h" +#include "server.h" + + +#define MAX_RANDOM_RANGE 0x7FFFFFFFUL + +#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation +#define AMBIENT_SOUND_EVERYWHERE 1 +#define AMBIENT_SOUND_SMALLRADIUS 2 +#define AMBIENT_SOUND_MEDIUMRADIUS 4 +#define AMBIENT_SOUND_LARGERADIUS 8 +#define AMBIENT_SOUND_START_SILENT 16 +#define AMBIENT_SOUND_NOT_LOOPING 32 + +#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements + + +#ifdef HOOK_ENGINE +#define gMsgData (*pgMsgData) +#define gMsgBuffer (*pgMsgBuffer) +#define gMsgEntity (*pgMsgEntity) +#define gMsgDest (*pgMsgDest) +#define gMsgType (*pgMsgType) +#define gMsgStarted (*pgMsgStarted) +#define gMsgOrigin (*pgMsgOrigin) +#define idum (*pidum) +#define g_groupop (*pg_groupop) +#define g_groupmask (*pg_groupmask) +#define checkpvs (*pcheckpvs) +#define c_invis (*pc_invis) +#define c_notvis (*pc_notvis) + +#define vec_origin (*pvec_origin) + +#define r_visframecount (*pr_visframecount) +#endif // HOOK_ENGINE + + +extern unsigned char gMsgData[512]; +extern sizebuf_t gMsgBuffer; +extern edict_t *gMsgEntity; +extern int gMsgDest; +extern int gMsgType; +extern qboolean gMsgStarted; +extern vec3_t gMsgOrigin; +extern int32_t idum; +extern int g_groupop; +extern int g_groupmask; +extern unsigned char checkpvs[1024]; +extern int c_invis; +extern int c_notvis; + +extern vec3_t vec_origin; + +extern int r_visframecount; + +#define GROUP_OP_AND 0 +#define GROUP_OP_NAND 1 + +void PF_makevectors_I(const float *rgflVector); +float PF_Time(void); +void PF_setorigin_I(edict_t *e, const float *org); +void SetMinMaxSize(edict_t *e, const float *min, const float *max, qboolean rotate); +void PF_setsize_I(edict_t *e, const float *rgflMin, const float *rgflMax); +void PF_setmodel_I(edict_t *e, const char *m); +int PF_modelindex(const char *pstr); +int ModelFrames(int modelIndex); +void PF_bprint(char *s); +void PF_sprint(char *s, int entnum); +void ServerPrint(const char *szMsg); +void ClientPrintf(edict_t *pEdict, PRINT_TYPE ptype, const char *szMsg); +float PF_vectoyaw_I(const float *rgflVector); +void PF_vectoangles_I(const float *rgflVectorIn, float *rgflVectorOut); +void PF_particle_I(const float *org, const float *dir, float color, float count); +void PF_ambientsound_I(edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch); +void PF_sound_I(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch); +void PF_traceline_Shared(const float *v1, const float *v2, int nomonsters, edict_t *ent); +void PF_traceline_DLL(const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); +void TraceHull(const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr); +void TraceSphere(const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr); +void TraceModel(const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr); +msurface_t *SurfaceAtPoint(model_t *pModel, mnode_t *node, vec_t *start, vec_t *end); +const char *TraceTexture(edict_t *pTextureEntity, const float *v1, const float *v2); +void PF_TraceToss_Shared(edict_t *ent, edict_t *ignore); +void SV_SetGlobalTrace(trace_t *ptrace); +void PF_TraceToss_DLL(edict_t *pent, edict_t *pentToIgnore, TraceResult *ptr); +int TraceMonsterHull(edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); +int PF_newcheckclient(int check); +edict_t *PF_checkclient_I(edict_t *pEdict); +mnode_t *PVSNode(mnode_t *node, vec_t *emins, vec_t *emaxs); +void PVSMark(model_t *pmodel, unsigned char *ppvs); +edict_t *PVSFindEntities(edict_t *pplayer); +qboolean ValidCmd(const char *pCmd); +void PF_stuffcmd_I(edict_t *pEdict, char *szFmt, ...); +void PF_localcmd_I(char *str); +void PF_localexec_I(void); +edict_t *FindEntityInSphere(edict_t *pEdictStartSearchAfter, const float *org, float rad); +edict_t *PF_Spawn_I(void); +edict_t *CreateNamedEntity(int className); +void PF_Remove_I(edict_t *ed); +edict_t *PF_find_Shared(int eStartSearchAfter, int iFieldToMatch, const char *szValueToFind); +int iGetIndex(const char *pszField); +edict_t *FindEntityByString(edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue); +int GetEntityIllum(edict_t *pEnt); +qboolean PR_IsEmptyString(const char *s); +int PF_precache_sound_I(char *s); +short unsigned int EV_Precache(int type, const char *psz); +void EV_PlayReliableEvent(client_t *cl, int entindex, short unsigned int eventindex, float delay, event_args_t *pargs); +void EV_Playback(int flags, const edict_t *pInvoker, short unsigned int eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2); +void EV_SV_Playback(int flags, int clientindex, short unsigned int eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2); +int PF_precache_model_I(char *s); +int PF_precache_generic_I(char *s); +int PF_IsMapValid_I(char *mapname); +int PF_NumberOfEntities_I(void); +char *PF_GetInfoKeyBuffer_I(edict_t *e); +char *PF_InfoKeyValue_I(char *infobuffer, char *key); +void PF_SetKeyValue_I(char *infobuffer, char *key, char *value); +void PF_RemoveKey_I(char *s, const char *key); +void PF_SetClientKeyValue_I(int clientIndex, char *infobuffer, char *key, char *value); +int PF_walkmove_I(edict_t *ent, float yaw, float dist, int iMode); +int PF_droptofloor_I(edict_t *ent); +int PF_DecalIndex(const char *name); +void PF_lightstyle_I(int style, char *val); +int PF_checkbottom_I(edict_t *pEdict); +int PF_pointcontents_I(const float *rgflVector); +void PF_aim_I(edict_t *ent, float speed, float *rgflReturn); +void PF_changeyaw_I(edict_t *ent); +void PF_changepitch_I(edict_t *ent); +void PF_setview_I(const edict_t *clientent, const edict_t *viewent); +void PF_crosshairangle_I(const edict_t *clientent, float pitch, float yaw); +edict_t *PF_CreateFakeClient_I(const char *netname); +void PF_RunPlayerMove_I(edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, short unsigned int buttons, unsigned char impulse, unsigned char msec); +sizebuf_t *WriteDest_Parm(int dest); +void PF_MessageBegin_I(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); +void PF_MessageEnd_I(void); +void PF_WriteByte_I(int iValue); +void PF_WriteChar_I(int iValue); +void PF_WriteShort_I(int iValue); +void PF_WriteLong_I(int iValue); +void PF_WriteAngle_I(float flValue); +void PF_WriteCoord_I(float flValue); +void PF_WriteString_I(const char *sz); +void PF_WriteEntity_I(int iValue); +void PF_makestatic_I(edict_t *ent); +void PF_StaticDecal(const float *origin, int decalIndex, int entityIndex, int modelIndex); +void PF_setspawnparms_I(edict_t *ent); +void PF_changelevel_I(char *s1, char *s2); +void SeedRandomNumberGenerator(void); +int32_t ran1(void); +float fran1(void); +float RandomFloat(float flLow, float flHigh); +int32_t RandomLong(int32_t lLow, int32_t lHigh); +void PF_FadeVolume(const edict_t *clientent, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds); +void PF_SetClientMaxspeed(edict_t *clientent, float fNewMaxspeed); +int PF_GetPlayerUserId(edict_t *e); +unsigned int PF_GetPlayerWONId(edict_t *e); +const char *PF_GetPlayerAuthId(edict_t *e); +void PF_BuildSoundMsg_I(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); +int PF_IsDedicatedServer(void); +const char *PF_GetPhysicsInfoString(const edict_t *pClient); +const char *PF_GetPhysicsKeyValue(const edict_t *pClient, const char *key); +void PF_SetPhysicsKeyValue(const edict_t *pClient, const char *key, const char *value); +int PF_GetCurrentPlayer(void); +int PF_CanSkipPlayer(const edict_t *pClient); +void PF_SetGroupMask(int mask, int op); +int PF_CreateInstancedBaseline(int classname, struct entity_state_s *baseline); +void PF_Cvar_DirectSet(struct cvar_s *var, char *value); +void PF_ForceUnmodified(FORCE_TYPE type, float *mins, float *maxs, const char *filename); +void PF_GetPlayerStats(const edict_t *pClient, int *ping, int *packet_loss); +NOXREF void QueryClientCvarValueCmd(void); +NOXREF void QueryClientCvarValueCmd2(void); +void QueryClientCvarValue(const edict_t *player, const char *cvarName); +void QueryClientCvarValue2(const edict_t *player, const char *cvarName, int requestID); +int hudCheckParm(char *parm, char **ppnext); +int EngCheckParm(const char *pchCmdLineToken, char **pchNextVal); + +#endif // PR_CMDS_H diff --git a/rehlds/engine/pr_dlls.h b/rehlds/engine/pr_dlls.h new file mode 100644 index 0000000..92227f1 --- /dev/null +++ b/rehlds/engine/pr_dlls.h @@ -0,0 +1,62 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef PR_DLLS_H +#define PR_DLLS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "eiface.h" + + +/* <8a763> ../engine/pr_dlls.h:42 */ +typedef struct functiontable_s +{ + uint32_t pFunction; + char *pFunctionName; +} functiontable_t; + +/* 572 */ +/* <8a793> ../engine/pr_dlls.h:48 */ +typedef struct extensiondll_s +{ + void *lDLLHandle; + functiontable_t *functionTable; + int functionCount; +} extensiondll_t; + +/* <8a7db> ../engine/pr_dlls.h:63 */ +typedef void(*ENTITYINIT)(struct entvars_s *); +/* <8a7f8> ../engine/pr_dlls.h:64 */ +typedef void(*DISPATCHFUNCTION)(struct entvars_s *, void *); +/* <8a81a> ../engine/pr_dlls.h:65 */ +typedef void(*FIELDIOFUNCTION)(SAVERESTOREDATA *, const char *, void *, TYPEDESCRIPTION *, int); + +#endif // PR_DLLS_H diff --git a/rehlds/engine/pr_edict.cpp b/rehlds/engine/pr_edict.cpp new file mode 100644 index 0000000..d45e469 --- /dev/null +++ b/rehlds/engine/pr_edict.cpp @@ -0,0 +1,647 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +/* <7f360> ../engine/pr_edict.c:37 */ +void ED_ClearEdict(edict_t *e) +{ + Q_memset(&e->v, 0, sizeof(e->v)); + e->free = FALSE; + ReleaseEntityDLLFields(e); + InitEntityDLLFields(e); +} + +/* <7f3cb> ../engine/pr_edict.c:57 */ +edict_t *ED_Alloc(void) +{ + int i; + edict_t *e; + + // Search for free entity + for (i = g_psvs.maxclients + 1; i < g_psv.num_edicts; i++) + { + e = &g_psv.edicts[i]; + if (e->free && (e->freetime <= 2.0 || g_psv.time - e->freetime >= 0.5)) + { + ED_ClearEdict(e); + return e; + } + } + + // Check if we are out of free edicts + if (i >= g_psv.max_edicts) + { + if (!g_psv.max_edicts) + { + Sys_Error(__FUNCTION__ ": no edicts yet"); + } + Sys_Error(__FUNCTION__ ": no free edicts"); + } + + // Use new one + ++g_psv.num_edicts; + e = &g_psv.edicts[i]; + + ED_ClearEdict(e); + return e; +} + +/* <7f310> ../engine/pr_edict.c:96 */ +void ED_Free(edict_t *ed) +{ + if (!ed->free) + { + SV_UnlinkEdict(ed); + FreeEntPrivateData(ed); + ed->serialnumber++; + ed->freetime = (float)g_psv.time; + ed->free = TRUE; + ed->v.flags = 0; + ed->v.model = 0; + + ed->v.takedamage = 0; + ed->v.modelindex = 0; + ed->v.colormap = 0; + ed->v.skin = 0; + ed->v.frame = 0; + ed->v.scale = 0; + ed->v.gravity = 0; + ed->v.nextthink = -1.0; + ed->v.solid = SOLID_NOT; + + ed->v.origin[0] = vec3_origin[0]; + ed->v.origin[1] = vec3_origin[1]; + ed->v.origin[2] = vec3_origin[2]; + ed->v.angles[0] = vec3_origin[0]; + ed->v.angles[1] = vec3_origin[1]; + ed->v.angles[2] = vec3_origin[2]; + } +} + +/* <7f4f6> ../engine/pr_edict.c:170 */ +NOXREF void ED_Count(void) +{ + NOXREFCHECK; + + int i; + edict_t *ent; + int active = 0, models = 0, solid = 0, step = 0; + + for (i = 0; i < g_psv.num_edicts; i++) + { + ent = &g_psv.edicts[i]; + if (!ent->free) + { + ++active; + models += (ent->v.model) ? 1 : 0; + solid += (ent->v.solid) ? 1 : 0; + step += (ent->v.movetype == MOVETYPE_STEP) ? 1 : 0; + } + } + + Con_Printf("num_edicts:%3i\n", g_psv.num_edicts); + Con_Printf("active :%3i\n", active); + Con_Printf("view :%3i\n", models); + Con_Printf("touch :%3i\n", solid); + Con_Printf("step :%3i\n", step); +} + +/* <7f568> ../engine/pr_edict.c:205 */ +char *ED_NewString(const char *string) +{ + char *new_s; + + //Engine string pooling +#ifdef REHLDS_FIXES + + //escaping is done inside Ed_StrPool_Alloc() + new_s = Ed_StrPool_Alloc(string); + +#else //REHLDS_FIXES + + int l = Q_strlen(string); + new_s = (char *)Hunk_Alloc(l + 1); + char* new_p = new_s; + + for (int i = 0; i < l; i++, new_p++) + { + if (string[i] == '\\') + { + if (string[i + 1] == 'n') + *new_p = '\n'; + else + *new_p = '\\'; + i++; + } + else + { + *new_p = string[i]; + } + } + *new_p = 0; + +#endif //REHLDS_FIXES + + return new_s; +} + +/* <7f5ee> ../engine/pr_edict.c:245 */ +char *ED_ParseEdict(char *data, edict_t *ent) +{ + qboolean init = FALSE; + char keyname[256]; + int n; + ENTITYINIT pEntityInit; + char *className; + KeyValueData kvd; + + if (ent != g_psv.edicts) + { + Q_memset(&ent->v, 0, sizeof(ent->v)); + } + + InitEntityDLLFields(ent); + + if (SuckOutClassname(data, ent)) + { + className = (char *)(pr_strings + ent->v.classname); + + pEntityInit = GetEntityInit(className); + if (pEntityInit) + { + pEntityInit(&ent->v); + init = TRUE; + } + else + { + pEntityInit = GetEntityInit("custom"); + if (pEntityInit) + { + pEntityInit(&ent->v); + kvd.szClassName = "custom"; + kvd.szKeyName = "customclass"; + kvd.szValue = className; + kvd.fHandled = FALSE; + gEntityInterface.pfnKeyValue(ent, &kvd); + init = TRUE; + } + else + { + Con_DPrintf("Can't init %s\n", className); + init = FALSE; + } + } + + while (1) + { + data = COM_Parse(data); + if (com_token[0] == '}') + { + break; + } + if (!data) + { + Host_Error(__FUNCTION__ ": EOF without closing brace"); + } + + Q_strncpy(keyname, com_token, ARRAYSIZE(keyname) - 1); + keyname[ARRAYSIZE(keyname) - 1] = 0; + // Remove tail spaces + for (n = Q_strlen(keyname) - 1; n >= 0 && keyname[n] == ' '; n--) + { + keyname[n] = 0; + } + + data = COM_Parse(data); + if (!data) + { + Host_Error(__FUNCTION__ ": EOF without closing brace"); + } + if (com_token[0] == '}') + { + Host_Error(__FUNCTION__ ": closing brace without data"); + } + + if (className != NULL && !Q_strcmp(className, com_token)) + { + continue; + } + + if (!Q_strcmp(keyname, "angle")) + { + float value = (float)Q_atof(com_token); + if (value >= 0.0) + { + Q_snprintf(com_token, COM_TOKEN_LEN, "%f %f %f", ent->v.angles[0], value, ent->v.angles[2]); + } + else if ((int)value == -1) + { + Q_snprintf(com_token, COM_TOKEN_LEN, "-90 0 0"); + } + else + { + Q_snprintf(com_token, COM_TOKEN_LEN, "90 0 0"); + } + + Q_strcpy(keyname, "angles"); + } + + kvd.szClassName = className; + kvd.szKeyName = keyname; + kvd.szValue = com_token; + kvd.fHandled = 0; + gEntityInterface.pfnKeyValue(ent, &kvd); + } + } + + if (!init) + { + ent->free = 1; + ent->serialnumber++; + } + return data; +} + +/* <7f6ee> ../engine/pr_edict.c:402 */ +void ED_LoadFromFile(char *data) +{ + edict_t *ent; + int inhibit; + + gGlobalVariables.time = (float)g_psv.time; + + ent = NULL; + inhibit = 0; + while (1) + { + data = COM_Parse(data); + if (!data) + { + break; + } + if (com_token[0] != '{') + { + Host_Error(__FUNCTION__ ": found %s when expecting {", com_token); + } + + if (ent) + { + ent = ED_Alloc(); + } + else + { + ent = g_psv.edicts; + ReleaseEntityDLLFields(g_psv.edicts); // TODO: May be better to call ED_ClearEdict here? + InitEntityDLLFields(ent); + } + + data = ED_ParseEdict(data, ent); + if (ent->free) + { + continue; + } + + if (deathmatch.value != 0.0 && (ent->v.spawnflags & SF_NOTINDEATHMATCH)) + { + ED_Free(ent); + ++inhibit; + } + else + { + if (ent->v.classname) + { + if (gEntityInterface.pfnSpawn(ent) < 0 || (ent->v.flags & FL_KILLME)) + { + ED_Free(ent); + } + } + else + { + Con_Printf("No classname for:\n"); + ED_Free(ent); + } + } + } + Con_DPrintf("%i entities inhibited\n", inhibit); +} + +/* <7f7fa> ../engine/pr_edict.c:484 */ +NOXREF void PR_Init(void) +{ + NOXREFCHECK; +} + +/* <7f80f> ../engine/pr_edict.c:495 */ +edict_t *EDICT_NUM(int n) +{ + if (n < 0 || n >= g_psv.max_edicts) + { + Sys_Error(__FUNCTION__ ": bad number %i", n); + } + return &g_psv.edicts[n]; +} + +/* <7f84b> ../engine/pr_edict.c:511 */ +int NUM_FOR_EDICT(const edict_t *e) +{ + int b; + b = e - g_psv.edicts; + + if (b < 0 || b >= g_psv.num_edicts) + { + Sys_Error(__FUNCTION__ ": bad pointer"); + } + + return b; +} + +/* <7f280> ../engine/pr_edict.c:539 */ +bool SuckOutClassname(char *szInputStream, edict_t *pEdict) +{ + char szKeyName[256]; + KeyValueData kvd; + + // key + szInputStream = COM_Parse(szInputStream); + while (szInputStream && com_token[0] != '}') + { + Q_strncpy(szKeyName, com_token, ARRAYSIZE(szKeyName) - 1); + szKeyName[ARRAYSIZE(szKeyName) - 1] = 0; + + // value + szInputStream = COM_Parse(szInputStream); + + if (!Q_strcmp(szKeyName, "classname")) + { + kvd.szClassName = NULL; + kvd.szKeyName = szKeyName; + kvd.szValue = com_token; + kvd.fHandled = FALSE; + + gEntityInterface.pfnKeyValue(pEdict, &kvd); + + if (kvd.fHandled == FALSE) + { + Host_Error(__FUNCTION__ ": parse error"); + } + + return true; + } + + if (!szInputStream) + { + break; + } + + // next key + szInputStream = COM_Parse(szInputStream); + } + + // classname not found + return false; +} + +/* <7f89a> ../engine/pr_edict.c:579 */ +void ReleaseEntityDLLFields(edict_t *pEdict) +{ + FreeEntPrivateData(pEdict); +} + +/* <7f264> ../engine/pr_edict.c:584 */ +void InitEntityDLLFields(edict_t *pEdict) +{ + pEdict->v.pContainingEntity = pEdict; +} + +/* <7f8ee> ../engine/pr_edict.c:594 */ +void *PvAllocEntPrivateData(edict_t *pEdict, int32_t cb) +{ + FreeEntPrivateData(pEdict); + + if (cb <= 0) + { + return NULL; + } + + pEdict->pvPrivateData = Mem_Calloc(1, cb); + + FR_AllocEntPrivateData(pEdict->pvPrivateData); + + return pEdict->pvPrivateData; +} + +/* <7f943> ../engine/pr_edict.c:607 */ +void *PvEntPrivateData(edict_t *pEdict) +{ + if (!pEdict) + { + return NULL; + } + + return pEdict->pvPrivateData; +} + +/* <7f2f4> ../engine/pr_edict.c:618 */ +void FreeEntPrivateData(edict_t *pEdict) +{ + if (pEdict->pvPrivateData) + { + if (gNewDLLFunctions.pfnOnFreeEntPrivateData) + { + gNewDLLFunctions.pfnOnFreeEntPrivateData(pEdict); + } + + FR_FreeEntPrivateData(pEdict->pvPrivateData); + + Mem_Free(pEdict->pvPrivateData); + pEdict->pvPrivateData = 0; + } +} + +/* <7f98e> ../engine/pr_edict.c:647 */ +void FreeAllEntPrivateData(void) +{ + for (int i = 0; i < g_psv.num_edicts; i++) + { + FreeEntPrivateData(&g_psv.edicts[i]); + } +} + +/* <7f9d0> ../engine/pr_edict.c:660 */ +edict_t *PEntityOfEntOffset(int iEntOffset) +{ + return (edict_t *)((char *)g_psv.edicts + iEntOffset); +} + +/* <7f9fd> ../engine/pr_edict.c:665 */ +int EntOffsetOfPEntity(const edict_t *pEdict) +{ + return (char *)pEdict - (char *)g_psv.edicts; +} + +/* <7fa2a> ../engine/pr_edict.c:670 */ +int IndexOfEdict(const edict_t *pEdict) +{ + int index = 0; + if (pEdict) + { + index = pEdict - g_psv.edicts; +#ifdef REHLDS_FIXES + if (index < 0 || index >= g_psv.max_edicts) //max_edicts is not valid entity index +#else // REHLDS_FIXES + if (index < 0 || index > g_psv.max_edicts) +#endif // REHLDS_FIXES + { + Sys_Error(__FUNCTION__ ": bad entity"); + } + } + return index; +} + +/* <7fa68> ../engine/pr_edict.c:691 */ +edict_t *PEntityOfEntIndex(int iEntIndex) +{ + if (iEntIndex < 0 || iEntIndex >= g_psv.max_edicts) + { + return NULL; + } + + edict_t *pEdict = EDICT_NUM(iEntIndex); + +#ifdef REHLDS_FIXES + if (pEdict && (pEdict->free || (iEntIndex > g_psvs.maxclients && !pEdict->pvPrivateData))) //Simplified confition + { + return NULL; + } +#else // REHLDS_FIXES + if ((!pEdict || pEdict->free || !pEdict->pvPrivateData) && (iEntIndex >= g_psvs.maxclients || pEdict->free)) + { + if (iEntIndex >= g_psvs.maxclients || pEdict->free) + { + pEdict = NULL; + } + } +#endif // REHLDS_FIXES + + return pEdict; +} + +/* <7fac3> ../engine/pr_edict.c:711 */ +const char *SzFromIndex(int iString) +{ + return (const char *)(pr_strings + iString); +} + +/* <7faf0> ../engine/pr_edict.c:721 */ +entvars_t *GetVarsOfEnt(edict_t *pEdict) +{ + return &pEdict->v; +} + +/* <7fb23> ../engine/pr_edict.c:731 */ +edict_t *FindEntityByVars(entvars_t *pvars) +{ + for (int i = 0; i < g_psv.num_edicts; i++) + { + edict_t *pEdict = &g_psv.edicts[i]; + if (&pEdict->v == pvars) + { + return pEdict; + } + } + return NULL; +} + +/* <7fb75> ../engine/pr_edict.c:747 */ +float CVarGetFloat(const char *szVarName) +{ + return Cvar_VariableValue(szVarName); +} + +/* <7fba2> ../engine/pr_edict.c:753 */ +const char *CVarGetString(const char *szVarName) +{ + return Cvar_VariableString(szVarName); +} + +/* <7fbcf> ../engine/pr_edict.c:759 */ +cvar_t *CVarGetPointer(const char *szVarName) +{ + return Cvar_FindVar(szVarName); +} + +/* <7fbfc> ../engine/pr_edict.c:765 */ +void CVarSetFloat(const char *szVarName, float flValue) +{ + Cvar_SetValue(szVarName, flValue); +} + +/* <7fc34> ../engine/pr_edict.c:771 */ +void CVarSetString(const char *szVarName, const char *szValue) +{ + Cvar_Set(szVarName, szValue); +} + +/* <7fc6c> ../engine/pr_edict.c:777 */ +void CVarRegister(cvar_t *pCvar) +{ + if (pCvar) + { + pCvar->flags |= FCVAR_EXTDLL; + Cvar_RegisterVariable(pCvar); + } +} + +/* <7fc95> ../engine/pr_edict.c:794 */ +int AllocEngineString(const char *szValue) +{ + return ED_NewString(szValue) - pr_strings; +} + +/* <7fd06> ../engine/pr_edict.c:802 */ +void SaveSpawnParms(edict_t *pEdict) +{ + int eoffset = NUM_FOR_EDICT(pEdict); + if (eoffset < 1 || eoffset > g_psvs.maxclients) + { + Host_Error("Entity is not a client"); + } + // Nothing more for this function even on client-side +} + +/* <7fd78> ../engine/pr_edict.c:815 */ +void *GetModelPtr(edict_t *pEdict) +{ + if (!pEdict) + { + return NULL; + } + return Mod_Extradata(g_psv.models[pEdict->v.modelindex]); +} diff --git a/rehlds/engine/pr_edict.h b/rehlds/engine/pr_edict.h new file mode 100644 index 0000000..d3703bb --- /dev/null +++ b/rehlds/engine/pr_edict.h @@ -0,0 +1,75 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef PR_EDICT_H +#define PR_EDICT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "cvar.h" +#include "pm_defs.h" +#include "progdefs.h" + + +void ED_ClearEdict(edict_t *e); +edict_t *ED_Alloc(void); +void ED_Free(edict_t *ed); +NOXREF void ED_Count(void); +char *ED_NewString(const char *string); +char *ED_ParseEdict(char *data, edict_t *ent); +void ED_LoadFromFile(char *data); +NOXREF void PR_Init(void); +edict_t *EDICT_NUM(int n); +int NUM_FOR_EDICT(const edict_t *e); +bool SuckOutClassname(char *szInputStream, edict_t *pEdict); +void ReleaseEntityDLLFields(edict_t *pEdict); +void InitEntityDLLFields(edict_t *pEdict); +void *PvAllocEntPrivateData(edict_t *pEdict, int32_t cb); +void *PvEntPrivateData(edict_t *pEdict); +void FreeEntPrivateData(edict_t *pEdict); +void FreeAllEntPrivateData(void); +edict_t *PEntityOfEntOffset(int iEntOffset); +int EntOffsetOfPEntity(const edict_t *pEdict); +int IndexOfEdict(const edict_t *pEdict); +edict_t *PEntityOfEntIndex(int iEntIndex); +const char *SzFromIndex(int iString); +entvars_t *GetVarsOfEnt(edict_t *pEdict); +edict_t *FindEntityByVars(entvars_t *pvars); +float CVarGetFloat(const char *szVarName); +const char *CVarGetString(const char *szVarName); +cvar_t *CVarGetPointer(const char *szVarName); +void CVarSetFloat(const char *szVarName, float flValue); +void CVarSetString(const char *szVarName, const char *szValue); +void CVarRegister(cvar_t *pCvar); +int AllocEngineString(const char *szValue); +void SaveSpawnParms(edict_t *pEdict); +void *GetModelPtr(edict_t *pEdict); + +#endif // PR_EDICT_H diff --git a/rehlds/engine/r_studio.cpp b/rehlds/engine/r_studio.cpp new file mode 100644 index 0000000..8cf7a96 --- /dev/null +++ b/rehlds/engine/r_studio.cpp @@ -0,0 +1,1171 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +/* <82eb2> ../engine/r_studio.c:108 */ +typedef struct r_studiocache_s +{ + float frame; + int sequence; + vec3_t angles; + vec3_t origin; + vec3_t size; + unsigned char controller[4]; + unsigned char blending[2]; + model_t *pModel; + int nStartHull; + int nStartPlane; + int numhulls; +} r_studiocache_t; + + +studiohdr_t *pstudiohdr; + +//auxvert_t auxverts[2048]; +//vec_t lightvalues[2048][3]; +int cache_hull_hitgroup[128]; +hull_t cache_hull[128]; +mplane_t cache_planes[768]; + +r_studiocache_t rgStudioCache[STUDIO_CACHE_SIZE]; + +int nCurrentHull; +int nCurrentPlane; +int r_cachecurrent; + +int studio_hull_hitgroup[STUDIO_NUM_HULLS]; +hull_t studio_hull[STUDIO_NUM_HULLS]; +dclipnode_t studio_clipnodes[6]; +mplane_t studio_planes[6 * STUDIO_NUM_HULLS]; + +float bonetransform[STUDIO_NUM_HULLS][3][4]; +float rotationmatrix[3][4]; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t r_cachestudio = { "r_cachestudio", "1", 0, 0.0f, NULL }; +sv_blending_interface_t svBlending = { 1, SV_StudioSetupBones }; +sv_blending_interface_t *g_pSvBlendingAPI = &svBlending; +server_studio_api_t server_studio_api = { Mem_Calloc, Cache_Check, COM_LoadCacheFile, Mod_Extradata }; + +#else //HOOK_ENGINE + +cvar_t r_cachestudio; +sv_blending_interface_t svBlending; +sv_blending_interface_t *g_pSvBlendingAPI; +server_studio_api_t server_studio_api; + + +#endif //HOOK_ENGINE + +/* <83117> ../engine/r_studio.c:190 */ +void SV_InitStudioHull(void) +{ + if (studio_hull[0].planes == NULL) + { + for (int i = 0; i < 6; i++) + { + int side = i & 1; + studio_clipnodes[i].planenum = i; + studio_clipnodes[i].children[side] = -1; + studio_clipnodes[i].children[side ^ 1] = (i < 5) ? i + 1 : -2; + } + + for (int i = 0; i < STUDIO_NUM_HULLS; i++) + { + studio_hull[i].planes = &studio_planes[i * 6]; + studio_hull[i].clipnodes = &studio_clipnodes[0]; + studio_hull[i].firstclipnode = 0; + studio_hull[i].lastclipnode = 5; + } + } +} + +/* <83160> ../engine/r_studio.c:227 */ +r_studiocache_t *R_CheckStudioCache(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const vec_t *size, const unsigned char *controller, const unsigned char *blending) +{ + for (int i = 0; i < STUDIO_CACHE_SIZE; i++) + { + r_studiocache_t *pCached = &rgStudioCache[(r_cachecurrent - i) & 0xF]; + if (pCached->pModel != pModel) continue; + if (pCached->frame != frame) continue; + if (pCached->sequence != sequence) continue; + if (!VectorCompare(pCached->angles, angles)) continue; + if (!VectorCompare(pCached->origin, origin)) continue; + if (!VectorCompare(pCached->size, size)) continue; + if (Q_memcmp(pCached->controller, controller, 4)) continue; + if (Q_memcmp(pCached->blending, blending, 2)) continue; + + return pCached; + } + + return NULL; +} + +/* <83215> ../engine/r_studio.c:275 */ +NOXREF void R_AddToStudioCache(float frame, int sequence, const vec_t *angles, const vec_t *origin, const vec_t *size, const unsigned char *controller, const unsigned char *pblending, model_t *pModel, hull_t *pHulls, int numhulls) +{ + r_studiocache_t *p; + if (numhulls + nCurrentHull >= 128) + R_FlushStudioCache(); + + r_cachecurrent++; + + p = &rgStudioCache[r_cachecurrent & 0xF]; + + p->frame = frame; + p->sequence = sequence; + + p->angles[0] = angles[0]; + p->angles[1] = angles[1]; + p->angles[2] = angles[2]; + + p->origin[0] = origin[0]; + p->origin[1] = origin[1]; + p->origin[2] = origin[2]; + + p->size[0] = size[0]; + p->size[1] = size[1]; + p->size[2] = size[2]; + + Q_memcpy(p->controller, controller, sizeof(p->controller)); + Q_memcpy(p->blending, pblending, sizeof(p->blending)); + + p->pModel = pModel; + p->nStartPlane = nCurrentPlane; + p->nStartHull = nCurrentHull; + + Q_memcpy(&cache_hull[nCurrentHull], pHulls, sizeof(hull_t) * numhulls); + Q_memcpy(&cache_planes[nCurrentPlane], studio_planes,sizeof(mplane_t) * 6 * numhulls); + Q_memcpy(&cache_hull_hitgroup[nCurrentHull], studio_hull_hitgroup, sizeof(int *) * numhulls); + + p->numhulls = numhulls; + + nCurrentHull += numhulls; + nCurrentPlane += 6 * numhulls; +} + +/* <832a5> ../engine/r_studio.c:317 */ +void AngleQuaternion(vec_t *angles, vec_t *quaternion) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + // FIXME: rescale the inputs to 1/2 angle + angle = angles[2] * 0.5f; + sy = sin(angle); + cy = cos(angle); + angle = angles[1] * 0.5f; + sp = sin(angle); + cp = cos(angle); + angle = angles[0] * 0.5f; + sr = sin(angle); + cr = cos(angle); + + quaternion[0] = sr*cp*cy - cr*sp*sy; // X + quaternion[1] = cr*sp*cy + sr*cp*sy; // Y + quaternion[2] = cr*cp*sy - sr*sp*cy; // Z + quaternion[3] = cr*cp*cy + sr*sp*sy; // W +} + +/* <83344> ../engine/r_studio.c:340 */ +void QuaternionSlerp(vec_t *p, vec_t *q, float t, vec_t *qt) +{ + int i; + float omega, cosom, sinom, sclp, sclq; + + // decide if one of the quaternions is backwards + float a = 0; + float b = 0; + for (i = 0; i < 4; i++) + { + a += (p[i] - q[i])*(p[i] - q[i]); + b += (p[i] + q[i])*(p[i] + q[i]); + } + if (a > b) + { + for (i = 0; i < 4; i++) + { + q[i] = -q[i]; + } + } + + cosom = p[0] * q[0] + p[1] * q[1] + p[2] * q[2] + p[3] * q[3]; + + if ((1.0 + cosom) > 0.00000001) + { + if ((1.0 - cosom) > 0.00000001) + { + omega = acos(cosom); + sinom = sin(omega); + sclp = (float)(sin((1.0 - t)*omega) / sinom); + sclq = (float)(sin(t*omega) / sinom); + } + else + { + sclp = 1.0f - t; + sclq = t; + } + for (i = 0; i < 4; i++) + { + qt[i] = sclp * p[i] + sclq * q[i]; + } + } + else + { + qt[0] = -p[1]; + qt[1] = p[0]; + qt[2] = -p[3]; + qt[3] = p[2]; + sclp = (float)sin((1.0 - t) * 0.5 * M_PI); + sclq = (float)sin(t * 0.5 * M_PI); + for (i = 0; i < 3; i++) + { + qt[i] = sclp * p[i] + sclq * qt[i]; + } + } +} + +/* <833be> ../engine/r_studio.c:387 */ +void QuaternionMatrix(vec_t *quaternion, float matrix[3][4]) +{ + matrix[0][0] = 1.0f - 2.0f * quaternion[1] * quaternion[1] - 2.0f * quaternion[2] * quaternion[2]; + matrix[1][0] = 2.0f * quaternion[0] * quaternion[1] + 2.0f * quaternion[3] * quaternion[2]; + matrix[2][0] = 2.0f * quaternion[0] * quaternion[2] - 2.0f * quaternion[3] * quaternion[1]; + + matrix[0][1] = 2.0f * quaternion[0] * quaternion[1] - 2.0f * quaternion[3] * quaternion[2]; + matrix[1][1] = 1.0f - 2.0f * quaternion[0] * quaternion[0] - 2.0f * quaternion[2] * quaternion[2]; + matrix[2][1] = 2.0f * quaternion[1] * quaternion[2] + 2.0f * quaternion[3] * quaternion[0]; + + matrix[0][2] = 2.0f * quaternion[0] * quaternion[2] + 2.0f * quaternion[3] * quaternion[1]; + matrix[1][2] = 2.0f * quaternion[1] * quaternion[2] - 2.0f * quaternion[3] * quaternion[0]; + matrix[2][2] = 1.0f - 2.0f * quaternion[0] * quaternion[0] - 2.0f * quaternion[1] * quaternion[1]; +} + +/* <8340d> ../engine/r_studio.c:436 */ +void R_StudioCalcBoneAdj(float dadt, float *adj, const unsigned char *pcontroller1, const unsigned char *pcontroller2, unsigned char mouthopen) +{ + int i, j; + float value; + mstudiobonecontroller_t *pbonecontroller; + pbonecontroller = (mstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex); + + for (j = 0; j < pstudiohdr->numbonecontrollers; j++) + { + i = pbonecontroller[j].index; + if (i <= 3) + { + // check for 360% wrapping + if (pbonecontroller[j].type & STUDIO_RLOOP) + { + if (abs(pcontroller1[i] - pcontroller2[i]) > 128) + { + int a, b; + a = (pcontroller1[j] + 128) % 256; + b = (pcontroller2[j] + 128) % 256; + value = (float)(((a * dadt) + (b * (1 - dadt)) - 128) * (360.0 / 256.0) + pbonecontroller[j].start); + } + else + value = (float)((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt)) * (360.0 / 256.0) + pbonecontroller[j].start); + } + else + { + value = (float)((pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0); + if (value < 0.0) + value = 0.0f; + if (value > 1.0) + value = 1.0f; + value = (float)((1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end); + } + // Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); + } + else + { + value = (float)(mouthopen / 64.0); + if (value > 1.0) + value = 1.0f; + value = (float)((1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end); + // Con_DPrintf("%d %f\n", mouthopen, value ); + } + switch (pbonecontroller[j].type & STUDIO_TYPES) + { + case STUDIO_XR: + case STUDIO_YR: + case STUDIO_ZR: + adj[j] = (float)(value * (M_PI / 180.0)); + break; + case STUDIO_X: + case STUDIO_Y: + case STUDIO_Z: + adj[j] = value; + break; + } + } +} + +/* <83487> ../engine/r_studio.c:497 */ +void R_StudioCalcBoneQuaterion(int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q) +{ + int j, k; + vec4_t q1, q2; + vec3_t angle1, angle2; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + if (panim->offset[j + 3] == 0) + { + angle2[j] = angle1[j] = pbone->value[j + 3]; // default; + } + else + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j + 3]); + k = frame; + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + } + // Bah, missing blend! + if (panimvalue->num.valid > k) + { + angle1[j] = panimvalue[k + 1].value; + + if (panimvalue->num.valid > k + 1) + { + angle2[j] = panimvalue[k + 2].value; + } + else + { + if (panimvalue->num.total > k + 1) + angle2[j] = angle1[j]; + else + angle2[j] = panimvalue[panimvalue->num.valid + 2].value; + } + } + else + { + angle1[j] = panimvalue[panimvalue->num.valid].value; + if (panimvalue->num.total > k + 1) + { + angle2[j] = angle1[j]; + } + else + { + angle2[j] = panimvalue[panimvalue->num.valid + 2].value; + } + } + angle1[j] = pbone->value[j + 3] + angle1[j] * pbone->scale[j + 3]; + angle2[j] = pbone->value[j + 3] + angle2[j] * pbone->scale[j + 3]; + } + + if (pbone->bonecontroller[j + 3] != -1) + { + angle1[j] += adj[pbone->bonecontroller[j + 3]]; + angle2[j] += adj[pbone->bonecontroller[j + 3]]; + } + } + + if (!VectorCompare(angle1, angle2)) + { + AngleQuaternion(angle1, q1); + AngleQuaternion(angle2, q2); + QuaternionSlerp(q1, q2, s, q); + } + else + { + AngleQuaternion(angle1, q); + } +} + +/* <83572> ../engine/r_studio.c:577 */ +void R_StudioCalcBonePosition(int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos) +{ + int j, k; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + pos[j] = pbone->value[j]; // default; + if (panim->offset[j] != 0) + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + + k = frame; + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + } + // if we're inside the span + if (panimvalue->num.valid > k) + { + // and there's more data in the span + if (panimvalue->num.valid > k + 1) + { + pos[j] += (panimvalue[k + 1].value * (1.0f - s) + s * panimvalue[k + 2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[k + 1].value * pbone->scale[j]; + } + } + else + { + // are we at the end of the repeating values section and there's another section with data? + if (panimvalue->num.total <= k + 1) + { + pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0f - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; + } + } + } + if (pbone->bonecontroller[j] != -1) + { + pos[j] += adj[pbone->bonecontroller[j]]; + } + } +} + +/* <830a3> ../engine/r_studio.c:639 */ +void R_StudioSlerpBones(vec4_t *q1, vec3_t *pos1, vec4_t *q2, vec3_t *pos2, float s) +{ + int i; + vec4_t q3; + float s1; + + if (s < 0) s = 0; + else if (s > 1.0) s = 1.0; + + s1 = 1.0f - s; + + for (i = 0; i < pstudiohdr->numbones; i++) + { + QuaternionSlerp(q1[i], q2[i], s, q3); + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; + } +} + +/* <83669> ../engine/r_studio.c:663 */ +mstudioanim_t *R_GetAnim(model_t *psubmodel, mstudioseqdesc_t *pseqdesc) +{ + mstudioseqgroup_t *pseqgroup; + cache_user_t *paSequences; + + pseqgroup = (mstudioseqgroup_t *)((char *)pstudiohdr + pstudiohdr->seqgroupindex); + pseqgroup += pseqdesc->seqgroup; + if (!pseqdesc->seqgroup) + return (mstudioanim_t *)((char *)pstudiohdr + pseqdesc->animindex); + + paSequences = (cache_user_t *)psubmodel->submodels; + if (!paSequences) + { + paSequences = (cache_user_t *)Mem_Calloc(16, 4); + psubmodel->submodels = (dmodel_t *)paSequences; + } + if (!Cache_Check(&paSequences[pseqdesc->seqgroup])) + { + Con_DPrintf("loading %s\n", pseqgroup->name); + COM_LoadCacheFile(pseqgroup->name, &paSequences[pseqdesc->seqgroup]); + } + + return (mstudioanim_t *)((char *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); +} + +/* <836d8> ../engine/r_studio.c:696 */ +void SV_StudioSetupBones(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const unsigned char *pcontroller, const unsigned char *pblending, int iBone, const edict_t *edict) +{ + static vec4_t q1[128]; + static vec3_t pos1[128]; + static vec4_t q2[128]; + static vec3_t pos2[128]; + + int chainlength; + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + int chain[128]; + float bonematrix[3][4]; + mstudioanim_t *panim; + float f; + float adj[8]; + float s; + + chainlength = 0; + if (sequence < 0 || sequence >= pstudiohdr->numseq) + { + Con_DPrintf("SV_StudioSetupBones: sequence %i/%i out of range for model %s\n", sequence, pstudiohdr->numseq, pstudiohdr->name); + sequence = 0; + } + pbones = (mstudiobone_t *)((char *)pstudiohdr + pstudiohdr->boneindex); + pseqdesc = (mstudioseqdesc_t *)((char *)pstudiohdr + pstudiohdr->seqindex); + pseqdesc += sequence; + panim = R_GetAnim(pModel, pseqdesc); + + if (iBone < -1 || iBone >= pstudiohdr->numbones) + iBone = 0; + + if (iBone != -1) + { + do + { + chain[chainlength++] = iBone; + iBone = pbones[iBone].parent; + } while (iBone != -1); + } + else + { + chainlength = pstudiohdr->numbones; + for (int i = 0; i < pstudiohdr->numbones; i++) + { + chain[pstudiohdr->numbones - 1 - i] = i; + } + } + + f = (pseqdesc->numframes > 1) ? (pseqdesc->numframes - 1) * frame / 256.0f : 0.0f; + + R_StudioCalcBoneAdj(0.0, adj, pcontroller, pcontroller, 0); + s = f - (float)(int)f; + + for (int i = chainlength - 1; i >= 0; i--) + { + int bone = chain[i]; + R_StudioCalcBoneQuaterion((int)f, s, &pbones[bone], &panim[bone], adj, q1[bone]); + R_StudioCalcBonePosition((int)f, s, &pbones[bone], &panim[bone], adj, pos1[bone]); + + } + + if (pseqdesc->numblends > 1) + { + panim = R_GetAnim(pModel, pseqdesc); + panim += pstudiohdr->numbones; + + for (int i = chainlength - 1; i >= 0; i--) + { + int bone = chain[i]; + R_StudioCalcBoneQuaterion((int)f, s, &pbones[bone], &panim[bone], adj, q2[bone]); + R_StudioCalcBonePosition((int)f, s, &pbones[bone], &panim[bone], adj, pos2[bone]); + } + + R_StudioSlerpBones(q1, pos1, q2, pos2, *pblending / 255.0f); + } + + AngleMatrix(angles, rotationmatrix); + rotationmatrix[0][3] = origin[0]; + rotationmatrix[1][3] = origin[1]; + rotationmatrix[2][3] = origin[2]; + for (int i = chainlength - 1; i >= 0; i--) + { + int bone = chain[i]; + int parent = pbones[bone].parent; + QuaternionMatrix(q1[bone], bonematrix); + + bonematrix[0][3] = pos1[bone][0]; + bonematrix[1][3] = pos1[bone][1]; + bonematrix[2][3] = pos1[bone][2]; + R_ConcatTransforms((parent == -1) ? rotationmatrix : bonetransform[parent], bonematrix, bonetransform[bone]); + } +} + +/* <839e7> ../engine/r_studio.c:816 */ +void SV_SetStudioHullPlane(mplane_t *pplane, int iBone, int k, float dist) +{ + pplane->type = 5; + + pplane->normal[0] = bonetransform[iBone][0][k]; + pplane->normal[1] = bonetransform[iBone][1][k]; + pplane->normal[2] = bonetransform[iBone][2][k]; + + pplane->dist = pplane->normal[2] * bonetransform[iBone][2][3] + + pplane->normal[1] * bonetransform[iBone][1][3] + + pplane->normal[0] * bonetransform[iBone][0][3] + + dist; +} + +/* <83a1c> ../engine/r_studio.c:844 */ +hull_t *R_StudioHull(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const vec_t *size, const unsigned char *pcontroller, const unsigned char *pblending, int *pNumHulls, const edict_t *pEdict, int bSkipShield) +{ + SV_InitStudioHull(); + + if (r_cachestudio.value != 0) + { +#ifdef SWDS + Sys_Error(__FUNCTION__ ": Studio state caching is not used on server"); +#endif + // TODO: Reverse for client-side + } + + pstudiohdr = (studiohdr_t*)Mod_Extradata(pModel); + + vec_t angles2[3] = { -angles[0], angles[1], angles[2] }; + g_pSvBlendingAPI->SV_StudioSetupBones(pModel, frame, sequence, angles2, origin, pcontroller, pblending, -1, pEdict); + + mstudiobbox_t* pbbox = (mstudiobbox_t *)((char *)pstudiohdr + pstudiohdr->hitboxindex); + for (int i = 0; i < pstudiohdr->numhitboxes; i++) + { + if (bSkipShield && i == 21) continue; + + studio_hull_hitgroup[i] = pbbox[i].group; + + for (int j = 0; j < 3; j++) + { + mplane_t* plane0 = &studio_planes[i * 6 + j * 2 + 0]; + mplane_t* plane1 = &studio_planes[i * 6 + j * 2 + 1]; + SV_SetStudioHullPlane(plane0, pbbox[i].bone, j, pbbox[i].bbmax[j]); + SV_SetStudioHullPlane(plane1, pbbox[i].bone, j, pbbox[i].bbmin[j]); + + plane0->dist += fabs(plane0->normal[0] * size[0]) + fabs(plane0->normal[1] * size[1]) + fabs(plane0->normal[2] * size[2]); + plane1->dist -= fabs(plane1->normal[0] * size[0]) + fabs(plane1->normal[1] * size[1]) + fabs(plane1->normal[2] * size[2]); + } + } + + *pNumHulls = (bSkipShield == 1) ? pstudiohdr->numhitboxes - 1 : pstudiohdr->numhitboxes; + if (r_cachestudio.value != 0) + { +#ifdef SWDS + Sys_Error(__FUNCTION__ ": Studio state caching is not used on server"); +#endif + // TODO: Reverse for client-side + // R_AddToStudioCache(float frame, + // int sequence, + // const vec_t *angles, + // const vec_t *origin, + // const vec_t *size, + // const unsigned char *controller, + // const unsigned char *pblending, + // model_t *pModel, + // hull_t *pHulls, + // int numhulls); /* size=0, low_pc=0 */ // 917 + } + + return &studio_hull[0]; +} + +/* <83d4f> ../engine/r_studio.c:924 */ +int SV_HitgroupForStudioHull(int index) +{ + return studio_hull_hitgroup[index]; +} + +/* <83d7c> ../engine/r_studio.c:935 */ +NOXREF void R_InitStudioCache(void) +{ + Q_memset(rgStudioCache, 0, sizeof(rgStudioCache)); + + r_cachecurrent = 0; + nCurrentHull = 0; + nCurrentPlane = 0; +} + +/* <83d8d> ../engine/r_studio.c:950 */ +NOXREF void R_FlushStudioCache(void) +{ + R_InitStudioCache(); +} + +/* <83db3> ../engine/r_studio.c:957 */ +int R_StudioBodyVariations(model_t *model) +{ + if (model->type != mod_studio) + return 0; + + studiohdr_t *shdr = (studiohdr_t *)Mod_Extradata(model); + if (!shdr) + return 0; + + int count = 1; + mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)((char *)shdr + shdr->bodypartindex); + for (int i = 0; i < shdr->numbodyparts; i++, pbodypart++) + { + count *= pbodypart->nummodels; + } + + return count; +} + +/* <83e4f> ../engine/r_studio.c:982 */ +void R_StudioPlayerBlend(mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch) +{ + *pBlend = (int)(*pPitch * 3.0); + if (*pBlend < pseqdesc->blendstart[0]) + { + *pBlend = 0; + *pPitch -= (float)(pseqdesc->blendstart[0] / 3.0); + } + else if (*pBlend <= pseqdesc->blendend[0]) + { + float blendDiff = pseqdesc->blendend[0] - pseqdesc->blendstart[0]; + if (blendDiff >= 0.1) + { + *pBlend = (int)((*pBlend - pseqdesc->blendstart[0]) * 255.0 / blendDiff); + *pPitch = 0; + } + else + { + *pBlend = 127; + *pPitch = 0; + } + } + else + { + *pBlend = 255; + *pPitch = (float)(*pPitch - pseqdesc->blendend[0] / 3.0); + } +} + +/* <83e97> ../engine/r_studio.c:1015 */ +hull_t *SV_HullForStudioModel(const edict_t *pEdict, const vec_t *mins, const vec_t *maxs, vec_t *offset, int *pNumHulls) +{ + qboolean useComplexHull = FALSE; + vec3_t size; + float factor = 0.5; + int bSkipShield = 0; + size[0] = maxs[0] - mins[0]; + size[1] = maxs[1] - mins[1]; + size[2] = maxs[2] - mins[2]; + if (VectorCompare(vec3_origin, size)) + { + if (!(gGlobalVariables.trace_flags & FTRACE_SIMPLEBOX)) + { + useComplexHull = TRUE; + if (pEdict->v.flags & FL_CLIENT) + { + if (sv_clienttrace.value == 0.0) + { + useComplexHull = FALSE; + } + else + { + size[2] = 1.0f; + size[1] = 1.0f; + size[0] = 1.0f; + factor = sv_clienttrace.value * 0.5f; + } + } + } + } + if (pEdict->v.gamestate == 1 && (g_bIsTerrorStrike == 1 || g_bIsCStrike == 1 || g_bIsCZero == 1)) + bSkipShield = 1; + + if ((g_psv.models[pEdict->v.modelindex]->flags & FL_ONGROUND) || useComplexHull == TRUE) + { + VectorScale(size, factor, size); + offset[0] = 0; + offset[1] = 0; + offset[2] = 0; + if (pEdict->v.flags & FL_CLIENT) + { + pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]); + + mstudioseqdesc_t* pseqdesc = (mstudioseqdesc_t *)((char*)pstudiohdr + pstudiohdr->seqindex); + pseqdesc += pEdict->v.sequence; + + vec3_t angles; + angles[0] = pEdict->v.angles[0]; + angles[1] = pEdict->v.angles[1]; + angles[2] = pEdict->v.angles[2]; + + int iBlend; + R_StudioPlayerBlend(pseqdesc, &iBlend, angles); + + unsigned char blending = (unsigned char)iBlend; + unsigned char controller[4] = { 0x7F, 0x7F, 0x7F, 0x7F }; + return R_StudioHull( + g_psv.models[pEdict->v.modelindex], + pEdict->v.frame, + pEdict->v.sequence, + angles, + pEdict->v.origin, + size, + controller, + &blending, + pNumHulls, + pEdict, + bSkipShield); + } + else + { + return R_StudioHull( + g_psv.models[pEdict->v.modelindex], + pEdict->v.frame, + pEdict->v.sequence, + pEdict->v.angles, + pEdict->v.origin, + size, + pEdict->v.controller, + pEdict->v.blending, + pNumHulls, + pEdict, + bSkipShield); + } + } + else + { + *pNumHulls = 1; + return SV_HullForEntity((edict_t *)pEdict, mins, maxs, offset); + } +} + +/* <83f98> ../engine/r_studio.c:1232 */ +qboolean DoesSphereIntersect(float *vSphereCenter, float fSphereRadiusSquared, float *vLinePt, float *vLineDir) +{ + vec3_t P; + float a; + float b; + float c; + float insideSqr; + + + P[0] = *vLinePt - *vSphereCenter; + P[1] = vLinePt[1] - vSphereCenter[1]; + P[2] = vLinePt[2] - vSphereCenter[2]; + a = vLineDir[0] * vLineDir[0] + vLineDir[1] * vLineDir[1] + vLineDir[2] * vLineDir[2]; + b = P[2] * vLineDir[2] + P[1] * vLineDir[1] + P[0] * vLineDir[0]; + b *= 2; + c = P[2] * P[2] + P[1] * P[1] + P[0] * P[0] - fSphereRadiusSquared; + insideSqr = b * b - c * a * 4.0f; + return insideSqr > 0.000001; +} + +/* <8402e> ../engine/r_studio.c:1264 */ +qboolean SV_CheckSphereIntersection(edict_t *ent, const vec_t *start, const vec_t *end) +{ + studiohdr_t *studiohdr; + mstudioseqdesc_t *pseqdesc; + + vec3_t traceOrg; + vec3_t traceDir; + float radiusSquared; + vec3_t maxDim; + + radiusSquared = 0.0f; + if (!(ent->v.flags & FL_CLIENT)) + return 1; + + traceOrg[0] = start[0]; + traceOrg[1] = start[1]; + traceOrg[2] = start[2]; + traceDir[0] = end[0] - start[0]; + traceDir[1] = end[1] - start[1]; + traceDir[2] = end[2] - start[2]; + + studiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[ent->v.modelindex]); + pseqdesc = (mstudioseqdesc_t *)((char *)studiohdr + studiohdr->seqindex); + pseqdesc += ent->v.sequence; + for (int i = 0; i < 3; i++) + { + maxDim[i] = max(fabs(pseqdesc->bbmax[i]), fabs(pseqdesc->bbmin[i])); + } + radiusSquared = maxDim[0] * maxDim[0] + maxDim[1] * maxDim[1] + maxDim[2] * maxDim[2]; + return DoesSphereIntersect(ent->v.origin, radiusSquared, traceOrg, traceDir) != 0; +} + + +/* <840e2> ../engine/r_studio.c:1302 */ +void AnimationAutomove(const edict_t *pEdict, float flTime) +{ +} + +/* <8411a> ../engine/r_studio.c:1329 */ +void GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles) +{ + pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]); + g_pSvBlendingAPI->SV_StudioSetupBones( + g_psv.models[pEdict->v.modelindex], + pEdict->v.frame, + pEdict->v.sequence, + pEdict->v.angles, + pEdict->v.origin, + pEdict->v.controller, + pEdict->v.blending, + iBone, + pEdict + ); + + if (rgflOrigin) + { + rgflOrigin[0] = bonetransform[iBone][0][3]; + rgflOrigin[1] = bonetransform[iBone][1][3]; + rgflOrigin[2] = bonetransform[iBone][2][3]; + } +} + +/* <84171> ../engine/r_studio.c:1351 */ +void GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles) +{ + mstudioattachment_t *pattachment; + vec3_t angles; + + angles[0] = -pEdict->v.angles[0]; + angles[1] = pEdict->v.angles[1]; + angles[2] = pEdict->v.angles[2]; + + pstudiohdr = (studiohdr_t *)Mod_Extradata(g_psv.models[pEdict->v.modelindex]); + pattachment = (mstudioattachment_t *)((char *)pstudiohdr + pstudiohdr->attachmentindex); + pattachment += iAttachment; + + g_pSvBlendingAPI->SV_StudioSetupBones( + g_psv.models[pEdict->v.modelindex], + pEdict->v.frame, + pEdict->v.sequence, + angles, + pEdict->v.origin, + pEdict->v.controller, + pEdict->v.blending, + pattachment->bone, + pEdict + ); + + if (rgflOrigin) + VectorTransform(pattachment->org, (float *)bonetransform[pattachment->bone], rgflOrigin); +} + +/* <841ed> ../engine/r_studio.c:1379 */ +int ModelFrameCount(model_t *model) +{ + int count; + + if (!model) + return 1; + + switch (model->type) + { + case mod_sprite: + count = ((msprite_t*)model->cache.data)->numframes; + break; + + case mod_studio: + count = R_StudioBodyVariations(model); + break; + + default: + return 1; + } + + if (count < 1) + return 1; + + return count; +} + +/* <84296> ../engine/r_studio.c:5618 */ +void R_StudioBoundVertex(vec_t *mins, vec_t *maxs, int *vertcount, const vec_t *point) +{ + if (*vertcount) + { + for (int i = 0; i < 3; i++) + { + if (mins[i] > point[i]) + mins[i] = point[i]; + + if (maxs[i] < point[i]) + maxs[i] = point[i]; + } + + } + else + { + for (int i = 0; i < 3; i++) + { + mins[i] = point[i]; + maxs[i] = point[i]; + } + } + + ++(*vertcount); +} + +/* <842fb> ../engine/r_studio.c:5640 */ +void R_StudioBoundBone(vec_t *mins, vec_t *maxs, int *bonecount, const vec_t *point) +{ + if (*bonecount) + { + for (int i = 0; i < 3; i++) + { + if (mins[i] > point[i]) + mins[i] = point[i]; + + if (maxs[i] < point[i]) + maxs[i] = point[i]; + } + + } + else + { + for (int i = 0; i < 3; i++) + { + mins[i] = point[i]; + maxs[i] = point[i]; + } + } + + ++(*bonecount); +} + +/* <84360> ../engine/r_studio.c:5662 */ +void R_StudioAccumulateBoneVerts(vec_t *mins, vec_t *maxs, int *vertcount, vec_t *bone_mins, vec_t *bone_maxs, int *bonecount) +{ + vec3_t delta; + vec3_t point; + + if (*bonecount > 0) + { + delta[0] = bone_maxs[0] - bone_mins[0]; + delta[1] = bone_maxs[1] - bone_mins[1]; + delta[2] = bone_maxs[2] - bone_mins[2]; + VectorScale(delta, 0.5, point); + R_StudioBoundVertex(mins, maxs, vertcount, point); + VectorScale(delta, -0.5, point); + R_StudioBoundVertex(mins, maxs, vertcount, point); + + for (int i = 0; i < 3; i++) + bone_mins[i] = bone_maxs[i] = 0; + + *bonecount = 0; + } +} + +/* <843f3> ../engine/r_studio.c:5693 */ +int R_StudioComputeBounds(unsigned char *pBuffer, float *mins, float *maxs) +{ + vec3_t bone_mins; + vec3_t bone_maxs; + vec3_t vert_mins; + vec3_t vert_maxs; + + for (int i = 0; i < 3; i++) + bone_mins[i] = bone_maxs[i] = vert_mins[i] = vert_maxs[i] = 0; + + studiohdr_t * header = (studiohdr_t *)pBuffer; + mstudiobodyparts_t * bodyparts = (mstudiobodyparts_t *)((char *)header + header->bodypartindex); + + + int nummodels = 0; + for (int i = 0; i < header->numbodyparts; i++) + nummodels += bodyparts[i].nummodels; + + int vert_count = 0; + mstudiomodel_t *pmodel = (mstudiomodel_t *)&bodyparts[header->numbodyparts]; + for (int model = 0; model < nummodels; model++, pmodel++) + { + int num_verts = pmodel->numverts; + vec3_t *pverts = (vec3_t *)((char *)header + pmodel->vertindex); + for (int v = 0; v < num_verts; v++) + R_StudioBoundVertex(vert_mins, vert_maxs, &vert_count, pverts[v]); + } + + int bone_count = 0; + mstudiobone_t* pbones = (mstudiobone_t*)((char *)header + header->boneindex); + mstudioseqdesc_t *pseq = (mstudioseqdesc_t *)((char *)header + header->seqindex); + for (int sequence = 0; sequence < header->numseq; sequence++, pseq++) + { + int num_frames = pseq->numframes; + mstudioanim_t *panim = (mstudioanim_t *)((char *)header + pseq->animindex); + for (int bone = 0; bone < header->numbones; bone++) + { + for (int f = 0; f < num_frames; ++f) + { + vec3_t bonepos; + R_StudioCalcBonePosition(f, 0.0, &pbones[bone], panim, 0, bonepos); + R_StudioBoundBone(bone_mins, bone_maxs, &bone_count, bonepos); + } + } + + R_StudioAccumulateBoneVerts(vert_mins, vert_maxs, &vert_count, bone_mins, bone_maxs, &bone_count); + } + + for (int i = 0; i < 3; i++) + { + mins[i] = vert_mins[i]; + maxs[i] = vert_maxs[i]; + } + + return 1; +} + +/* <845bc> ../engine/r_studio.c:5809 */ +int R_GetStudioBounds(const char *filename, float *mins, float *maxs) +{ + int iret = 0; + qboolean usingReadBuffer = 0; + + for (int i = 0; i < 3; i++) + mins[0] = maxs[0] = vec3_origin[i]; + + if (!Q_strstr(filename, "models") || !Q_strstr(filename, ".mdl")) + return 0; + + + FileHandle_t fp = FS_Open(filename, "rb"); + if (!fp) + return 0; + + int length; + char *pBuffer = (char *)FS_GetReadBuffer(fp, &length); + if (pBuffer) + usingReadBuffer = 1; + else + pBuffer = (char*) COM_LoadFile(filename, 5, 0); + + if (pBuffer) + { + if (LittleLong(*(unsigned int *)pBuffer) == 'TSDI') + iret = R_StudioComputeBounds((unsigned char*)pBuffer, mins, maxs); + else + COM_FreeFile(pBuffer); + } + + if (usingReadBuffer) + FS_ReleaseReadBuffer(fp, pBuffer); + else + COM_FreeFile(pBuffer); + + FS_Close(fp); + + return iret; +} + +/* <8465f> ../engine/r_studio.c:6565 */ +void R_ResetSvBlending(void) +{ + g_pSvBlendingAPI = &svBlending; +} diff --git a/rehlds/engine/server.h b/rehlds/engine/server.h new file mode 100644 index 0000000..593601f --- /dev/null +++ b/rehlds/engine/server.h @@ -0,0 +1,752 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SERVER_H +#define SERVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + +#define MAX_CLIENTS 32 +#define MAX_EDICTS 900 +#define MAX_NAME 32 +#define MAX_LIGHTSTYLES 64 + +#include "custom_int.h" +#include "crc.h" +#include "cvar.h" +#include "dll_state.h" +#include "consistency.h" +#include "event.h" +#include "entity_state.h" +#include "delta.h" +#include "delta_packet.h" +#include "model.h" +#include "net.h" +#include "progs.h" +#include "filter.h" +#include "server_static.h" +#include "usermsg.h" +#include "userid.h" +#include "pm_defs.h" +#include "inst_baseline.h" + + +#define DEFAULT_SOUND_PACKET_VOLUME 255 +#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0f +#define DEFAULT_SOUND_PACKET_PITCH 100 + +// Sound flags +#define SND_FL_VOLUME BIT(0) // send volume +#define SND_FL_ATTENUATION BIT(1) // send attenuation +#define SND_FL_LARGE_INDEX BIT(2) // send sound number as short instead of byte +#define SND_FL_PITCH BIT(3) // send pitch +#define SND_FL_SENTENCE BIT(4) // set if sound num is actually a sentence num +#define SND_FL_STOP BIT(5) // stop the sound +#define SND_FL_CHANGE_VOL BIT(6) // change sound vol +#define SND_FL_CHANGE_PITCH BIT(7) // change sound pitch +#define SND_FL_SPAWNING BIT(8) // we're spawning, used in some cases for ambients (not sent across network) + +// Message send destination flags +#define MSG_FL_NONE 0 // No flags +#define MSG_FL_BROADCAST BIT(0) // Broadcast? +#define MSG_FL_PVS BIT(1) // Send to PVS +#define MSG_FL_PAS BIT(2) // Send to PAS +#define MSG_FL_ONE BIT(7) // Send to single client + + +#define HL_SOUND_MAX 512 +#define HL_SOUND_HASHLOOKUP_SIZE (HL_SOUND_MAX * 2 - 1) + +#define HL_MODEL_MAX 512 + +// Authentication types +#define AUTH_IDTYPE_UNKNOWN 0 +#define AUTH_IDTYPE_STEAM 1 +#define AUTH_IDTYPE_VALVE 2 +#define AUTH_IDTYPE_LOCAL 3 + + +/* <87d6f> ../engine/server.h:43 */ +typedef enum redirect_e +{ + RD_NONE = 0, + RD_CLIENT = 1, + RD_PACKET = 2, +} redirect_t; + +/* <7588> ../engine/server.h:65 */ +typedef enum server_state_e +{ + ss_dead = 0, + ss_loading = 1, + ss_active = 2, +} server_state_t; + +/* <75f3> ../engine/server.h:75 */ +typedef struct server_s +{ + qboolean active; + qboolean paused; + qboolean loadgame; + double time; + double oldtime; + int lastcheck; + double lastchecktime; + char name[64]; + char oldname[64]; + char startspot[64]; + char modelname[64]; + struct model_s *worldmodel; + CRC32_t worldmapCRC; + unsigned char clientdllmd5[16]; + resource_t resourcelist[1280]; + int num_resources; + consistency_t consistency_list[512]; + int num_consistency; + char *model_precache[512]; + struct model_s *models[512]; + unsigned char model_precache_flags[512]; + struct event_s event_precache[256]; + char *sound_precache[512]; + short int sound_precache_hashedlookup[HL_SOUND_HASHLOOKUP_SIZE]; + qboolean sound_precache_hashedlookup_built; + char *generic_precache[512]; + char generic_precache_names[512][64]; + int num_generic_names; + char *lightstyles[MAX_LIGHTSTYLES]; + int num_edicts; + int max_edicts; + edict_t *edicts; + struct entity_state_s *baselines; + extra_baselines_t *instance_baselines; + server_state_t state; + sizebuf_t datagram; + unsigned char datagram_buf[4000]; + sizebuf_t reliable_datagram; + unsigned char reliable_datagram_buf[4000]; + sizebuf_t multicast; + unsigned char multicast_buf[1024]; + sizebuf_t spectator; + unsigned char spectator_buf[1024]; + sizebuf_t signon; + unsigned char signon_data[32768]; +} server_t; + +/* <3b30a> ../engine/server.h:163 */ +typedef struct client_frame_s +{ + double senttime; + float ping_time; + clientdata_t clientdata; + weapon_data_t weapondata[64]; + packet_entities_t entities; +} client_frame_t; + +/* <2eb23> ../engine/server.h:177 */ +typedef struct client_s +{ + qboolean active; + qboolean spawned; + qboolean fully_connected; + qboolean connected; + qboolean uploading; + qboolean hasusrmsgs; + qboolean has_force_unmodified; + netchan_t netchan; + int chokecount; + int delta_sequence; + qboolean fakeclient; + qboolean proxy; + usercmd_t lastcmd; + double connecttime; + double cmdtime; + double ignorecmdtime; + float latency; + float packet_loss; + double localtime; + double nextping; + double svtimebase; + sizebuf_t datagram; + byte datagram_buf[4000]; + double connection_started; + double next_messagetime; + double next_messageinterval; + qboolean send_message; + qboolean skip_message; + client_frame_t *frames; + event_state_t events; + edict_t *edict; + const edict_t *pViewEntity; + int userid; + USERID_t network_userid; + char userinfo[MAX_INFO_STRING]; + qboolean sendinfo; + float sendinfo_time; + char hashedcdkey[64]; + char name[32]; + int topcolor; + int bottomcolor; + int entityId; + resource_t resourcesonhand; + resource_t resourcesneeded; + FileHandle_t upload; + qboolean uploaddoneregistering; + customization_t customdata; + int crcValue; + int lw; + int lc; + char physinfo[MAX_INFO_STRING]; + qboolean m_bLoopback; + uint32_t m_VoiceStreams[2]; + double m_lastvoicetime; + int m_sendrescount; +} client_t; + +/* <9e1af> ../engine/server.h:276 */ +typedef enum sv_delta_s +{ + sv_packet_nodelta, + sv_packet_delta, +} sv_delta_t; + +/* <9e1d1> ../engine/server.h:336 */ +enum +{ + SND_ANYPLAYER, + SND_NOTHOST, +}; + +typedef struct rcon_failure_s rcon_failure_t; +typedef struct challenge_s challenge_t; + +/* ../engine/sv_main.c:5335 */ +typedef struct deltacallback_s +{ + int *numbase; + int num; + qboolean remove; + qboolean custom; + qboolean newbl; + int newblindex; + qboolean full; + int offset; +} deltacallback_t; + + +#ifdef HOOK_ENGINE +#define pr_strings (*ppr_strings) +#define gNullString (*pgNullString) +#define scr_skipupdate (*pscr_skipupdate) +#define scr_centertime_off (*pscr_centertime_off) +#define g_LastScreenUpdateTime (*pg_LastScreenUpdateTime) + +#define SV_UPDATE_BACKUP (*pSV_UPDATE_BACKUP) +#define SV_UPDATE_MASK (*pSV_UPDATE_MASK) + +#define gGlobalVariables (*pgGlobalVariables) +#define g_psvs (*psvs) +#define g_psv (*psv) + +#define sv_lan (*psv_lan) +#define sv_lan_rate (*psv_lan_rate) +#define sv_aim (*psv_aim) + +#define sv_skycolor_r (*psv_skycolor_r) +#define sv_skycolor_g (*psv_skycolor_g) +#define sv_skycolor_b (*psv_skycolor_b) +#define sv_skyvec_x (*psv_skyvec_x) +#define sv_skyvec_y (*psv_skyvec_y) +#define sv_skyvec_z (*psv_skyvec_z) +#define sv_skyname (*psv_skyname) + +#define sv_spectatormaxspeed (*psv_spectatormaxspeed) +#define sv_airaccelerate (*psv_airaccelerate) +#define sv_wateraccelerate (*psv_wateraccelerate) +#define sv_waterfriction (*psv_waterfriction) +#define sv_zmax (*psv_zmax) +#define sv_wateramp (*psv_wateramp) +#define mapcyclefile (*pmapcyclefile) +#define motdfile (*pmotdfile) +#define servercfgfile (*pservercfgfile) +#define lservercfgfile (*plservercfgfile) +#define logsdir (*plogsdir) +#define bannedcfgfile (*pbannedcfgfile) + +#define sv_decalnames (*psv_decalnames) +#define sv_decalnamecount (*psv_decalnamecount) + +#define sv_gpNewUserMsgs (*psv_gpNewUserMsgs) +#define sv_gpUserMsgs (*psv_gpUserMsgs) + +#define g_svmove (*pg_svmove) + +#define sv_lastnum (*psv_lastnum) +#define g_sv_instance_baselines (*pg_sv_instance_baselines) +#define g_bOutOfDateRestart (*pg_bOutOfDateRestart) +#define g_userid (*pg_userid) + +#define g_sv_delta (*pg_sv_delta) +#define g_peventdelta (*pg_peventdelta) + +#define rcon_password (*prcon_password) +#define sv_enableoldqueries (*psv_enableoldqueries) +#define sv_instancedbaseline (*psv_instancedbaseline) +#define sv_contact (*psv_contact) +#define sv_maxupdaterate (*psv_maxupdaterate) +#define sv_minupdaterate (*psv_minupdaterate) +#define sv_filterban (*psv_filterban) +#define sv_minrate (*psv_minrate) +#define sv_maxrate (*psv_maxrate) +#define sv_logrelay (*psv_logrelay) +#define violence_hblood (*pviolence_hblood) +#define violence_ablood (*pviolence_ablood) +#define violence_hgibs (*pviolence_hgibs) +#define violence_agibs (*pviolence_agibs) +#define sv_newunit (*psv_newunit) +#define sv_clienttrace (*psv_clienttrace) +#define sv_timeout (*psv_timeout) +#define sv_failuretime (*psv_failuretime) + +#define sv_cheats (*psv_cheats) +#define sv_password (*psv_password) +#define sv_proxies (*psv_proxies) +#define sv_outofdatetime (*psv_outofdatetime) +#define mapchangecfgfile (*pmapchangecfgfile) + +#define allow_cheats (*pallow_cheats) +#define mp_logecho (*pmp_logecho) +#define mp_logfile (*pmp_logfile) + +#define sv_allow_download (*psv_allow_download) +#define sv_send_logos (*psv_send_logos) +#define sv_send_resources (*psv_send_resources) +#define sv_log_singleplayer (*psv_log_singleplayer) +#define sv_logsecret (*psv_logsecret) +#define sv_log_onefile (*psv_log_onefile) +#define sv_logbans (*psv_logbans) +#define sv_allow_upload (*psv_allow_upload) +#define sv_max_upload (*psv_max_upload) +#define hpk_maxsize (*phpk_maxsize) +#define sv_visiblemaxplayers (*psv_visiblemaxplayers) +#define max_queries_sec (*pmax_queries_sec) +#define max_queries_sec_global (*pmax_queries_sec_global) +#define max_queries_window (*pmax_queries_window) +#define sv_logblocks (*psv_logblocks) +#define sv_downloadurl (*psv_downloadurl) +#define sv_allow_dlfile (*psv_allow_dlfile) +#define sv_version (*psv_version) +#define sv_playermodel (*psv_playermodel) + +#define outputbuf (*poutputbuf) +#define sv_redirected (*psv_redirected) +#define sv_redirectto (*psv_redirectto) + +#define sv_rcon_minfailures (*psv_rcon_minfailures) +#define sv_rcon_maxfailures (*psv_rcon_maxfailures) +#define sv_rcon_minfailuretime (*psv_rcon_minfailuretime) +#define sv_rcon_banpenalty (*psv_rcon_banpenalty) + +#define scr_downloading (*pscr_downloading) + +#define g_bCS_CZ_Flags_Initialized (*pg_bCS_CZ_Flags_Initialized) +#define g_bIsCZero (*pg_bIsCZero) +#define g_bIsCZeroRitual (*pg_bIsCZeroRitual) +#define g_bIsTerrorStrike (*pg_bIsTerrorStrike) +#define g_bIsTFC (*pg_bIsTFC) +#define g_bIsHL1 (*pg_bIsHL1) +#define g_bIsCStrike (*pg_bIsCStrike) + +#define fatbytes (*pfatbytes) +#define fatpvs (*pfatpvs) +#define fatpasbytes (*pfatpasbytes) +#define fatpas (*pfatpas) +#define gPacketSuppressed (*pgPacketSuppressed) +#define giNextUserMsg (*pgiNextUserMsg) +#define hashstrings_collisions (*phashstrings_collisions) + +#define g_pplayerdelta (*pg_pplayerdelta) +#define g_pentitydelta (*pg_pentitydelta) +#define g_pcustomentitydelta (*pg_pcustomentitydelta) +#define g_pclientdelta (*pg_pclientdelta) +#define g_pweapondelta (*pg_pweapondelta) + +#define localinfo (*plocalinfo) +#define localmodels (*plocalmodels) + +#define ipfilters (*pipfilters) +#define numipfilters (*pnumipfilters) +#define userfilters (*puserfilters) +#define numuserfilters (*pnumuserfilters) + +#define g_rg_sv_challenges (*pg_rg_sv_challenges) + +#define g_svdeltacallback (*pg_svdeltacallback) + +#endif // HOOK_ENGINE + + +extern char *pr_strings; +extern char *gNullString; +extern qboolean scr_skipupdate; +extern float scr_centertime_off; +extern float g_LastScreenUpdateTime; + +extern int SV_UPDATE_BACKUP; +extern int SV_UPDATE_MASK; + +extern globalvars_t gGlobalVariables; +extern server_static_t g_psvs; +extern server_t g_psv; + +extern cvar_t sv_lan; +extern cvar_t sv_lan_rate; +extern cvar_t sv_aim; + +extern cvar_t sv_skycolor_r; +extern cvar_t sv_skycolor_g; +extern cvar_t sv_skycolor_b; +extern cvar_t sv_skyvec_x; +extern cvar_t sv_skyvec_y; +extern cvar_t sv_skyvec_z; +extern cvar_t sv_skyname; + +extern cvar_t sv_spectatormaxspeed; +extern cvar_t sv_airaccelerate; +extern cvar_t sv_wateraccelerate; +extern cvar_t sv_waterfriction; +extern cvar_t sv_zmax; +extern cvar_t sv_wateramp; +extern cvar_t mapcyclefile; +extern cvar_t motdfile; +extern cvar_t servercfgfile; +extern cvar_t lservercfgfile; +extern cvar_t logsdir; +extern cvar_t bannedcfgfile; + +extern decalname_t sv_decalnames[512]; +extern int sv_decalnamecount; + +extern UserMsg *sv_gpNewUserMsgs; +extern UserMsg *sv_gpUserMsgs; +extern playermove_t g_svmove; + +extern int sv_lastnum; +extern extra_baselines_t g_sv_instance_baselines; +extern qboolean g_bOutOfDateRestart; +extern int g_userid; + +extern delta_info_t *g_sv_delta; +extern delta_t *g_peventdelta; + +extern cvar_t rcon_password; +extern cvar_t sv_enableoldqueries; +extern cvar_t sv_instancedbaseline; +extern cvar_t sv_contact; +extern cvar_t sv_maxupdaterate; +extern cvar_t sv_minupdaterate; +extern cvar_t sv_filterban; +extern cvar_t sv_minrate; +extern cvar_t sv_maxrate; +extern cvar_t sv_logrelay; +extern cvar_t violence_hblood; +extern cvar_t violence_ablood; +extern cvar_t violence_hgibs; +extern cvar_t violence_agibs; +extern cvar_t sv_newunit; +extern cvar_t sv_clienttrace; +extern cvar_t sv_timeout; +extern cvar_t sv_failuretime; + +extern cvar_t sv_cheats; +extern cvar_t sv_password; +extern cvar_t sv_proxies; +extern cvar_t sv_outofdatetime; +extern cvar_t mapchangecfgfile; + +extern qboolean allow_cheats; +extern cvar_t mp_logecho; +extern cvar_t mp_logfile; +extern cvar_t sv_allow_download; +extern cvar_t sv_send_logos; +extern cvar_t sv_send_resources; +extern cvar_t sv_log_singleplayer; +extern cvar_t sv_logsecret; +extern cvar_t sv_log_onefile; +extern cvar_t sv_logbans; +extern cvar_t sv_allow_upload; +extern cvar_t sv_max_upload; +extern cvar_t hpk_maxsize; +extern cvar_t sv_visiblemaxplayers; +extern cvar_t max_queries_sec; +extern cvar_t max_queries_sec_global; +extern cvar_t max_queries_window; +extern cvar_t sv_logblocks; +extern cvar_t sv_downloadurl; +extern cvar_t sv_allow_dlfile; +extern cvar_t sv_version; +extern int sv_playermodel; + +extern char outputbuf[1400]; +extern redirect_t sv_redirected; +extern netadr_t sv_redirectto; + +extern cvar_t sv_rcon_minfailures; +extern cvar_t sv_rcon_maxfailures; +extern cvar_t sv_rcon_minfailuretime; +extern cvar_t sv_rcon_banpenalty; + +extern cvar_t scr_downloading; + +extern int g_bCS_CZ_Flags_Initialized; +extern int g_bIsCZero; +extern int g_bIsCZeroRitual; +extern int g_bIsTerrorStrike; +extern int g_bIsTFC; +extern int g_bIsHL1; +extern int g_bIsCStrike; + +extern int fatbytes; +extern int giNextUserMsg; +extern int hashstrings_collisions; + +extern delta_t *g_pplayerdelta; +extern delta_t *g_pentitydelta; +extern delta_t *g_pcustomentitydelta; +extern delta_t *g_pclientdelta; +extern delta_t *g_pweapondelta; + + +extern unsigned char fatpvs[1024]; +extern int fatpasbytes; +extern unsigned char fatpas[1024]; + +extern int gPacketSuppressed; + +extern char localinfo[MAX_INFO_STRING * 128]; +extern char localmodels[512][5]; + +extern ipfilter_t ipfilters[32768]; +extern int numipfilters; +extern userfilter_t userfilters[32768]; +extern int numuserfilters; + +extern challenge_t g_rg_sv_challenges[1024]; + + +#ifdef HOOK_ENGINE +#define g_rgRconFailures (*pg_rgRconFailures) +#endif // HOOK_ENGINE + +extern rcon_failure_t g_rgRconFailures[32]; +extern deltacallback_t g_svdeltacallback; + +delta_t *SV_LookupDelta(char *name); +NOXREF void SV_DownloadingModules(void); +void SV_GatherStatistics(void); +void SV_DeallocateDynamicData(void); +void SV_ReallocateDynamicData(void); +void SV_AllocClientFrames(void); +qboolean SV_IsPlayerIndex(int index); +qboolean SV_IsPlayerIndex_wrapped(int index); +void SV_ClearPacketEntities(client_frame_t *frame); +void SV_AllocPacketEntities(client_frame_t *frame, int numents); +void SV_ClearFrames(client_frame_t ** frames); +void SV_Serverinfo_f(void); +void SV_Localinfo_f(void); +void SV_User_f(void); +void SV_Users_f(void); +void SV_CountPlayers(int *clients); +void SV_CountProxies(int *proxies); +void SV_FindModelNumbers(void); +void SV_StartParticle(const vec_t *org, const vec_t *dir, int color, int count); +void SV_StartSound(int recipients, edict_t *entity, int channel, const char *sample, int volume, float attenuation, int fFlags, int pitch); +qboolean SV_BuildSoundMsg(edict_t *entity, int channel, const char *sample, int volume, float attenuation, int fFlags, int pitch, const float *origin, sizebuf_t *buffer); +int SV_HashString(const char *string, int iBounds); +int SV_LookupSoundIndex(const char *sample); +void SV_BuildHashedSoundLookupTable(void); +void SV_AddSampleToHashedLookupTable(const char *pszSample, int iSampleIndex); +qboolean SV_ValidClientMulticast(client_t *client, int soundLeaf, int to); +void SV_Multicast(edict_t *ent, vec_t *origin, int to, qboolean reliable); +void SV_WriteMovevarsToClient(sizebuf_t *message); +void SV_WriteDeltaDescriptionsToClient(sizebuf_t *msg); +void SV_SetMoveVars(void); +void SV_QueryMovevarsChanged(void); +void SV_SendServerinfo(sizebuf_t *msg, client_t *client); +void SV_SendServerinfo_internal(sizebuf_t *msg, client_t *client); +void SV_SendResources(sizebuf_t *msg); +void SV_WriteClientdataToMessage(client_t *client, sizebuf_t *msg); +void SV_WriteSpawn(sizebuf_t *msg); +void SV_SendUserReg(sizebuf_t *msg); +void SV_New_f(void); +void SV_SendRes_f(void); +void SV_Spawn_f(void); +void SV_CheckUpdateRate(double *rate); +void SV_RejectConnection(netadr_t *adr, char *fmt, ...); +void SV_RejectConnectionForPassword(netadr_t *adr); +int SV_GetFragmentSize(void *state); +qboolean SV_FilterUser(USERID_t *userid); +int SV_CheckProtocol(netadr_t *adr, int nProtocol); +int SV_CheckProtocol_internal(netadr_t *adr, int nProtocol); +bool SV_CheckChallenge_api(const netadr_t &adr, int nChallengeValue); +int SV_CheckChallenge(netadr_t *adr, int nChallengeValue); +int SV_CheckIPRestrictions(netadr_t *adr, int nAuthProtocol); +int SV_CheckIPRestrictions_internal(netadr_t *adr, int nAuthProtocol); +int SV_CheckIPConnectionReuse(netadr_t *adr); +int SV_FinishCertificateCheck(netadr_t *adr, int nAuthProtocol, char *szRawCertificate, char *userinfo); +int SV_FinishCertificateCheck_internal(netadr_t *adr, int nAuthProtocol, char *szRawCertificate, char *userinfo); +int SV_CheckKeyInfo(netadr_t *adr, char *protinfo, short unsigned int *port, int *pAuthProtocol, char *pszRaw, char *cdkey); +int SV_CheckKeyInfo_internal(netadr_t *adr, char *protinfo, short unsigned int *port, int *pAuthProtocol, char *pszRaw, char *cdkey); +int SV_CheckForDuplicateSteamID(client_t *client); +int SV_CheckForDuplicateNames(char *userinfo, qboolean bIsReconnecting, int nExcludeSlot); +int SV_CheckUserInfo(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, int nReconnectSlot, char *name); +int SV_FindEmptySlot(netadr_t *adr, int *pslot, client_t ** ppClient); +void SV_ConnectClient(void); +void SV_ConnectClient_internal(void); +void SVC_Ping(void); +void SVC_GetChallenge(void); +void SVC_ServiceChallenge(void); +void SV_ResetModInfo(void); +int SV_GetFakeClientCount(void); +NOXREF qboolean SV_GetModInfo(char *pszInfo, char *pszDL, int *version, int *size, qboolean *svonly, qboolean *cldll, char *pszHLVersion); +NOXREF qboolean RequireValidChallenge(netadr_t *adr); +NOXREF qboolean ValidInfoChallenge(netadr_t *adr, const char *nugget); +NOXREF int GetChallengeNr(netadr_t *adr); +NOXREF qboolean CheckChallengeNr(netadr_t *adr, int nChallengeValue); +NOXREF void ReplyServerChallenge(netadr_t *adr); +NOXREF qboolean ValidChallenge(netadr_t *adr, int challengeNr); +NOXREF void SVC_InfoString(void); +NOXREF void SVC_Info(qboolean bDetailed); +NOXREF void SVC_PlayerInfo(void); +NOXREF void SVC_RuleInfo(void); +int SVC_GameDllQuery(const char *s); +void SV_FlushRedirect(void); +void SV_EndRedirect(void); +void SV_BeginRedirect(redirect_t rd, netadr_t *addr); +void SV_ResetRcon_f(void); +void SV_AddFailedRcon(netadr_t *adr); +qboolean SV_CheckRconFailure(netadr_t *adr); +int SV_Rcon_Validate(void); +void SV_Rcon(netadr_t *net_from_); +void SV_ConnectionlessPacket(void); +void SV_CheckRate(client_t *cl); +void SV_ProcessFile(client_t *cl, char *filename); +qboolean SV_FilterPacket(void); +void SV_SendBan(void); +void SV_ReadPackets(void); +//NOBODY int ntohl(void); +//NOBODY int htons(void); +void SV_CheckTimeouts(void); +int SV_CalcPing(client_t *cl); +void SV_FullClientUpdate(client_t *cl, sizebuf_t *sb); +void SV_EmitEvents(client_t *cl, packet_entities_t *pack, sizebuf_t *msg); +void SV_AddToFatPVS(vec_t *org, mnode_t *node); +unsigned char *SV_FatPVS(float *org); +void SV_AddToFatPAS(vec_t *org, mnode_t *node); +unsigned char *SV_FatPAS(float *org); +int SV_PointLeafnum(vec_t *p); +void TRACE_DELTA(char *fmt, ...); +void SV_SetCallback(int num, qboolean remove, qboolean custom, int *numbase, qboolean full, int offset); +void SV_SetNewInfo(int newblindex); +void SV_WriteDeltaHeader(int num, qboolean remove, qboolean custom, int *numbase, qboolean newbl, int newblindex, qboolean full, int offset); +void SV_InvokeCallback(void); +int SV_FindBestBaseline(int index, entity_state_t ** baseline, entity_state_t *to, int num, qboolean custom); +int SV_CreatePacketEntities(sv_delta_t type, client_t *client, packet_entities_t *to, sizebuf_t *msg); +void SV_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t *msg); +qboolean SV_ShouldUpdatePing(client_t *client); +NOXREF qboolean SV_HasEventsInQueue(client_t *client); +void SV_GetNetInfo(client_t *client, int *ping, int *packet_loss); +int SV_CheckVisibility(edict_t *entity, unsigned char *pset); +void SV_EmitPings(client_t *client, sizebuf_t *msg); +void SV_WriteEntitiesToClient(client_t *client, sizebuf_t *msg); +void SV_CleanupEnts(void); +qboolean SV_SendClientDatagram(client_t *client); +void SV_UpdateToReliableMessages(void); +void SV_SkipUpdates(void); +void SV_SendClientMessages(void); +void SV_ExtractFromUserinfo(client_t *cl); +int SV_ModelIndex(const char *name); +void SV_AddResource(resourcetype_t type, char *name, int size, unsigned char flags, int index); +void SV_CreateGenericResources(void); +void SV_CreateResourceList(void); +void SV_ClearCaches(void); +void SV_PropagateCustomizations(void); +void SV_WriteVoiceCodec(sizebuf_t *pBuf); +void SV_CreateBaseline(void); +void SV_BroadcastCommand(char *fmt, ...); +void SV_BuildReconnect(sizebuf_t *msg); +NOXREF void SV_ReconnectAllClients(void); +void SetCStrikeFlags(void); +void SV_ActivateServer(int runPhysics); +void SV_ServerShutdown(void); +int SV_SpawnServer(qboolean bIsDemo, char *server, char *startspot); +void SV_LoadEntities(void); +void SV_ClearEntities(void); +int RegUserMsg(const char *pszName, int iSize); +qboolean StringToFilter(const char *s, ipfilter_t *f); +USERID_t *SV_StringToUserID(const char *str); +void SV_BanId_f(void); +void Host_Kick_f(void); +void SV_RemoveId_f(void); +void SV_WriteId_f(void); +void SV_ListId_f(void); +void SV_AddIP_f(void); +void SV_RemoveIP_f(void); +void SV_ListIP_f(void); +void SV_WriteIP_f(void); +void SV_KickPlayer(int nPlayerSlot, int nReason); +void SV_InactivateClients(void); +void SV_FailDownload(const char *filename); +const char *Q_stristr(const char *pStr, const char *pSearch); +qboolean IsSafeFileToDownload(const char *filename); +void SV_BeginFileDownload_f(void); +void SV_SetMaxclients(void); +void SV_HandleRconPacket(void); +void SV_CheckCmdTimes(void); +void SV_CheckForRcon(void); +qboolean SV_IsSimulating(void); +void SV_CheckMapDifferences(void); +void SV_Frame(void); +void SV_Drop_f(void); +void SV_RegisterDelta(char *name, char *loadfile); +void SV_InitDeltas(void); +void SV_InitEncoders(void); +void SV_Init(void); +void SV_Shutdown(void); +qboolean SV_CompareUserID(USERID_t *id1, USERID_t *id2); +qboolean SV_CompareUserID_internal(USERID_t *id1, USERID_t *id2); +char *SV_GetIDString(USERID_t *id); +char *SV_GetIDString_internal(USERID_t *id); +char *SV_GetClientIDString(client_t *client); +int GetGameAppID(void); +qboolean IsGameSubscribed(const char *gameName); +NOXREF qboolean BIsValveGame(void); + +#endif // SERVER_H diff --git a/rehlds/engine/server_static.h b/rehlds/engine/server_static.h new file mode 100644 index 0000000..6e66267 --- /dev/null +++ b/rehlds/engine/server_static.h @@ -0,0 +1,84 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SERVER_STATIC_H +#define SERVER_STATIC_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "netadr.h" + + +/* <2e957> ../engine/server_static.h:13 */ +typedef struct server_log_s +{ + qboolean active; + qboolean net_log_; + netadr_t net_address_; + void *file; +} server_log_t; + +/* <2e9a3> ../engine/server_static.h:22 */ +typedef struct server_stats_s +{ + int num_samples; + int at_capacity; + int at_empty; + float capacity_percent; + float empty_percent; + int minusers; + int maxusers; + float cumulative_occupancy; + float occupancy; + int num_sessions; + float cumulative_sessiontime; + float average_session_len; + float cumulative_latency; + float average_latency; +} server_stats_t; + +/* <2ea7b> ../engine/server_static.h:43 */ +typedef struct server_static_s +{ + qboolean dll_initialized; + struct client_s *clients; + int maxclients; + int maxclientslimit; + int spawncount; + int serverflags; + server_log_t log; + double next_cleartime; + double next_sampletime; + server_stats_t stats; + qboolean isSecure; +} server_static_t; + + +#endif // SERVER_STATIC_H diff --git a/rehlds/engine/snd_null.cpp b/rehlds/engine/snd_null.cpp new file mode 100644 index 0000000..5471ebd --- /dev/null +++ b/rehlds/engine/snd_null.cpp @@ -0,0 +1,104 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +/* <84fa2> ../engine/snd_null.c:16 */ +void S_Init(void) { } + +/* <84fb6> ../engine/snd_null.c:18 */ +void S_AmbientOff(void) { } + +/* <84fca> ../engine/snd_null.c:20 */ +void S_AmbientOn(void) { } + +/* <84fde> ../engine/snd_null.c:22 */ +void S_Shutdown(void) { } + +/* <84ff2> ../engine/snd_null.c:24 */ +void S_TouchSound(char *sample) { } + +/* <85019> ../engine/snd_null.c:26 */ +void S_ClearBuffer(void) { } + +/* <8502d> ../engine/snd_null.c:28 */ +void S_StartStaticSound(int entnum, int entchannel, sfx_t *sfx, vec_t *origin, float vol, float attenuation, int flags, int pitch) { } + +/* <850bc> ../engine/snd_null.c:30 */ +void S_StartDynamicSound(int entnum, int entchannel, sfx_t *sfx, vec_t *origin, float fvol, float attenuation, int flags, int pitch) { } + +/* <85145> ../engine/snd_null.c:32 */ +void S_StopSound(int entnum, int entchannel) { } + +/* <8517a> ../engine/snd_null.c:34 */ +sfx_t *S_PrecacheSound(char *sample) { return NULL; } + +/* <851a5> ../engine/snd_null.c:36 */ +void S_ClearPrecache(void) { } + +/* <851b9> ../engine/snd_null.c:38 */ +void S_Update(vec_t *origin, vec_t *v_forward, vec_t *v_right, vec_t *v_up) { } + +/* <8520a> ../engine/snd_null.c:40 */ +void S_StopAllSounds(qboolean clear) { } + +/* <85231> ../engine/snd_null.c:42 */ +void S_BeginPrecaching(void) { } + +/* <85245> ../engine/snd_null.c:44 */ +void S_EndPrecaching(void) { } + +/* <85259> ../engine/snd_null.c:46 */ +void S_ExtraUpdate(void) { } + +/* <8526d> ../engine/snd_null.c:48 */ +void S_LocalSound(char *s) { } + +/* <85292> ../engine/snd_null.c:50 */ +void S_BlockSound(void) { } + +/* <852a6> ../engine/snd_null.c:52 */ +void S_PrintStats(void) { } + +/* <852ba> ../engine/snd_null.c:55 */ +qboolean Voice_RecordStart(const char *pUncompressedFile, const char *pDecompressedFile, const char *pMicInputFile) { return FALSE; } + +/* <85301> ../engine/snd_null.c:56 */ +qboolean Voice_IsRecording(void) { return FALSE; } + +/* <85319> ../engine/snd_null.c:57 */ +void Voice_RegisterCvars(void) { } + +/* <8532d> ../engine/snd_null.c:58 */ +void Voice_Deinit(void) { } + +/* <85341> ../engine/snd_null.c:59 */ +void Voice_Idle(float frametime) { } + +/* <85368> ../engine/snd_null.c:60 */ +qboolean Voice_RecordStop(void) { return TRUE; } diff --git a/rehlds/engine/sound.h b/rehlds/engine/sound.h new file mode 100644 index 0000000..09d6230 --- /dev/null +++ b/rehlds/engine/sound.h @@ -0,0 +1,74 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SOUND_H +#define SOUND_H +#ifdef _WIN32 +#pragma once +#endif + +#include "quakedef.h" + +// max number of sentences in game. NOTE: this must match CVOXFILESENTENCEMAX in dlls\util.h!!! +#define CVOXFILESENTENCEMAX 1536 + +/* <2e874> ../engine/sound.h:26 */ +typedef struct sfx_s +{ + char name[64]; + cache_user_t cache; + int servercount; +} sfx_t; + +void S_Init(void); +void S_AmbientOff(void); +void S_AmbientOn(void); +void S_Shutdown(void); +void S_TouchSound(char *sample); +void S_ClearBuffer(void); +void S_StartStaticSound(int entnum, int entchannel, sfx_t *sfx, vec_t *origin, float vol, float attenuation, int flags, int pitch); +void S_StartDynamicSound(int entnum, int entchannel, sfx_t *sfx, vec_t *origin, float fvol, float attenuation, int flags, int pitch); +void S_StopSound(int entnum, int entchannel); +sfx_t *S_PrecacheSound(char *sample); +void S_ClearPrecache(void); +void S_Update(vec_t * origin, vec_t * v_forward, vec_t * v_right, vec_t * v_up); +void S_StopAllSounds(qboolean clear); +void S_BeginPrecaching(void); +void S_EndPrecaching(void); +void S_ExtraUpdate(void); +void S_LocalSound(char * s); +void S_BlockSound(void); +void S_PrintStats(void); +qboolean Voice_RecordStart(const char * pUncompressedFile, const char * pDecompressedFile, const char * pMicInputFile); +qboolean Voice_IsRecording(void); +void Voice_RegisterCvars(void); +void Voice_Deinit(void); +void Voice_Idle(float frametime); +qboolean Voice_RecordStop(void); + +#endif // SOUND_H \ No newline at end of file diff --git a/rehlds/engine/studio_rehlds.h b/rehlds/engine/studio_rehlds.h new file mode 100644 index 0000000..a52ee38 --- /dev/null +++ b/rehlds/engine/studio_rehlds.h @@ -0,0 +1,107 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#pragma once +#include "studio.h" +#include "model.h" +#include "r_studioint.h" +#include "cvardef.h" + +typedef struct r_studiocache_s r_studiocache_t; + +typedef hull_t studio_hull_t[STUDIO_NUM_HULLS]; +typedef int studio_hull_hitgroup_t[STUDIO_NUM_HULLS]; +typedef dclipnode_t studio_clipnodes_t[6]; +typedef mplane_t studio_planes_t[STUDIO_NUM_PLANES]; +typedef r_studiocache_t rgStudioCache_t[STUDIO_CACHE_SIZE]; +typedef float bonetransform_t[STUDIO_NUM_HULLS][3][4]; + +#ifdef HOOK_ENGINE + +#define cache_hull_hitgroup (*pcache_hull_hitgroup) +#define cache_hull (*pcache_hull) +#define cache_planes (*pcache_planes) + +#define pstudiohdr (*ppstudiohdr) +#define studio_hull (*pstudio_hull) +#define studio_hull_hitgroup (*pstudio_hull_hitgroup) +#define studio_clipnodes (*pstudio_clipnodes) +#define studio_planes (*pstudio_planes) +#define rgStudioCache (*prgStudioCache) +#define r_cachecurrent (*pr_cachecurrent) +#define nCurrentHull (*pnCurrentHull) +#define nCurrentPlane (*pnCurrentPlane) +#define bonetransform (*pbonetransform) +#define g_pSvBlendingAPI (*pg_pSvBlendingAPI) +#define svBlending (*psvBlending) +#define server_studio_api (*pserver_studio_api) +#define r_cachestudio (*pr_cachestudio) +#define rotationmatrix (*protationmatrix) + +#endif // HOOK_ENGINE + +extern int cache_hull_hitgroup[128]; +extern hull_t cache_hull[128]; +extern mplane_t cache_planes[768]; + +extern studiohdr_t *pstudiohdr; +extern studio_hull_t studio_hull; +extern studio_hull_hitgroup_t studio_hull_hitgroup; +extern studio_clipnodes_t studio_clipnodes; +extern studio_planes_t studio_planes; +extern rgStudioCache_t rgStudioCache; +extern int r_cachecurrent; +extern int nCurrentHull; +extern int nCurrentPlane; +extern bonetransform_t bonetransform; +extern sv_blending_interface_t *g_pSvBlendingAPI; +extern sv_blending_interface_t svBlending; +extern server_studio_api_t server_studio_api; +extern cvar_t r_cachestudio; +extern float rotationmatrix[3][4]; + +void SV_InitStudioHull(void); +r_studiocache_t *R_CheckStudioCache(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const vec_t *size, const unsigned char *controller, const unsigned char *blending); +NOXREF void R_AddToStudioCache(float frame, int sequence, const vec_t *angles, const vec_t *origin, const vec_t *size, const unsigned char *controller, const unsigned char *pblending, model_t *pModel, hull_t *pHulls, int numhulls); +void AngleQuaternion(vec_t *angles, vec_t *quaternion); +void QuaternionSlerp(vec_t *p, vec_t *q, float t, vec_t *qt); +void QuaternionMatrix(vec_t *quaternion, float matrix[3][4]); +void R_StudioCalcBoneAdj(float dadt, float *adj, const unsigned char *pcontroller1, const unsigned char *pcontroller2, unsigned char mouthopen); +void R_StudioCalcBoneQuaterion(int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q); +void R_StudioCalcBonePosition(int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos); +void R_StudioSlerpBones(vec4_t *q1, vec3_t *pos1, vec4_t *q2, vec3_t *pos2, float s); +mstudioanim_t *R_GetAnim(model_t *psubmodel, mstudioseqdesc_t *pseqdesc); +void SV_StudioSetupBones(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const unsigned char *pcontroller, const unsigned char *pblending, int iBone, const edict_t *edict); +void SV_SetStudioHullPlane(mplane_t *pplane, int iBone, int k, float dist); +hull_t *R_StudioHull(model_t *pModel, float frame, int sequence, const vec_t *angles, const vec_t *origin, const vec_t *size, const unsigned char *pcontroller, const unsigned char *pblending, int *pNumHulls, const edict_t *pEdict, int bSkipShield); +int SV_HitgroupForStudioHull(int index); +NOXREF void R_InitStudioCache(void); +NOXREF void R_FlushStudioCache(void); +int R_StudioBodyVariations(model_t *model); +void R_StudioPlayerBlend(mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch); +hull_t *SV_HullForStudioModel(const edict_t *pEdict, const vec_t *mins, const vec_t *maxs, vec_t *offset, int *pNumHulls); +qboolean DoesSphereIntersect(float *vSphereCenter, float fSphereRadiusSquared, float *vLinePt, float *vLineDir); +qboolean SV_CheckSphereIntersection(edict_t *ent, const vec_t *start, const vec_t *end); +void AnimationAutomove(const edict_t *pEdict, float flTime); +void GetBonePosition(const edict_t *pEdict, int iBone, float *rgflOrigin, float *rgflAngles); +void GetAttachment(const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles); +int ModelFrameCount(model_t *model); +void R_StudioBoundVertex(vec_t *mins, vec_t *maxs, int *vertcount, const vec_t *point); +void R_StudioBoundBone(vec_t *mins, vec_t *maxs, int *bonecount, const vec_t *point); +void R_StudioAccumulateBoneVerts(vec_t *mins, vec_t *maxs, int *vertcount, vec_t *bone_mins, vec_t *bone_maxs, int *bonecount); +int R_StudioComputeBounds(unsigned char *pBuffer, float *mins, float *maxs); +int R_GetStudioBounds(const char *filename, float *mins, float *maxs); +void R_ResetSvBlending(void); diff --git a/rehlds/engine/sv_log.cpp b/rehlds/engine/sv_log.cpp new file mode 100644 index 0000000..4c8d59a --- /dev/null +++ b/rehlds/engine/sv_log.cpp @@ -0,0 +1,424 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +LOGLIST_T *firstLog; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t mp_logecho = { "mp_logecho", "1", 0, 0.0f, NULL }; +cvar_t mp_logfile = { "mp_logfile", "1", FCVAR_SERVER, 0.0f, NULL }; + +#else //HOOK_ENGINE + +cvar_t mp_logecho; +cvar_t mp_logfile; + +#endif //HOOK_ENGINE + +/* <9a0ba> ../engine/sv_log.c:37 */ +void Log_Printf(const char *fmt, ...) +{ + va_list argptr; + char string[1024]; + time_t ltime; + tm *today; + LOGLIST_T *list; + + if (!g_psvs.log.net_log_ && !firstLog && !g_psvs.log.active) + return; + + time(<ime); + today = localtime(<ime); + + va_start(argptr, fmt); + Q_snprintf(string,sizeof(string), "L %02i/%02i/%04i - %02i:%02i:%02i: ", + today->tm_mon + 1, + today->tm_mday, + today->tm_year + 1900, + today->tm_hour, + today->tm_min, + today->tm_sec); + + Q_vsnprintf(&string[Q_strlen(string)], sizeof(string) - Q_strlen(string), fmt, argptr); + va_end(argptr); + + if (g_psvs.log.net_log_ || firstLog != NULL) + { + if (g_psvs.log.net_log_) + Netchan_OutOfBandPrint(NS_SERVER, g_psvs.log.net_address_, "log %s", string); + + for (list = firstLog; list != NULL; list = list->next) + { + if (sv_logsecret.value == 0.0f) + Netchan_OutOfBandPrint(NS_SERVER, list->log.net_address_, "log %s", string); + + else Netchan_OutOfBandPrint(NS_SERVER, list->log.net_address_, "%c%s%s", S2A_LOGKEY, sv_logsecret.string, string); + } + } + if (g_psvs.log.active && (g_psvs.maxclients > 1 || sv_log_singleplayer.value != 0.0f)) + { + if (mp_logecho.value != 0.0f) + Con_Printf("%s", string); + + if (g_psvs.log.file) + { + if (mp_logfile.value != 0.0f) + FS_FPrintf((FileHandle_t)g_psvs.log.file, "%s", string); + } + } +} + +/* <9a15f> ../engine/sv_log.c:118 */ +void Log_PrintServerVars(void) +{ + cvar_t *var; + if (!g_psvs.log.active) + return; + + Log_Printf("Server cvars start\n"); + for (var = cvar_vars; var != NULL; var = var->next) + { + if (var->flags & FCVAR_SERVER) + Log_Printf("Server cvar \"%s\" = \"%s\"\n", var->name, var->string); + } + Log_Printf("Server cvars end\n"); +} + +/* <9a18e> ../engine/sv_log.c:145 */ +void Log_Close(void) +{ + if (g_psvs.log.file) + { + Log_Printf("Log file closed\n"); + FS_Close((FileHandle_t)g_psvs.log.file); + } + g_psvs.log.file = NULL; +} + +/* <9a1a9> ../engine/sv_log.c:162 */ +void Log_Open(void) +{ + time_t ltime; + struct tm *today; + char szFileBase[MAX_PATH]; + char szTestFile[MAX_PATH]; + int i; + FileHandle_t fp; + char *temp; + + if (!g_psvs.log.active || (sv_log_onefile.value != 0.0f && g_psvs.log.file)) + return; + + if (mp_logfile.value == 0.0f) + Con_Printf("Server logging data to console.\n"); + else + { + Log_Close(); + time(<ime); + today = localtime(<ime); + + temp = Cvar_VariableString("logsdir"); + + if (!temp || Q_strlen(temp) <= 0 || Q_strstr(temp, ":") || Q_strstr(temp, "..")) + Q_snprintf(szFileBase, sizeof(szFileBase), "logs/L%02i%02i", today->tm_mon + 1, today->tm_mday); + + else Q_snprintf(szFileBase, sizeof(szFileBase), "%s/L%02i%02i", temp, today->tm_mon + 1, today->tm_mday); + + for (i = 0; i < 1000; i++) + { + Q_snprintf(szTestFile, sizeof(szTestFile), "%s%03i.log", szFileBase, i); + + COM_FixSlashes(szTestFile); + COM_CreatePath(szTestFile); + + fp = FS_OpenPathID(szTestFile, "r", "GAMECONFIG"); + if (!fp) + { + COM_CreatePath(szTestFile); + fp = FS_OpenPathID(szTestFile, "wt", "GAMECONFIG"); + if (fp) + { + g_psvs.log.file = (void *)fp; + Con_Printf("Server logging data to file %s\n", szTestFile); + Log_Printf("Log file started (file \"%s\") (game \"%s\") (version \"%i/%s/%d\")\n", szTestFile, Info_ValueForKey(Info_Serverinfo(), "*gamedir"), PROTOCOL_VERSION, gpszVersionString, build_number()); + } + return; + } + FS_Close(fp); + } + Con_Printf("Unable to open logfiles under %s\nLogging disabled\n", szFileBase); + g_psvs.log.active = FALSE; + } +} + +/* <9a237> ../engine/sv_log.c:266 */ +void SV_SetLogAddress_f(void) +{ + const char *s; + int nPort; + char szAdr[MAX_PATH]; + netadr_t adr; + + if (Cmd_Argc() != 3) + { + Con_Printf("logaddress: usage\nlogaddress ip port\n"); + if (g_psvs.log.active) + Con_Printf("current: %s\n", NET_AdrToString(g_psvs.log.net_address_)); + return; + } + + nPort = Q_atoi(Cmd_Argv(2)); + if (!nPort) + { + Con_Printf("logaddress: must specify a valid port\n"); + return; + } + + s = Cmd_Argv(1); + if (!s || *s == '\0') + { + Con_Printf("logaddress: unparseable address\n"); + return; + } + + Q_snprintf(szAdr, sizeof(szAdr), "%s:%i", s, nPort); + + if (!NET_StringToAdr(szAdr, &adr)) + { + Con_Printf("logaddress: unable to resolve %s\n", szAdr); + return; + } + + g_psvs.log.net_log_ = TRUE; + memcpy(&g_psvs.log.net_address_, &adr, sizeof(netadr_t)); + Con_Printf("logaddress: %s\n", NET_AdrToString(adr)); +} + +/* <9a28f> ../engine/sv_log.c:321 */ +void SV_AddLogAddress_f(void) +{ + const char *s; + int nPort; + char szAdr[MAX_PATH]; + netadr_t adr; + LOGLIST_T *list; + qboolean found = FALSE; + LOGLIST_T *tmp; + + if (Cmd_Argc() != 3) + { + Con_Printf("logaddress_add: usage\nlogaddress_add ip port\n"); + for (list = firstLog; list != NULL; list = list->next) + Con_Printf("current: %s\n", NET_AdrToString(list->log.net_address_)); + return; + } + + nPort = Q_atoi(Cmd_Argv(2)); + if (!nPort) + { + Con_Printf("logaddress_add: must specify a valid port\n"); + return; + } + + s = Cmd_Argv(1); + if (!s || *s == '\0') + { + Con_Printf("logaddress_add: unparseable address\n"); + return; + } + Q_snprintf(szAdr, sizeof(szAdr), "%s:%i", s, nPort); + + if (!NET_StringToAdr(szAdr, &adr)) + { + Con_Printf("logaddress_add: unable to resolve %s\n", szAdr); + return; + } + + if (firstLog) + { + for (list = firstLog; list != NULL; list = list->next) + { +#ifdef REHLDS_FIXES + //for IPX support + if (NET_CompareAdr(adr, list->log.net_address_)) +#else + if (Q_memcmp(adr.ip, list->log.net_address_.ip, 4) == 0 && adr.port == list->log.net_address_.port) +#endif // REHLDS_FIXES + { + found = TRUE; + break; + } + } + if (found) + { + Con_Printf("logaddress_add: address already in list\n"); + return; + } + tmp = (LOGLIST_T *)Mem_Malloc(sizeof(LOGLIST_T)); + if (!tmp) + { + Con_Printf("logaddress_add: error allocating new node\n"); + return; + } + + tmp->next = NULL; + memcpy(&tmp->log.net_address_, &adr, sizeof(netadr_t)); + + list = firstLog; + + while (list->next) + list = list->next; + + list->next = tmp; + } + else + { + firstLog = (LOGLIST_T *)Mem_Malloc(sizeof(LOGLIST_T)); + if (!firstLog) + { + Con_Printf("logaddress_add: error allocating new node\n"); + return; + } + firstLog->next = NULL; + memcpy(&firstLog->log.net_address_, &adr, sizeof(netadr_t)); + } + + Con_Printf("logaddress_add: %s\n", NET_AdrToString(adr)); +} + +/* <9a345> ../engine/sv_log.c:439 */ +void SV_DelLogAddress_f(void) +{ + const char *s; + int nPort; + char szAdr[MAX_PATH]; + netadr_t adr; + LOGLIST_T *list; + LOGLIST_T *prev; + qboolean found = FALSE; + + if (Cmd_Argc() != 3) + { + Con_Printf("logaddress_del: usage\nlogaddress_del ip port\n"); + for (list = firstLog; list != NULL; list = list->next) + Con_Printf("current: %s\n", NET_AdrToString(list->log.net_address_)); + return; + } + nPort = Q_atoi(Cmd_Argv(2)); + if (!nPort) + { + Con_Printf("logaddress_del: must specify a valid port\n"); + return; + } + + s = Cmd_Argv(1); + if (!s || *s == '\0') + { + Con_Printf("logaddress_del: unparseable address\n"); + return; + } + Q_snprintf(szAdr, sizeof(szAdr), "%s:%i", s, nPort); + if (!NET_StringToAdr(szAdr,&adr)) + { + Con_Printf("logaddress_del: unable to resolve %s\n", szAdr); + return; + } + if (!firstLog) + { + Con_Printf("logaddress_del: No addresses added yet\n"); + return; + } + for(list = firstLog, prev = firstLog; list != NULL; list = list->next) + { +#ifdef REHLDS_FIXES + //for IPX + if (NET_CompareAdr(adr,list->log.net_address_)) +#else + if (Q_memcmp(adr.ip, list->log.net_address_.ip, 4) == 0 && adr.port == list->log.net_address_.port) +#endif // REHLDS_FIXES + { + found = TRUE; + if (list == prev) + { + firstLog = prev->next; + Mem_Free(prev); + } + else + { + prev->next = list->next; + Mem_Free(list); + } + break; + } + prev = list; + } + if (!found) + { + Con_Printf("logaddress_del: Couldn't find address in list\n"); + return; + } + Con_Printf("deleting: %s\n", NET_AdrToString(adr)); +} + +/* <9a3f1> ../engine/sv_log.c:543 */ +void SV_ServerLog_f(void) +{ + if (Cmd_Argc() != 2) + { + Con_Printf("usage: log < on | off >\n"); + + if (g_psvs.log.active) + Con_Printf("currently logging\n"); + + else Con_Printf("not currently logging\n"); + return; + } + + const char *s = Cmd_Argv(1); + if (Q_stricmp(s,"off")) + { + if (Q_stricmp(s, "on")) + Con_Printf("log: unknown parameter %s, 'on' and 'off' are valid\n", s); + else + { + g_psvs.log.active = TRUE; + Log_Open(); + } + } + else if (g_psvs.log.active) + { + Log_Close(); + Con_Printf("Server logging disabled.\n"); + g_psvs.log.active = FALSE; + } +} diff --git a/rehlds/engine/sv_log.h b/rehlds/engine/sv_log.h new file mode 100644 index 0000000..23be360 --- /dev/null +++ b/rehlds/engine/sv_log.h @@ -0,0 +1,59 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SV_LOG_H +#define SV_LOG_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + +/* <9a080> ../engine/sv_log.c:23 */ +typedef struct loglist +{ + server_log_t log; + struct loglist *next; +} LOGLIST_T; + +#ifdef HOOK_ENGINE +#define firstLog (*pfirstLog) +#endif // HOOK_ENGINE + +extern LOGLIST_T *firstLog; + +void Log_Printf(const char *fmt, ...); +void Log_PrintServerVars(void); +void Log_Close(void); +void Log_Open(void); +void SV_SetLogAddress_f(void); +void SV_AddLogAddress_f(void); +void SV_DelLogAddress_f(void); +void SV_ServerLog_f(void); + +#endif // SV_LOG_H diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp new file mode 100644 index 0000000..4beead4 --- /dev/null +++ b/rehlds/engine/sv_main.cpp @@ -0,0 +1,7132 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +/* ../engine/sv_main.c:96 */ +typedef struct full_packet_entities_s +{ + int num_entities; + entity_state_t entities[256]; +} full_packet_entities_t; + +/* ../engine/sv_main.c:102 */ +typedef struct delta_info_s +{ + delta_info_s *next; + char *name; + char *loadfile; + delta_t *delta; +} delta_info_t; + + +int sv_lastnum; + +extra_baselines_t g_sv_instance_baselines; + +delta_t *g_pplayerdelta; +delta_t *g_pentitydelta; +delta_t *g_pcustomentitydelta; +delta_t *g_pclientdelta; +delta_t *g_pweapondelta; + +int hashstrings_collisions; + +char *pr_strings; +qboolean scr_skipupdate; +float scr_centertime_off; +float g_LastScreenUpdateTime; + +globalvars_t gGlobalVariables; +server_static_t g_psvs; +server_t g_psv; + +decalname_t sv_decalnames[512]; +int sv_decalnamecount; + +UserMsg *sv_gpNewUserMsgs; +UserMsg *sv_gpUserMsgs; + +playermove_t g_svmove; + +qboolean g_bOutOfDateRestart; + + +delta_info_t *g_sv_delta; +delta_t *g_peventdelta; + +//int num_servers; + +int gPacketSuppressed; + +char localinfo[MAX_INFO_STRING * 128]; +char localmodels[512][5]; + +ipfilter_t ipfilters[32768]; +int numipfilters; +userfilter_t userfilters[32768]; +int numuserfilters; + + +//cvar_t sv_language; + +//cvar_t laddermode; + +int sv_playermodel; + +//int player_datacounts[32]; +char outputbuf[1400]; + +redirect_t sv_redirected; +netadr_t sv_redirectto; + +// TODO: make one global var with mods enum. +int g_bCS_CZ_Flags_Initialized; +int g_bIsCZero; +int g_bIsCZeroRitual; +int g_bIsTerrorStrike; +int g_bIsTFC; +int g_bIsHL1; +int g_bIsCStrike; + +qboolean allow_cheats; + +/* + * Globals initialization + */ +#ifndef HOOK_ENGINE + +char *gNullString = ""; +int SV_UPDATE_BACKUP = 8; +int SV_UPDATE_MASK = 7; +int giNextUserMsg = 64; + +cvar_t sv_lan = { "sv_lan", "0", 0, 0.0f, NULL }; +cvar_t sv_lan_rate = { "sv_lan_rate", "20000.0", 0, 0.0f, NULL }; +cvar_t sv_aim = { "sv_aim", "1", FCVAR_SERVER | FCVAR_ARCHIVE , 0.0f, NULL }; + +cvar_t sv_skycolor_r = { "sv_skycolor_r", "0", 0, 0.0f, NULL }; +cvar_t sv_skycolor_g = { "sv_skycolor_g", "0", 0, 0.0f, NULL }; +cvar_t sv_skycolor_b = { "sv_skycolor_b", "0", 0, 0.0f, NULL }; +cvar_t sv_skyvec_x = { "sv_skyvec_x", "0", 0, 0.0f, NULL }; +cvar_t sv_skyvec_y = { "sv_skyvec_y", "0", 0, 0.0f, NULL }; +cvar_t sv_skyvec_z = { "sv_skyvec_z", "0", 0, 0.0f, NULL }; + +cvar_t sv_spectatormaxspeed = { "sv_spectatormaxspeed", "500", 0, 0.0f, NULL }; +cvar_t sv_airaccelerate = { "sv_airaccelerate", "10", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_wateraccelerate = { "sv_wateraccelerate", "10", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_waterfriction = { "sv_waterfriction", "1", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_zmax = { "sv_zmax", "4096", FCVAR_SPONLY, 0.0f, NULL }; +cvar_t sv_wateramp = { "sv_wateramp", "0", 0, 0.0f, NULL }; + +cvar_t sv_skyname = { "sv_skyname", "desert", 0, 0.0f, NULL }; +cvar_t mapcyclefile = { "mapcyclefile", "mapcycle.txt", 0, 0.0f, NULL }; +cvar_t motdfile = { "motdfile", "motd.txt", 0, 0.0f, NULL }; +cvar_t servercfgfile = { "servercfgfile", "server.cfg", 0, 0.0f, NULL }; +cvar_t lservercfgfile = { "lservercfgfile", "listenserver.cfg", 0, 0.0f, NULL }; +cvar_t logsdir = { "logsdir", "logs", 0, 0.0f, NULL }; +cvar_t bannedcfgfile = { "bannedcfgfile", "banned.cfg", 0, 0.0f, NULL }; + +int g_userid = 1; + +cvar_t rcon_password = { "rcon_password", "", 0, 0.0f, NULL }; +cvar_t sv_enableoldqueries = { "sv_enableoldqueries", "0", 0, 0.0f, NULL }; + +cvar_t sv_instancedbaseline = { "sv_instancedbaseline", "1", 0, 0.0f, NULL }; +cvar_t sv_contact = { "sv_contact", "", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_maxupdaterate = { "sv_maxupdaterate", "30.0", 0, 0.0f, NULL }; +cvar_t sv_minupdaterate = { "sv_minupdaterate", "10.0", 0, 0.0f, NULL }; +cvar_t sv_filterban = { "sv_filterban", "1", 0, 0.0f, NULL }; +cvar_t sv_minrate = { "sv_minrate", "0", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_maxrate = { "sv_maxrate", "0", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_logrelay = { "sv_logrelay", "0", 0, 0.0f, NULL }; + +cvar_t violence_hblood = { "violence_hblood", "1", 0, 0.0f, NULL }; +cvar_t violence_ablood = { "violence_ablood", "1", 0, 0.0f, NULL }; +cvar_t violence_hgibs = { "violence_hgibs", "1", 0, 0.0f, NULL }; +cvar_t violence_agibs = { "violence_agibs", "1", 0, 0.0f, NULL }; +cvar_t sv_newunit = { "sv_newunit", "0", 0, 0.0f, NULL }; + +cvar_t sv_clienttrace = { "sv_clienttrace", "1", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_timeout = { "sv_timeout", "60", 0, 0.0f, NULL }; +cvar_t sv_failuretime = { "sv_failuretime", "0.5", 0, 0.0f, NULL }; +cvar_t sv_cheats = { "sv_cheats", "0", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_password = { "sv_password", "", FCVAR_SERVER | FCVAR_PROTECTED, 0.0f, NULL }; +cvar_t sv_proxies = { "sv_proxies", "1", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_outofdatetime = { "sv_outofdatetime", "1800", 0, 0.0f, NULL }; +cvar_t mapchangecfgfile = { "mapchangecfgfile", "", 0, 0.0f, NULL }; + +cvar_t sv_allow_download = { "sv_allowdownload", "1", 0, 0.0f, NULL }; +cvar_t sv_send_logos = { "sv_send_logos", "1", 0, 0.0f, NULL }; +cvar_t sv_send_resources = { "sv_send_resources", "1", 0, 0.0f, NULL }; +cvar_t sv_log_singleplayer = { "sv_log_singleplayer", "0", 0, 0.0f, NULL }; +cvar_t sv_logsecret = { "sv_logsecret", "0", 0, 0.0f, NULL }; +cvar_t sv_log_onefile = { "sv_log_onefile", "0", 0, 0.0f, NULL }; +cvar_t sv_logbans = { "sv_logbans", "0", 0, 0.0f, NULL }; +cvar_t sv_allow_upload = { "sv_allowupload", "1", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_max_upload = { "sv_uploadmax", "0.5", FCVAR_SERVER, 0.0f, NULL }; +cvar_t hpk_maxsize = { "hpk_maxsize", "4", FCVAR_ARCHIVE, 0.0f, NULL }; +cvar_t sv_visiblemaxplayers = { "sv_visiblemaxplayers", "-1", 0, 0.0f, NULL }; + +cvar_t max_queries_sec = { "max_queries_sec", "3.0", FCVAR_SERVER | FCVAR_PROTECTED, 0.0f, NULL }; +cvar_t max_queries_sec_global = { "max_queries_sec_global", "30", FCVAR_SERVER | FCVAR_PROTECTED, 0.0f, NULL }; +cvar_t max_queries_window = { "max_queries_window", "60", FCVAR_SERVER | FCVAR_PROTECTED, 0.0f, NULL }; +cvar_t sv_logblocks = { "sv_logblocks", "0", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_downloadurl = { "sv_downloadurl", "", FCVAR_PROTECTED, 0.0f, NULL }; +cvar_t sv_allow_dlfile = { "sv_allow_dlfile", "1", 0, 0.0f, NULL }; +cvar_t sv_version = { "sv_version", "", 0, 0.0f, NULL }; + +cvar_t sv_rcon_minfailures = { "sv_rcon_minfailures", "5", 0, 0.0f, NULL }; +cvar_t sv_rcon_maxfailures = { "sv_rcon_maxfailures", "10", 0, 0.0f, NULL }; +cvar_t sv_rcon_minfailuretime = { "sv_rcon_minfailuretime", "30", 0, 0.0f, NULL }; +cvar_t sv_rcon_banpenalty = { "sv_rcon_banpenalty", "0", 0, 0.0f, NULL }; + +cvar_t scr_downloading = { "scr_downloading", "0", 0, 0.0f, NULL }; + +#else //HOOK_ENGINE + +char *gNullString; +int SV_UPDATE_BACKUP; +int SV_UPDATE_MASK; +int giNextUserMsg; + +cvar_t sv_lan; +cvar_t sv_lan_rate; +cvar_t sv_aim; + +cvar_t sv_skycolor_r; +cvar_t sv_skycolor_g; +cvar_t sv_skycolor_b; +cvar_t sv_skyvec_x; +cvar_t sv_skyvec_y; +cvar_t sv_skyvec_z; + +cvar_t sv_spectatormaxspeed; +cvar_t sv_airaccelerate; +cvar_t sv_wateraccelerate; +cvar_t sv_waterfriction; +cvar_t sv_zmax; +cvar_t sv_wateramp; + +cvar_t sv_skyname; +cvar_t mapcyclefile; +cvar_t motdfile; +cvar_t servercfgfile; +cvar_t lservercfgfile; +cvar_t logsdir; +cvar_t bannedcfgfile; + +int g_userid; + +cvar_t rcon_password; +cvar_t sv_enableoldqueries; + +cvar_t sv_instancedbaseline; +cvar_t sv_contact; +cvar_t sv_maxupdaterate; +cvar_t sv_minupdaterate; +cvar_t sv_filterban; +cvar_t sv_minrate; +cvar_t sv_maxrate; +cvar_t sv_logrelay; + +cvar_t violence_hblood; +cvar_t violence_ablood; +cvar_t violence_hgibs; +cvar_t violence_agibs; +cvar_t sv_newunit; + +cvar_t sv_clienttrace; +cvar_t sv_timeout; +cvar_t sv_failuretime; +cvar_t sv_cheats; +cvar_t sv_password; +cvar_t sv_proxies; +cvar_t sv_outofdatetime; +cvar_t mapchangecfgfile; + +cvar_t sv_allow_download; +cvar_t sv_send_logos; +cvar_t sv_send_resources; +cvar_t sv_log_singleplayer; +cvar_t sv_logsecret; +cvar_t sv_log_onefile; +cvar_t sv_logbans; +cvar_t sv_allow_upload; +cvar_t sv_max_upload; +cvar_t hpk_maxsize; +cvar_t sv_visiblemaxplayers; + +cvar_t max_queries_sec; +cvar_t max_queries_sec_global; +cvar_t max_queries_window; +cvar_t sv_logblocks; +cvar_t sv_downloadurl; +cvar_t sv_allow_dlfile; +cvar_t sv_version; + +cvar_t sv_rcon_minfailures; +cvar_t sv_rcon_maxfailures; +cvar_t sv_rcon_minfailuretime; +cvar_t sv_rcon_banpenalty; + +cvar_t scr_downloading; + +#endif //HOOK_ENGINE + + +/* ../engine/sv_main.c:113 */ +delta_t *SV_LookupDelta(char *name) +{ + delta_info_t *p = g_sv_delta; + + while (p) + { + if (!Q_stricmp(name, p->name)) + { + return p->delta; + } + p = p->next; + } + + Sys_Error(__FUNCTION__ ": Couldn't find delta for %s\n", name); + + return NULL; +} + +/* ../engine/sv_main.c:280 */ +NOXREF void SV_DownloadingModules(void) +{ + NOXREFCHECK; + + char message[] = "Downloading Security Module from Speakeasy.net ...\n"; + Con_Printf(message); + +#ifndef SWDS + // TODO: Possibly some client-side code here +#endif // SWDS +} + +/* ../engine/sv_main.c:310 */ +void SV_GatherStatistics(void) +{ + int players = 0; + + if (g_psvs.next_cleartime < realtime) + { + SV_CountPlayers(&players); + g_psvs.next_cleartime = realtime + 3600.0; + Q_memset(&g_psvs.stats, 0, sizeof(g_psvs.stats)); + g_psvs.stats.maxusers = players; + g_psvs.stats.minusers = players; + return; + } + + if (g_psvs.next_sampletime > realtime) + return; + + SV_CountPlayers(&players); + + g_psvs.stats.num_samples++; + g_psvs.next_sampletime = realtime + 60.0; + g_psvs.stats.cumulative_occupancy += (players * 100.0 / g_psvs.maxclients); + + if (g_psvs.stats.num_samples >= 1) + g_psvs.stats.occupancy = g_psvs.stats.cumulative_occupancy / g_psvs.stats.num_samples; + + if (g_psvs.stats.minusers > players) + g_psvs.stats.minusers = players; + else if (g_psvs.stats.maxusers < players) + g_psvs.stats.maxusers = players; + + if ((g_psvs.maxclients - 1) <= players) + g_psvs.stats.at_capacity++; + if (players <= 1) + g_psvs.stats.at_empty++; + + if (g_psvs.stats.num_samples >= 1) + { + g_psvs.stats.capacity_percent = g_psvs.stats.at_capacity * 100.0 / g_psvs.stats.num_samples; + g_psvs.stats.empty_percent = g_psvs.stats.at_empty * 100.0 / g_psvs.stats.num_samples; + } + + int c = 0; + float v = 0.0f; + client_t *cl = g_psvs.clients; + + for (int i = g_psvs.maxclients; i > 0; i--, cl++) + { + if (cl->active && !cl->fakeclient) + { + c++; + v += cl->latency; + } + } + + if (c) + v = v / c; + + g_psvs.stats.cumulative_latency += v; + if (g_psvs.stats.num_samples >= 1) + g_psvs.stats.average_latency = g_psvs.stats.cumulative_latency / g_psvs.stats.num_samples; + if (g_psvs.stats.num_sessions >= 1) + g_psvs.stats.average_session_len = g_psvs.stats.cumulative_sessiontime / g_psvs.stats.num_sessions; +} + +/* ../engine/sv_main.c:432 */ +void SV_DeallocateDynamicData(void) +{ + if (g_moved_edict) + Mem_Free(g_moved_edict); + if (g_moved_from) + Mem_Free(g_moved_from); + g_moved_edict = NULL; + g_moved_from = NULL; +} + +/* ../engine/sv_main.c:450 */ +void SV_ReallocateDynamicData(void) +{ + if (!g_psv.max_edicts) + { + Con_DPrintf(__FUNCTION__ " with sv.max_edicts == 0\n"); + return; + } + + int nSize = g_psv.max_edicts; + + if (g_moved_edict) + { + Con_Printf("Reallocate on moved_edict\n"); + // TODO: Free memory to prevent mem leaks? + } + g_moved_edict = (edict_t **)Mem_ZeroMalloc(sizeof(edict_t *) * nSize); + + if (g_moved_from) + { + Con_Printf("Reallocate on moved_from\n"); + // TODO: Free memory to prevent mem leaks? + } + g_moved_from = (vec3_t *)Mem_ZeroMalloc(sizeof(vec3_t) * nSize); +} + +/* ../engine/sv_main.c:485 */ +void SV_AllocClientFrames(void) +{ + client_t *cl = g_psvs.clients; + + for (int i = 0; i < g_psvs.maxclientslimit; i++, cl++) + { + if (cl->frames) + { + Con_DPrintf("Allocating over frame pointer?\n"); + // TODO: Free memory to prevent mem leaks? + } + cl->frames = (client_frame_t *)Mem_ZeroMalloc(sizeof(client_frame_t) * SV_UPDATE_BACKUP); + } +} + +/* ../engine/sv_main.c:500 */ +qboolean SV_IsPlayerIndex(int index) +{ + return (index >= 1 && index <= g_psvs.maxclients); +} + +qboolean __declspec(naked) SV_IsPlayerIndex_wrapped(int index) +{ + // Original SV_IsPlayerIndex in swds.dll doesn't modify ecx nor edx. + // During the compilation of original swds.dll compiler was assuming that these registers wouldn't be modified during call to SV_IsPlayerIndex(). + // This is not true for code produced by msvc2013 (which uses ecx even in Release config). That's why we need a wrapper here that preserves ecx and edx before call to reversed SV_IsPlayerIndex(). + __asm + { + mov eax, dword ptr[esp + 4]; + push ecx; + push edx; + push eax; + call SV_IsPlayerIndex; + add esp, 4; + pop edx; + pop ecx; + retn; + } +} + +/* ../engine/sv_main.c:514 */ +void SV_ClearPacketEntities(client_frame_t *frame) +{ + if (frame) + { + if (frame->entities.entities) + Mem_Free(frame->entities.entities); + frame->entities.entities = NULL; + frame->entities.num_entities = 0; + } +} + +/* ../engine/sv_main.c:532 */ +void SV_AllocPacketEntities(client_frame_t *frame, int numents) +{ + if (frame) + { + if (frame->entities.entities) + SV_ClearPacketEntities(frame); + + int allocatedslots = numents; + if (numents < 1) + allocatedslots = 1; + + frame->entities.num_entities = numents; + frame->entities.entities = (entity_state_t *)Mem_ZeroMalloc(sizeof(entity_state_t) * allocatedslots); + } +} + +/* ../engine/sv_main.c:561 */ +void SV_ClearFrames(client_frame_t **frames) +{ + client_frame_t *pframe = *frames; + + if (pframe) + { + for (int i = 0; i < SV_UPDATE_BACKUP; i++, pframe++) + { + SV_ClearPacketEntities(pframe); + pframe->senttime = 0.0; + pframe->ping_time = -1.0f; + } + + Mem_Free(*frames); + *frames = NULL; + } +} + +/* ../engine/sv_main.c:593 */ +void SV_Serverinfo_f(void) +{ + if (Cmd_Argc() == 1) + { + Con_Printf("Server info settings:\n"); + Info_Print(Info_Serverinfo()); + return; + } + if (Cmd_Argc() != 3) + { + Con_Printf("usage: serverinfo [ ]\n"); + return; + } + if (Cmd_Argv(1)[0] == '*') + { + Con_Printf("Star variables cannot be changed.\n"); + return; + } + +#ifdef REHLDS_FIXES + Info_SetValueForKey(Info_Serverinfo(), Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING); // Do it right +#else // REHLDS_FIXES + Info_SetValueForKey(Info_Serverinfo(), Cmd_Argv(1), Cmd_Argv(2), 512); +#endif // REHLDS_FIXES + + cvar_t *var = Cvar_FindVar(Cmd_Argv(1)); + if (var) + { + Z_Free(var->string); + var->string = CopyString((char *)Cmd_Argv(2)); + var->value = Q_atof(var->string); + } + + SV_BroadcastCommand("fullserverinfo \"%s\"\n", Info_Serverinfo()); +} + +/* ../engine/sv_main.c:638 */ +void SV_Localinfo_f(void) +{ + if (Cmd_Argc() == 1) + { + Con_Printf("Local info settings:\n"); + Info_Print(localinfo); + return; + } + if (Cmd_Argc() != 3) + { + Con_Printf("usage: localinfo [ ]\n"); + return; + } + if (Cmd_Argv(1)[0] == '*') + { + Con_Printf("Star variables cannot be changed.\n"); + return; + } + + Info_SetValueForKey(localinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING * 128); +} + +/* ../engine/sv_main.c:672 */ +void SV_User_f(void) +{ + if (!g_psv.active) + { + Con_Printf("Can't 'user', not running a server\n"); + return; + } + if (Cmd_Argc() != 2) + { + Con_Printf("Usage: user \n"); + return; + } + + int uid = Q_atoi(Cmd_Argv(1)); + client_t *cl = g_psvs.clients; + + for (int i = 0; i < g_psvs.maxclients; i++, cl++) + { + if (cl->active || cl->spawned || cl->connected) + { + if (!cl->fakeclient && cl->name[0]) + { + if (cl->userid == uid || !Q_strcmp(cl->name, Cmd_Argv(1))) + { + Info_Print(cl->userinfo); + return; + } + } + } + } + + Con_Printf("User not in server.\n"); +} + +/* ../engine/sv_main.c:721 */ +void SV_Users_f(void) +{ + if (!g_psv.active) + { + Con_Printf("Can't 'users', not running a server\n"); + return; + } + + Con_Printf("userid : uniqueid : name\n"); + Con_Printf("------ : ---------: ----\n"); + + int c = 0; + client_t *cl = g_psvs.clients; + + for (int i = 0; i < g_psvs.maxclients; i++, cl++) + { + if (cl->active || cl->spawned || cl->connected) + { + if (!cl->fakeclient && cl->name[0]) + { + Con_Printf("%6i : %s : %s\n", cl->userid, SV_GetClientIDString(cl), cl->name); + c++; + } + } + } + + Con_Printf("%i users\n", c); +} + +/* ../engine/sv_main.c:762 */ +void SV_CountPlayers(int *clients) +{ + *clients = 0; + client_s *cl = g_psvs.clients; + + for (int i = 0; i < g_psvs.maxclients; i++, cl++) + { + if (cl->active || cl->spawned || cl->connected) + (*clients)++; + } +} + +/* ../engine/sv_main.c:786 */ +void SV_CountProxies(int *proxies) +{ + *proxies = 0; + client_s *cl = g_psvs.clients; + + for (int i = 0; i < g_psvs.maxclients; i++, cl++) + { + if (cl->active || cl->spawned || cl->connected) + { + if (cl->proxy) + (*proxies)++; + } + } +} + +/* ../engine/sv_main.c:810 */ +void SV_FindModelNumbers(void) +{ + sv_playermodel = -1; + + for (int i = 0; i < HL_MODEL_MAX; i++) + { + if (!g_psv.model_precache[i]) + break; + if (!Q_stricmp(g_psv.model_precache[i], "models/player.mdl")) + sv_playermodel = i; + } +} + +/* ../engine/sv_main.c:841 */ +void SV_StartParticle(const vec_t *org, const vec_t *dir, int color, int count) +{ + if (g_psv.datagram.cursize + 16 <= g_psv.datagram.maxsize) + { + MSG_WriteByte(&g_psv.datagram, svc_particle); + MSG_WriteCoord(&g_psv.datagram, org[0]); + MSG_WriteCoord(&g_psv.datagram, org[1]); + MSG_WriteCoord(&g_psv.datagram, org[2]); + + for (int i = 0; i < 3; i++) + { + MSG_WriteChar(&g_psv.datagram, clamp((int)(dir[i] * 16.0f), -128, 127)); + } + + MSG_WriteByte(&g_psv.datagram, count); + MSG_WriteByte(&g_psv.datagram, color); + } +} + +/* ../engine/sv_main.c:887 */ +void SV_StartSound(int recipients, edict_t *entity, int channel, const char *sample, int volume, float attenuation, int fFlags, int pitch) +{ + vec3_t origin; + + for (int i = 0; i < 3; i++) + { + origin[i] = (entity->v.maxs[i] + entity->v.mins[i]) * 0.5f + entity->v.origin[i]; + } + + if (!SV_BuildSoundMsg(entity, channel, sample, volume, attenuation, fFlags, pitch, origin, &g_psv.multicast)) + { + return; + } + + int flags = 0; + if (recipients == 1) + { + flags = MSG_FL_ONE; + } + + qboolean sendPAS = channel != CHAN_STATIC && !(fFlags & SND_FL_STOP); + if (sendPAS) + { + SV_Multicast(entity, origin, flags | MSG_FL_PAS, FALSE); + } + else + { + if (Host_IsSinglePlayerGame()) + SV_Multicast(entity, origin, flags | MSG_FL_BROADCAST, FALSE); + else + SV_Multicast(entity, origin, flags | MSG_FL_BROADCAST, TRUE); + } +} + +/* ../engine/sv_main.c:942 */ +qboolean SV_BuildSoundMsg(edict_t *entity, int channel, const char *sample, int volume, float attenuation, int fFlags, int pitch, const float *origin, sizebuf_t *buffer) +{ + int sound_num; + int field_mask; + + if (volume < 0 || volume > 255) + { + Con_Printf(__FUNCTION__ ": volume = %i", volume); + volume = (volume < 0) ? 0 : 255; + } + if (attenuation < 0.0f || attenuation > 4.0f) + { + Con_Printf(__FUNCTION__ ": attenuation = %f", attenuation); + attenuation = (attenuation < 0.0f) ? 0.0f : 4.0f; + } + if (channel < 0 || channel > 7) + { + Con_Printf(__FUNCTION__ ": channel = %i", channel); + channel = (channel < 0) ? CHAN_AUTO : CHAN_NETWORKVOICE_BASE; + } + if (pitch < 0 || pitch > 255) + { + Con_Printf(__FUNCTION__ ": pitch = %i", pitch); + pitch = (pitch < 0) ? 0 : 255; + } + + field_mask = fFlags; + + if (*sample == '!') + { + field_mask |= SND_FL_SENTENCE; + sound_num = Q_atoi(sample + 1); + if (sound_num >= CVOXFILESENTENCEMAX) + { + Con_Printf(__FUNCTION__ ": invalid sentence number: %s", sample + 1); + return FALSE; + } + } + else if (*sample == '#') + { + field_mask |= SND_FL_SENTENCE; + sound_num = Q_atoi(sample + 1) + CVOXFILESENTENCEMAX; + } + else + { + sound_num = SV_LookupSoundIndex(sample); + if (!sound_num || !g_psv.sound_precache[sound_num]) + { + Con_Printf(__FUNCTION__ ": %s not precached (%d)\n", sample, sound_num); + return FALSE; + } + } + + int ent = NUM_FOR_EDICT(entity); + + if (volume != DEFAULT_SOUND_PACKET_VOLUME) + field_mask |= SND_FL_VOLUME; + if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) + field_mask |= SND_FL_ATTENUATION; + if (pitch != DEFAULT_SOUND_PACKET_PITCH) + field_mask |= SND_FL_PITCH; + if (sound_num > 255) + field_mask |= SND_FL_LARGE_INDEX; + + MSG_WriteByte(buffer, svc_sound); + MSG_StartBitWriting(buffer); + MSG_WriteBits(field_mask, 9); + if (field_mask & SND_FL_VOLUME) + MSG_WriteBits(volume, 8); + if (field_mask & SND_FL_ATTENUATION) + MSG_WriteBits((uint32_t)(attenuation * 64.0f), 8); + MSG_WriteBits(channel, 3); + MSG_WriteBits(ent, 11); + MSG_WriteBits(sound_num, (field_mask & SND_FL_LARGE_INDEX) ? 16 : 8); + MSG_WriteBitVec3Coord(origin); + if (field_mask & SND_FL_PITCH) + MSG_WriteBits(pitch, 8); + MSG_EndBitWriting(buffer); + + return TRUE; +} + +/* ../engine/sv_main.c:1073 */ +int SV_HashString(const char *string, int iBounds) +{ + unsigned int hash = 0; + const char *cc = string; + + while (*cc) + { + hash = tolower(*cc) + 2 * hash; + ++cc; + } + return hash % iBounds; +} + +/* ../engine/sv_main.c:1087 */ +int SV_LookupSoundIndex(const char *sample) +{ + int index; + + if (!g_psv.sound_precache_hashedlookup_built) + { + if (g_psv.state == ss_loading) + { + index = 1; + while (g_psv.sound_precache[index]) + { + if (!Q_stricmp(sample, g_psv.sound_precache[index])) + return index; + index++; + if (index >= HL_SOUND_MAX) + return 0; + } + return 0; + } + SV_BuildHashedSoundLookupTable(); + } + + int starting_index = SV_HashString(sample, 1023); + index = starting_index; + while (g_psv.sound_precache_hashedlookup[index]) + { + if (!Q_stricmp(sample, g_psv.sound_precache[g_psv.sound_precache_hashedlookup[index]])) + return g_psv.sound_precache_hashedlookup[index]; + + index++; + if (index >= HL_SOUND_HASHLOOKUP_SIZE) + index = 0; + if (index == starting_index) + return 0; + } + return 0; +} + +/* ../engine/sv_main.c:1136 */ +void SV_BuildHashedSoundLookupTable(void) +{ + Q_memset(g_psv.sound_precache_hashedlookup, 0, sizeof(g_psv.sound_precache_hashedlookup)); + + for (int sound_num = 0; sound_num < HL_SOUND_MAX; sound_num++) + { + if (!g_psv.sound_precache[sound_num]) + break; + + SV_AddSampleToHashedLookupTable(g_psv.sound_precache[sound_num], sound_num); + } + + g_psv.sound_precache_hashedlookup_built = TRUE; +} + +/* ../engine/sv_main.c:1151 */ +void SV_AddSampleToHashedLookupTable(const char *pszSample, int iSampleIndex) +{ + int starting_index = SV_HashString(pszSample, HL_SOUND_HASHLOOKUP_SIZE); + int index = starting_index; + while (g_psv.sound_precache_hashedlookup[index]) + { + index++; + hashstrings_collisions++; + + if (index >= HL_SOUND_HASHLOOKUP_SIZE) + index = 0; + + if (index == starting_index) + Sys_Error(__FUNCTION__ ": NO FREE SLOTS IN SOUND LOOKUP TABLE"); + } + + g_psv.sound_precache_hashedlookup[index] = iSampleIndex; +} + +/* ../engine/sv_main.c:1180 */ +qboolean SV_ValidClientMulticast(client_t *client, int soundLeaf, int to) +{ + if (Host_IsSinglePlayerGame() || client->proxy) + { + return TRUE; + } + + int destination = to & ~(MSG_FL_ONE); + if (destination == MSG_FL_BROADCAST) + { + return TRUE; + } + + unsigned char* mask; + if (destination == MSG_FL_PVS) + { + mask = CM_LeafPVS(soundLeaf); + } + else + { + if (destination == MSG_FL_PAS) + { + mask = CM_LeafPAS(soundLeaf); + } + else + { + Con_Printf("MULTICAST: Error %d!\n", to); + return FALSE; + } + } + + if (!mask) + { + return TRUE; + } + + int bitNumber = SV_PointLeafnum(client->edict->v.origin); + if (mask[(bitNumber - 1) >> 3] & (1 << ((bitNumber - 1) & 7))) + { + return TRUE; + } + + return FALSE; +} + +/* ../engine/sv_main.c:1240 */ +void SV_Multicast(edict_t *ent, vec_t *origin, int to, qboolean reliable) +{ + client_t *save = host_client; + int leafnum = SV_PointLeafnum(origin); + if (ent && !(host_client && host_client->edict == ent)) + { + for (int i = 0; i < g_psvs.maxclients; i++) + { + if (g_psvs.clients[i].edict == ent) + { + host_client = &g_psvs.clients[i]; + break; + } + } + } + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *client = &g_psvs.clients[i]; + if (!client->active) + continue; + + if ((to & MSG_FL_ONE) && client == host_client) + continue; + + if (ent && ent->v.groupinfo != 0 && client->edict->v.groupinfo != 0) + { + if (g_groupop) + { + if (g_groupop == GROUP_OP_NAND && (ent->v.groupinfo & client->edict->v.groupinfo)) + continue; + } + else + { + if (!(ent->v.groupinfo & client->edict->v.groupinfo)) + continue; + } + } + + if (SV_ValidClientMulticast(client, leafnum, to)) + { + sizebuf_t *pBuffer = &client->netchan.message; + if (!reliable) + pBuffer = &client->datagram; + +#ifdef REHLDS_FIXES + if (pBuffer->cursize + g_psv.multicast.cursize <= pBuffer->maxsize) // TODO: Should it be <= ? I think so. +#else // REHLDS_FIXES + if (pBuffer->cursize + g_psv.multicast.cursize < pBuffer->maxsize) +#endif // REHLDS_FIXES + SZ_Write(pBuffer, g_psv.multicast.data, g_psv.multicast.cursize); + } + else + { + gPacketSuppressed += g_psv.multicast.cursize; + } + } + + SZ_Clear(&g_psv.multicast); + host_client = save; +} + +/* ../engine/sv_main.c:1328 */ +void SV_WriteMovevarsToClient(sizebuf_t *message) +{ + MSG_WriteByte(message, svc_newmovevars); + MSG_WriteFloat(message, movevars.gravity); + MSG_WriteFloat(message, movevars.stopspeed); + MSG_WriteFloat(message, movevars.maxspeed); + MSG_WriteFloat(message, movevars.spectatormaxspeed); + MSG_WriteFloat(message, movevars.accelerate); + MSG_WriteFloat(message, movevars.airaccelerate); + MSG_WriteFloat(message, movevars.wateraccelerate); + MSG_WriteFloat(message, movevars.friction); + MSG_WriteFloat(message, movevars.edgefriction); + MSG_WriteFloat(message, movevars.waterfriction); + MSG_WriteFloat(message, movevars.entgravity); + MSG_WriteFloat(message, movevars.bounce); + MSG_WriteFloat(message, movevars.stepsize); + MSG_WriteFloat(message, movevars.maxvelocity); + MSG_WriteFloat(message, movevars.zmax); + MSG_WriteFloat(message, movevars.waveHeight); + MSG_WriteByte(message, movevars.footsteps != 0); + MSG_WriteFloat(message, movevars.rollangle); + MSG_WriteFloat(message, movevars.rollspeed); + MSG_WriteFloat(message, movevars.skycolor_r); + MSG_WriteFloat(message, movevars.skycolor_g); + MSG_WriteFloat(message, movevars.skycolor_b); + MSG_WriteFloat(message, movevars.skyvec_x); + MSG_WriteFloat(message, movevars.skyvec_y); + MSG_WriteFloat(message, movevars.skyvec_z); + MSG_WriteString(message, movevars.skyName); +} + +/* ../engine/sv_main.c:1365 */ +void SV_WriteDeltaDescriptionsToClient(sizebuf_t *msg) +{ + int i, c; + + delta_description_t nulldesc; + Q_memset(&nulldesc, 0, sizeof(nulldesc)); + + for (delta_info_t *p = g_sv_delta; p != NULL; p = p->next) + { + MSG_WriteByte(msg, svc_deltadescription); + MSG_WriteString(msg, p->name); + MSG_StartBitWriting(msg); + + c = p->delta->fieldCount; + + MSG_WriteBits(c, 16); + + for (i = 0; i < c; i++) + { + DELTA_WriteDelta((byte *)&nulldesc, (byte *)&p->delta->pdd[i], TRUE, (delta_t *)&g_MetaDelta, NULL); + } + + MSG_EndBitWriting(msg); + } +} + +/* ../engine/sv_main.c:1407 */ +void SV_SetMoveVars(void) +{ + movevars.entgravity = 1.0f; + movevars.gravity = sv_gravity.value; + movevars.stopspeed = sv_stopspeed.value; + movevars.maxspeed = sv_maxspeed.value; + movevars.spectatormaxspeed = sv_spectatormaxspeed.value; + movevars.accelerate = sv_accelerate.value; + movevars.airaccelerate = sv_airaccelerate.value; + movevars.wateraccelerate = sv_wateraccelerate.value; + movevars.friction = sv_friction.value; + movevars.edgefriction = sv_edgefriction.value; + movevars.waterfriction = sv_waterfriction.value; + movevars.bounce = sv_bounce.value; + movevars.stepsize = sv_stepsize.value; + movevars.maxvelocity = sv_maxvelocity.value; + movevars.zmax = sv_zmax.value; + movevars.waveHeight = sv_wateramp.value; + movevars.footsteps = sv_footsteps.value; + movevars.rollangle = sv_rollangle.value; + movevars.rollspeed = sv_rollspeed.value; + movevars.skycolor_r = sv_skycolor_r.value; + movevars.skycolor_g = sv_skycolor_g.value; + movevars.skycolor_b = sv_skycolor_b.value; + movevars.skyvec_x = sv_skyvec_x.value; + movevars.skyvec_y = sv_skyvec_y.value; + movevars.skyvec_z = sv_skyvec_z.value; + + Q_strncpy(movevars.skyName, sv_skyname.string, sizeof(movevars.skyName) - 1); + movevars.skyName[sizeof(movevars.skyName) - 1] = 0; +} + +/* ../engine/sv_main.c:1446 */ +void SV_QueryMovevarsChanged(void) +{ + if (movevars.entgravity != 1.0f + || sv_maxspeed.value != movevars.maxspeed + || sv_gravity.value != movevars.gravity + || sv_stopspeed.value != movevars.stopspeed + || sv_spectatormaxspeed.value != movevars.spectatormaxspeed + || sv_accelerate.value != movevars.accelerate + || sv_airaccelerate.value != movevars.airaccelerate + || sv_wateraccelerate.value != movevars.wateraccelerate + || sv_friction.value != movevars.friction + || sv_edgefriction.value != movevars.edgefriction + || sv_waterfriction.value != movevars.waterfriction + || sv_bounce.value != movevars.bounce + || sv_stepsize.value != movevars.stepsize + || sv_maxvelocity.value != movevars.maxvelocity + || sv_zmax.value != movevars.zmax + || sv_wateramp.value != movevars.waveHeight + || sv_footsteps.value != movevars.footsteps + || sv_rollangle.value != movevars.rollangle + || sv_rollspeed.value != movevars.rollspeed + || sv_skycolor_r.value != movevars.skycolor_r + || sv_skycolor_g.value != movevars.skycolor_g + || sv_skycolor_b.value != movevars.skycolor_b + || sv_skyvec_x.value != movevars.skyvec_x + || sv_skyvec_y.value != movevars.skyvec_y + || sv_skyvec_z.value != movevars.skyvec_z + || Q_strcmp(sv_skyname.string, movevars.skyName)) + { + SV_SetMoveVars(); + + client_t *cl = g_psvs.clients; + for (int i = 0; i < g_psvs.maxclients; i++, cl++) + { + if (!cl->fakeclient && (cl->active || cl->spawned || cl->connected)) + SV_WriteMovevarsToClient(&cl->netchan.message); + } + } +} + +void SV_SendServerinfo_mod(sizebuf_t *msg, IGameClient* cl) +{ + SV_SendServerinfo_internal(msg, cl->GetClient()); +} + +void SV_SendServerinfo(sizebuf_t *msg, client_t *client) +{ + g_RehldsHookchains.m_SV_SendServerinfo.callChain(SV_SendServerinfo_mod, msg, GetRehldsApiClient(client)); +} + +/* ../engine/sv_main.c:1499 */ +void SV_SendServerinfo_internal(sizebuf_t *msg, client_t *client) +{ + char message[2048]; + + if (developer.value != 0.0f || g_psvs.maxclients > 1) + { + MSG_WriteByte(msg, svc_print); + Q_snprintf(message, ARRAYSIZE(message), "%c\nBUILD %d SERVER (%i CRC)\nServer # %i\n", 2, build_number(), 0, g_psvs.spawncount); + MSG_WriteString(msg, message); + } + + MSG_WriteByte(msg, svc_serverinfo); + MSG_WriteLong(msg, PROTOCOL_VERSION); + MSG_WriteLong(msg, g_psvs.spawncount); + + int playernum = NUM_FOR_EDICT(client->edict) - 1; + int mungebuffer = g_psv.worldmapCRC; + + COM_Munge3((byte *)&mungebuffer, sizeof(mungebuffer), (-1 - playernum) & 0xFF); + MSG_WriteLong(msg, mungebuffer); + + MSG_WriteBuf(msg, sizeof(g_psv.clientdllmd5), g_psv.clientdllmd5); + MSG_WriteByte(msg, g_psvs.maxclients); + MSG_WriteByte(msg, playernum); + + if (coop.value == 0.0f && deathmatch.value != 0.0f) + MSG_WriteByte(msg, 1); + else + MSG_WriteByte(msg, 0); + + COM_FileBase(com_gamedir, message); + MSG_WriteString(msg, message); + MSG_WriteString(msg, Cvar_VariableString("hostname")); + MSG_WriteString(msg, g_psv.modelname); + + int len = 0; + unsigned char *mapcyclelist = COM_LoadFileForMe(mapcyclefile.string, &len); +#ifdef REHLDS_FIXES + if (mapcyclelist && len) + { + MSG_WriteString(msg, (const char *)mapcyclelist); + } + else + { + MSG_WriteString(msg, "mapcycle failure"); + } + // FIXED: Mem leak. + if (mapcyclelist) + { + COM_FreeFile(mapcyclelist); + } +#else // REHLDS_FIXES + if (mapcyclelist && len) + { + MSG_WriteString(msg, (const char *)mapcyclelist); + COM_FreeFile(mapcyclelist); + } + else + { + MSG_WriteString(msg, "mapcycle failure"); + } +#endif // REHLDS_FIXES + MSG_WriteByte(msg, 0); + + MSG_WriteByte(msg, svc_sendextrainfo); + MSG_WriteString(msg, com_clientfallback); + MSG_WriteByte(msg, allow_cheats); + + SV_WriteDeltaDescriptionsToClient(msg); + SV_SetMoveVars(); + SV_WriteMovevarsToClient(msg); + + MSG_WriteByte(msg, svc_cdtrack); + MSG_WriteByte(msg, gGlobalVariables.cdAudioTrack); + MSG_WriteByte(msg, gGlobalVariables.cdAudioTrack); + MSG_WriteByte(msg, svc_setview); + MSG_WriteShort(msg, playernum + 1); + + client->spawned = FALSE; + client->connected = TRUE; + client->fully_connected = FALSE; +} + +/* ../engine/sv_main.c:1600 */ +void SV_SendResources(sizebuf_t *msg) +{ + unsigned char nullbuffer[32]; + Q_memset(nullbuffer, 0, sizeof(nullbuffer)); + + MSG_WriteByte(msg, svc_resourcerequest); + MSG_WriteLong(msg, g_psvs.spawncount); + MSG_WriteLong(msg, 0); + + if (sv_downloadurl.string && sv_downloadurl.string[0] != 0 && Q_strlen(sv_downloadurl.string) < 129) + { + MSG_WriteByte(msg, svc_resourcelocation); + MSG_WriteString(msg, sv_downloadurl.string); + } + + MSG_WriteByte(msg, svc_resourcelist); + MSG_StartBitWriting(msg); + MSG_WriteBits(g_psv.num_resources, 12); + + resource_t *r = g_psv.resourcelist; + for (int i = 0; i < g_psv.num_resources; i++, r++) + { + MSG_WriteBits(r->type, t_generic); + MSG_WriteBitString(r->szFileName); + MSG_WriteBits(r->nIndex, 12); + MSG_WriteBits(r->nDownloadSize, 24); + MSG_WriteBits(r->ucFlags & (RES_WASMISSING | RES_FATALIFMISSING), 3); + + if (r->ucFlags & RES_CUSTOM) + { + MSG_WriteBitData(r->rgucMD5_hash, sizeof(r->rgucMD5_hash)); + } + + if (!Q_memcmp(r->rguc_reserved, nullbuffer, sizeof(r->rguc_reserved))) + { + MSG_WriteBits(0, 1); + } + else + { + MSG_WriteBits(1, 1); + MSG_WriteBitData(r->rguc_reserved, sizeof(r->rguc_reserved)); + } + } + + SV_SendConsistencyList(msg); + MSG_EndBitWriting(msg); +} + +/* ../engine/sv_main.c:1659 */ +void SV_WriteClientdataToMessage(client_t *client, sizebuf_t *msg) +{ + edict_t *ent = client->edict; + client_frame_t *frame = &client->frames[SV_UPDATE_MASK & client->netchan.outgoing_sequence]; + int bits = (SV_UPDATE_MASK & host_client->delta_sequence); + + frame->senttime = realtime; + frame->ping_time = -1.0f; + + if (client->chokecount) + { + MSG_WriteByte(msg, svc_choke); + client->chokecount = 0; + } + + if (ent->v.fixangle) + { + if (ent->v.fixangle == 2) + { + MSG_WriteByte(msg, svc_addangle); + MSG_WriteHiresAngle(msg, ent->v.avelocity[1]); + ent->v.avelocity[1] = 0; + } + else + { + MSG_WriteByte(msg, svc_setangle); + MSG_WriteHiresAngle(msg, ent->v.angles[0]); + MSG_WriteHiresAngle(msg, ent->v.angles[1]); + MSG_WriteHiresAngle(msg, ent->v.angles[2]); + } + ent->v.fixangle = 0; + } + + Q_memset(&frame->clientdata, 0, sizeof(frame->clientdata)); + gEntityInterface.pfnUpdateClientData(ent, host_client->lw != 0, &frame->clientdata); + + MSG_WriteByte(msg, svc_clientdata); + + if (client->proxy) + return; + + MSG_StartBitWriting(msg); + + clientdata_t baseline; + Q_memset(&baseline, 0, sizeof(baseline)); + + clientdata_t *from = &baseline; + clientdata_t *to = &frame->clientdata; + + if (host_client->delta_sequence == -1) + { + MSG_WriteBits(0, 1); + } + else + { + MSG_WriteBits(1, 1); + MSG_WriteBits(host_client->delta_sequence, 8); + from = &host_client->frames[bits].clientdata; + } + + DELTA_WriteDelta((byte *)from, (byte *)to, TRUE, (delta_t *)g_pclientdelta, NULL); + + if (host_client->lw && gEntityInterface.pfnGetWeaponData(host_client->edict, frame->weapondata)) + { + weapon_data_t wbaseline; + Q_memset(&wbaseline, 0, sizeof(wbaseline)); + + weapon_data_t *fdata = NULL; + weapon_data_t *tdata = frame->weapondata; + + for (int i = 0; i < 64; i++, tdata++) + { + if (host_client->delta_sequence == -1) + fdata = &wbaseline; + else + fdata = &host_client->frames[bits].weapondata[i]; + + if (DELTA_CheckDelta((byte *)fdata, (byte *)tdata, (delta_t *)g_pweapondelta)) + { + MSG_WriteBits(1, 1); + MSG_WriteBits(i, 6); + DELTA_WriteDelta((byte *)fdata, (byte *)tdata, TRUE, (delta_t *)g_pweapondelta, NULL); + } + } + } + + MSG_WriteBits(0, 1); + MSG_EndBitWriting(msg); +} + +/* ../engine/sv_main.c:1789 */ +void SV_WriteSpawn(sizebuf_t *msg) +{ + int i = 0; + client_t *client = g_psvs.clients; + + if (g_psv.loadgame) + { + if (host_client->proxy) + { + Con_Printf("ERROR! Spectator mode doesn't work with saved game.\n"); + return; + } + g_psv.paused = FALSE; + } + else + { + g_psv.state = ss_loading; + ReleaseEntityDLLFields(sv_player); + + Q_memset(&sv_player->v, 0, sizeof(sv_player->v)); + InitEntityDLLFields(sv_player); + + sv_player->v.colormap = NUM_FOR_EDICT(sv_player); + sv_player->v.netname = host_client->name - pr_strings; + + if (host_client->proxy) + sv_player->v.flags |= FL_PROXY; + + gGlobalVariables.time = g_psv.time; + gEntityInterface.pfnClientPutInServer(sv_player); + g_psv.state = ss_active; + } + + SZ_Clear(&host_client->netchan.message); + SZ_Clear(&host_client->datagram); + + MSG_WriteByte(msg, svc_time); + MSG_WriteFloat(msg, g_psv.time); + + host_client->sendinfo = TRUE; + + for (i = 0; i < g_psvs.maxclients; i++, client++) + { + if (client == host_client || client->active || client->connected || client->spawned) + SV_FullClientUpdate(client, msg); + } + + for (i = 0; i < 64; i++) + { + MSG_WriteByte(msg, svc_lightstyle); + MSG_WriteByte(msg, i); + MSG_WriteString(msg, g_psv.lightstyles[i]); + } + + if (!host_client->proxy) + { + MSG_WriteByte(msg, svc_setangle); + MSG_WriteHiresAngle(msg, sv_player->v.v_angle[0]); + MSG_WriteHiresAngle(msg, sv_player->v.v_angle[1]); + MSG_WriteHiresAngle(msg, 0.0f); + SV_WriteClientdataToMessage(host_client, msg); +#ifndef SWDS + if (g_psv.loadgame) + { + // TODO: add client code + } +#endif // SWDS + } + + MSG_WriteByte(msg, svc_signonnum); + MSG_WriteByte(msg, 1); + + host_client->connecttime = 0.0; + host_client->ignorecmdtime = 0.0; + host_client->cmdtime = 0.0; + host_client->active = TRUE; + host_client->spawned = TRUE; + host_client->connected = TRUE; + host_client->fully_connected = FALSE; + + NotifyDedicatedServerUI("UpdatePlayers"); +} + +/* ../engine/sv_main.c:1920 */ +void SV_SendUserReg(sizebuf_t *msg) +{ + for (UserMsg *pMsg = sv_gpNewUserMsgs; pMsg; pMsg = pMsg->next) + { + MSG_WriteByte(msg, svc_newusermsg); + MSG_WriteByte(msg, pMsg->iMsg); + MSG_WriteByte(msg, pMsg->iSize); + MSG_WriteLong(msg, *(int *)&pMsg->szName[0]); + MSG_WriteLong(msg, *(int *)&pMsg->szName[4]); + MSG_WriteLong(msg, *(int *)&pMsg->szName[8]); + MSG_WriteLong(msg, *(int *)&pMsg->szName[12]); + } +} + +/* ../engine/sv_main.c:1953 */ +void SV_New_f(void) +{ + int i; + client_t *client; + unsigned char data[65536]; + sizebuf_t msg; + edict_t *ent; + char szRejectReason[128]; + char szAddress[256]; + char szName[64]; + + Q_memset(&msg, 0, sizeof(msg)); + msg.buffername = "New Connection"; + msg.data = data; + msg.maxsize = sizeof(data); + msg.cursize = 0; + msg.flags = SIZEBUF_CHECK_OVERFLOW; + + // Not valid on the client + if (cmd_source == src_command) + { + return; + } + + if (!host_client->active && host_client->spawned) + { + return; + } + + ent = host_client->edict; + + host_client->connected = TRUE; + host_client->connection_started = realtime; + host_client->m_sendrescount = 0; + + SZ_Clear(&host_client->netchan.message); + SZ_Clear(&host_client->datagram); + + Netchan_Clear(&host_client->netchan); + + SV_SendServerinfo(&msg, host_client); + + if (sv_gpUserMsgs) + { + UserMsg *pTemp = sv_gpNewUserMsgs; + sv_gpNewUserMsgs = sv_gpUserMsgs; + SV_SendUserReg(&msg); + sv_gpNewUserMsgs = pTemp; + } + host_client->hasusrmsgs = TRUE; + + // TODO: set userinfo to be sent? + //host_client->sendinfo = true; + + // If the client was connected, tell the game dll to disconnect him/her. + if ((host_client->active || host_client->spawned) && ent) + { + gEntityInterface.pfnClientDisconnect(ent); + } + + Q_snprintf(szName, sizeof(szName), host_client->name); + Q_snprintf(szAddress, sizeof(szAddress), NET_AdrToString(host_client->netchan.remote_address)); + Q_snprintf(szRejectReason, sizeof(szRejectReason), "Connection rejected by game\n"); + + // Allow the game dll to reject this client. + if (!gEntityInterface.pfnClientConnect(ent, szName, szAddress, szRejectReason)) + { + // Reject the connection and drop the client. + MSG_WriteByte(&host_client->netchan.message, svc_stufftext); + MSG_WriteString(&host_client->netchan.message, va("echo %s\n", szRejectReason)); + SV_DropClient(host_client, FALSE, "Server refused connection because: %s", szRejectReason); + return; + } + + MSG_WriteByte(&msg, svc_stufftext); + MSG_WriteString(&msg, va("fullserverinfo \"%s\"\n", Info_Serverinfo())); + for (i = 0, client = g_psvs.clients; i < g_psvs.maxclients; i++, client++) + { + if (client == host_client || client->active || client->connected || client->spawned) + SV_FullClientUpdate(client, &msg); + } + Netchan_CreateFragments(TRUE, &host_client->netchan, &msg); + Netchan_FragSend(&host_client->netchan); +} + +/* ../engine/sv_main.c:2057 */ +void SV_SendRes_f(void) +{ + unsigned char data[65536]; + sizebuf_t msg; + + Q_memset(&msg, 0, sizeof(msg)); + msg.buffername = "SendResources"; + msg.data = data; + msg.maxsize = sizeof(data); + msg.cursize = 0; + msg.flags = SIZEBUF_CHECK_OVERFLOW; + + if (cmd_source != src_command && (!host_client->spawned || host_client->active)) + { + if (g_psvs.maxclients <= 1 || host_client->m_sendrescount <= 1) + { + host_client->m_sendrescount++; + SV_SendResources(&msg); + Netchan_CreateFragments(true, &host_client->netchan, &msg); + Netchan_FragSend(&host_client->netchan); + } + } +} + +/* ../engine/sv_main.c:2096 */ +void SV_Spawn_f(void) +{ + unsigned char data[65536]; + sizebuf_t msg; + + Q_memset(&msg, 0, sizeof(msg)); + msg.buffername = "Spawning"; + msg.data = data; + msg.maxsize = sizeof(data); + msg.cursize = 0; + msg.flags = SIZEBUF_CHECK_OVERFLOW; + + if (Cmd_Argc() != 3) + { + Con_Printf("spawn is not valid\n"); + return; + } + + host_client->crcValue = Q_atoi(Cmd_Argv(2)); + + COM_UnMunge2((unsigned char *)&host_client->crcValue, 4, (-1 - g_psvs.spawncount) & 0xFF); + + if (cmd_source == src_command) + { + Con_Printf("spawn is not valid from the console\n"); + return; + } + + if (g_pcls.demoplayback || Q_atoi(Cmd_Argv(1)) == g_psvs.spawncount) + { + SZ_Write(&msg, g_psv.signon.data, g_psv.signon.cursize); + SV_WriteSpawn(&msg); + SV_WriteVoiceCodec(&msg); + Netchan_CreateFragments(1, &host_client->netchan, &msg); + Netchan_FragSend(&host_client->netchan); + } + else + { + SV_New_f(); + } +} + +/* ../engine/sv_main.c:2148 */ +void SV_CheckUpdateRate(double *rate) +{ + if (*rate == 0.0) + { + *rate = 0.05; + return; + } + + if (sv_maxupdaterate.value <= 0.001f && sv_maxupdaterate.value != 0.0f) + Cvar_Set("sv_maxupdaterate", "30.0"); + if (sv_minupdaterate.value <= 0.001f && sv_minupdaterate.value != 0.0f) + Cvar_Set("sv_minupdaterate", "1.0"); + + if (sv_maxupdaterate.value != 0.0f) + { + if (*rate < 1.0 / sv_maxupdaterate.value) + *rate = 1.0 / sv_maxupdaterate.value; + } + if (sv_minupdaterate.value != 0.0f) + { + if (*rate > 1.0 / sv_minupdaterate.value) + *rate = 1.0 / sv_minupdaterate.value; + } +} + +/* ../engine/sv_main.c:2189 */ +void SV_RejectConnection(netadr_t *adr, char *fmt, ...) +{ + va_list argptr; + char text[1024]; + va_start(argptr, fmt); + Q_vsnprintf(text, sizeof(text), fmt, argptr); + va_end(argptr); + + SZ_Clear(&net_message); + MSG_WriteLong(&net_message, -1); + MSG_WriteByte(&net_message, '9'); + MSG_WriteString(&net_message, text); + NET_SendPacket(NS_SERVER, net_message.cursize, net_message.data, *adr); + SZ_Clear(&net_message); +} + +/* ../engine/sv_main.c:2213 */ +void SV_RejectConnectionForPassword(netadr_t *adr) +{ + SZ_Clear(&net_message); + MSG_WriteLong(&net_message, -1); + MSG_WriteByte(&net_message, '8'); + MSG_WriteString(&net_message, "BADPASSWORD"); + NET_SendPacket(NS_SERVER, net_message.cursize, net_message.data, *adr); + SZ_Clear(&net_message); +} + +/* ../engine/sv_main.c:2230 */ +int SV_GetFragmentSize(void *state) +{ + int size = 1024; + client_t *cl = (client_t *)state; + + if (cl->active && cl->spawned && cl->connected && cl->fully_connected) + { + size = 256; + const char *val = Info_ValueForKey(cl->userinfo, "cl_dlmax"); + if (val[0] != 0) + { + size = clamp(size, 256, 1024); + } + } + + return size; +} + +/* ../engine/sv_main.c:2266 */ +qboolean SV_FilterUser(USERID_t *userid) +{ + int j = numuserfilters; + for (int i = numuserfilters - 1; i >= 0; i--) + { + userfilter_t *filter = &userfilters[i]; + if (filter->banEndTime == 0.0f || filter->banEndTime > realtime) + { + if (SV_CompareUserID(userid, &filter->userid)) + return (qboolean)sv_filterban.value; + } + else + { + if (i + 1 < j) + memcpy(filter, &filter[1], sizeof(userfilter_t) * (j - i + 1)); + + numuserfilters = --j; + } + } + + return sv_filterban.value == 0.0f ? TRUE : FALSE; +} + +int SV_CheckProtocol(netadr_t *adr, int nProtocol) +{ + return g_RehldsHookchains.m_SV_CheckProtocol.callChain(SV_CheckProtocol_internal, adr, nProtocol); +} + +/* ../engine/sv_main.c:2302 */ +int SV_CheckProtocol_internal(netadr_t *adr, int nProtocol) +{ + if (adr == NULL) + { + Sys_Error(__FUNCTION__ ": Null address\n"); + return FALSE; + } + + if (nProtocol == PROTOCOL_VERSION) + { + return TRUE; + } + + if (nProtocol < PROTOCOL_VERSION) + { + SV_RejectConnection( + adr, + "This server is using a newer protocol ( %i ) than your client ( %i ). You should check for updates to your client.\n", + PROTOCOL_VERSION, + nProtocol); + } + else + { + char *contact = "(no email address specified)"; + if (sv_contact.string[0] != 0) + contact = sv_contact.string; + + SV_RejectConnection( + adr, + "This server is using an older protocol ( %i ) than your client ( %i ). If you believe this server is outdated, you can contact the server administrator at %s.\n", + PROTOCOL_VERSION, + nProtocol, + contact); + } + + return FALSE; +} + +/* ../engine/sv_main.c:2335 */ +typedef struct challenge_s +{ + netadr_t adr; + int challenge; + int time; +} challenge_t; + +challenge_t g_rg_sv_challenges[1024]; + +bool SV_CheckChallenge_api(const netadr_t &adr, int nChallengeValue) { + netadr_t localAdr = adr; + return SV_CheckChallenge(&localAdr, nChallengeValue) != 0; +} + +/* ../engine/sv_main.c:2351 */ +int SV_CheckChallenge(netadr_t *adr, int nChallengeValue) +{ + if (!adr) + Sys_Error(__FUNCTION__ ": Null address\n"); + + if (NET_IsLocalAddress(*adr)) + return 1; + + for (int i = 0; i < MAX_CHALLENGES; i++) + { + if (NET_CompareBaseAdr(net_from, g_rg_sv_challenges[i].adr)) + { + if (nChallengeValue != g_rg_sv_challenges[i].challenge) + { + SV_RejectConnection(adr, "Bad challenge.\n"); + return 0; + } + return 1; + } + } + SV_RejectConnection(adr, "No challenge for your address.\n"); + return 0; +} + +int SV_CheckIPRestrictions(netadr_t *adr, int nAuthProtocol) +{ + return g_RehldsHookchains.m_SV_CheckIPRestrictions.callChain(SV_CheckIPRestrictions_internal, adr, nAuthProtocol); +} + +/* ../engine/sv_main.c:2393 */ +int SV_CheckIPRestrictions_internal(netadr_t *adr, int nAuthProtocol) +{ + if (sv_lan.value || nAuthProtocol != 3) + { + if (nAuthProtocol == 2) + return 1; + + return (sv_lan.value && (NET_CompareClassBAdr(*adr, net_local_adr) || NET_IsReservedAdr(*adr))); + } + return 1; +} + +/* ../engine/sv_main.c:2427 */ +int SV_CheckIPConnectionReuse(netadr_t *adr) +{ + int count = 0; + + client_t *cl = g_psvs.clients; + for (int i = 0; i < g_psvs.maxclients; i++, cl++) + { + if (cl->connected && !cl->fully_connected && NET_CompareBaseAdr(cl->netchan.remote_address, *adr)) + { + count++; + } + } + + if (count > 5) + { + Log_Printf("Too many connect packets from %s\n", NET_AdrToString(*adr)); + return 0; + } + + return 1; +} + +int SV_FinishCertificateCheck(netadr_t *adr, int nAuthProtocol, char *szRawCertificate, char *userinfo) +{ + return g_RehldsHookchains.m_SV_FinishCertificateCheck.callChain(SV_FinishCertificateCheck_internal, adr, nAuthProtocol, szRawCertificate, userinfo); +} + +/* ../engine/sv_main.c:2461 */ +int SV_FinishCertificateCheck_internal(netadr_t *adr, int nAuthProtocol, char *szRawCertificate, char *userinfo) +{ + if (nAuthProtocol != 2) + { + if (Q_stricmp(szRawCertificate, "steam")) + { + SV_RejectConnection(adr, "Expecting STEAM authentication USERID ticket!\n"); + return 0; + } + + return 1; + } + + if (Q_strlen(szRawCertificate) != 32) + { + SV_RejectConnection(adr, "Invalid CD Key.\n"); + return 0; + } + + if (adr->type == NA_LOOPBACK) + { + return 1; + } + + const char *val = Info_ValueForKey(userinfo, "*hltv"); + + if (val[0] == 0 || Q_atoi(val) != 1) + { + SV_RejectConnection(adr, "Invalid CD Key.\n"); + return 0; + } + + return 1; +} + +int SV_CheckKeyInfo(netadr_t *adr, char *protinfo, short unsigned int *port, int *pAuthProtocol, char *pszRaw, char *cdkey) +{ + return g_RehldsHookchains.m_SV_CheckKeyInfo.callChain(SV_CheckKeyInfo_internal, adr, protinfo, port, pAuthProtocol, pszRaw, cdkey); +} + +/* ../engine/sv_main.c:2527 */ +int SV_CheckKeyInfo_internal(netadr_t *adr, char *protinfo, short unsigned int *port, int *pAuthProtocol, char *pszRaw, char *cdkey) +{ + const char *s = Info_ValueForKey(protinfo, "prot"); + int nAuthProtocol = Q_atoi(s); + + if (nAuthProtocol <= 0 || nAuthProtocol > 4) + { + SV_RejectConnection(adr, "Invalid connection.\n"); + return 0; + } + + s = Info_ValueForKey(protinfo, "raw"); + + if (s[0] == 0 || (nAuthProtocol == 2 && Q_strlen(s) != 32)) + { + SV_RejectConnection(adr, "Invalid authentication certificate length.\n"); + return 0; + } + + Q_strcpy(pszRaw, s); + + if (nAuthProtocol != 2) + { + s = Info_ValueForKey(protinfo, "cdkey"); + + if (Q_strlen(s) != 32) + { + SV_RejectConnection(adr, "Invalid hashed CD key.\n"); + return 0; + } + } + + Q_snprintf(cdkey, 64, "%s", s); + *pAuthProtocol = nAuthProtocol; + *port = Q_atoi("27005"); + + return 1; +} + +/* ../engine/sv_main.c:2590 */ +int SV_CheckForDuplicateSteamID(client_t *client) +{ + if (sv_lan.value != 0.0f) + return -1; + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + + if (!cl->connected || cl->fakeclient || cl == client) + continue; + + if (cl->network_userid.idtype != AUTH_IDTYPE_STEAM && cl->network_userid.idtype != AUTH_IDTYPE_VALVE) + continue; + + if (SV_CompareUserID(&client->network_userid, &cl->network_userid)) + return i; + } + + return -1; +} + +/* ../engine/sv_main.c:2639 */ +int SV_CheckForDuplicateNames(char *userinfo, qboolean bIsReconnecting, int nExcludeSlot) +{ + const char *val; + int i; + client_t *client; + int dupc; + char newname[MAX_NAME]; + int retval = 0; + + // TODO: Refactor names checking in SV_CheckForDuplicateNames, SV_CheckUserInfo and SV_ExtractFromUserinfo +#ifdef REHLDS_FIXES + char rawname[MAX_NAME]; + + val = Info_ValueForKey(userinfo, "name"); + Q_strncpy(rawname, val, sizeof(rawname) - 1); + rawname[sizeof(rawname) - 1] = 0; + + // Fix name to not start with '#', so it will not resemble userid + for (char *p = rawname; *p == '#'; p++) *p = ' '; + + TrimSpace(rawname, newname); + + if (!Q_UnicodeValidate(newname)) + { + Q_UnicodeRepair(newname); + } + + if (newname[0] == 0 || !Q_stricmp(newname, "console") || Q_strstr(newname, "..") != NULL) + { + Info_SetValueForKey(userinfo, "name", "unnamed", MAX_INFO_STRING); + val = Info_ValueForKey(userinfo, "name"); + retval = 1; + } +#else // REHLDS_FIXES + val = Info_ValueForKey(userinfo, "name"); + + if (val == NULL || val[0] == 0 || Q_strstr(val, "..") != NULL) + { + Info_SetValueForKey(userinfo, "name", "unnamed", MAX_INFO_STRING); + return 1; + } +#endif // REHLDS_FIXES + + dupc = 1; + while (true) + { + client = g_psvs.clients; + + i = 0; + while (!client->connected || (i == nExcludeSlot && bIsReconnecting) || Q_stricmp(client->name, val)) + { + client++; + i++; + if (i >= g_psvs.maxclients) + return retval; + } + + if (val[0] == '(') + { + if (val[2] == ')') + val += 3; + else if (val[3] == ')') + val += 4; + } + + Q_snprintf(newname, sizeof(newname), "(%d)%-0.*s", dupc, 28, val); +#ifdef REHLDS_FIXES + // Fix possibly incorrectly cut UTF8 chars + if (!Q_UnicodeValidate(newname)) + { + Q_UnicodeRepair(newname); + } +#endif // REHLDS_FIXES + Info_SetValueForKey(userinfo, "name", newname, MAX_INFO_STRING); + + retval = 1; + dupc++; + + val = Info_ValueForKey(userinfo, "name"); + } + + return retval; +} + +/* ../engine/sv_main.c:2710 */ +int SV_CheckUserInfo(netadr_t *adr, char *userinfo, qboolean bIsReconnecting, int nReconnectSlot, char *name) +{ + const char *s; + char *pChar; + char newname[MAX_NAME]; + int proxies; + int i; + + if (!NET_IsLocalAddress(*adr)) + { + if (sv_password.string[0] != 0 && Q_stricmp(sv_password.string, "none") && Q_strcmp(sv_password.string, Info_ValueForKey(userinfo, "password"))) + { + Con_Printf("%s: password failed\n", NET_AdrToString(*adr)); + SV_RejectConnectionForPassword(adr); + + return 0; + } + } + + i = strlen(userinfo); + if (i <= 4 || strstr(userinfo, "\\\\") || userinfo[i - 1] == '\\') + { + SV_RejectConnection(adr, "Unknown HLTV client type.\n"); + + return 0; + } + + Info_RemoveKey(userinfo, "password"); + + s = Info_ValueForKey(userinfo, "name"); + if (Q_strlen(s) > 0) + { + Q_strncpy(newname, s, sizeof(newname) - 1); + newname[sizeof(newname) - 1] = 0; + } + else + { + Q_strcpy(newname, "unnamed"); + } + + // TODO: Refactor names checking in SV_CheckForDuplicateNames, SV_CheckUserInfo and SV_ExtractFromUserinfo + for (pChar = newname; *pChar; pChar++) + { + if (*pChar == '%' || *pChar == '&') + *pChar = ' '; + } + + for (pChar = newname; *pChar == '#'; pChar++) + { + *pChar = ' '; + } + + TrimSpace(newname, name); + + if (!Q_UnicodeValidate(name)) + { + Q_UnicodeRepair(name); + } + + Info_SetValueForKey(userinfo, "name", name, MAX_INFO_STRING); + + if (SV_CheckForDuplicateNames(userinfo, bIsReconnecting, nReconnectSlot)) + { + Q_strncpy(name, Info_ValueForKey(userinfo, "name"), MAX_NAME - 1); + name[MAX_NAME - 1] = 0; + } + + s = Info_ValueForKey(userinfo, "*hltv"); + + if (!Q_strlen(s)) + return 1; + + switch (Q_atoi(s)) + { + case 0: + return 1; + + case 1: + SV_CountProxies(&proxies); + if (proxies >= sv_proxies.value && !bIsReconnecting) + { + SV_RejectConnection(adr, "Proxy slots are full.\n"); + return 0; + } + return 1; + + case 3: + SV_RejectConnection(adr, "Please connect to HLTV master proxy.\n"); + return 0; + + default: + SV_RejectConnection(adr, "Unknown HLTV client type.\n"); + return 0; + } +} + +/* ../engine/sv_main.c:2822 */ +int SV_FindEmptySlot(netadr_t *adr, int *pslot, client_t ** ppClient) +{ + if (g_psvs.maxclients > 0) + { + int slot; + client_t *client = g_psvs.clients; + + for (slot = 0; slot < g_psvs.maxclients; slot++, client++) + { + if (!client->active && !client->spawned && !client->connected) + break; + } + + if (slot < g_psvs.maxclients) + { + *pslot = slot; + *ppClient = client; + return 1; + } + } + + SV_RejectConnection(adr, "Server is full.\n"); + return 0; +} + +void SV_ConnectClient(void) +{ + g_RehldsHookchains.m_SV_ConnectClient.callChain(SV_ConnectClient_internal); +} + +/* ../engine/sv_main.c:2859 */ +void SV_ConnectClient_internal(void) +{ + client_t *client; + netadr_t adr; + int nClientSlot; + char userinfo[1024]; + char protinfo[1024]; + char cdkey[64]; + const char *s; + char name[32]; + char szRawCertificate[512]; + int nAuthProtocol; + short unsigned int port; + qboolean reconnect; + qboolean bIsSecure; + + client = NULL; + memcpy(&adr, &net_from, sizeof(adr)); + nAuthProtocol = -1; + reconnect = FALSE; + port = Q_atoi("27005"); + if (Cmd_Argc() < 5) + { + SV_RejectConnection(&adr, "Insufficient connection info\n"); + return; + } + + if (!SV_CheckProtocol(&adr, Q_atoi(Cmd_Argv(1)))) + return; + + if (!SV_CheckChallenge(&adr, Q_atoi(Cmd_Argv(2)))) + return; + + Q_memset(szRawCertificate, 0, sizeof(szRawCertificate)); + s = Cmd_Argv(3); + if (!Info_IsValid(s)) + { + SV_RejectConnection(&adr, "Invalid protinfo in connect command\n"); + return; + } + + Q_strncpy(protinfo, s, sizeof(protinfo) - 1); + protinfo[sizeof(protinfo) - 1] = 0; + if (!SV_CheckKeyInfo(&adr, protinfo, &port, &nAuthProtocol, szRawCertificate, cdkey)) + return; + + if (!SV_CheckIPRestrictions(&adr, nAuthProtocol)) + { + SV_RejectConnection(&adr, "LAN servers are restricted to local clients (class C).\n"); + return; + } + + s = Cmd_Argv(4); + if (Q_strlen(s) > 256 || !Info_IsValid(s)) + { + SV_RejectConnection(&adr, "Invalid userinfo in connect command\n"); + return; + } + Q_strncpy(userinfo, s, sizeof(userinfo) - 1); + userinfo[sizeof(userinfo) - 1] = 0; + if (Master_IsLanGame() || nAuthProtocol == 2 || nAuthProtocol == 3) + { + for (nClientSlot = 0; nClientSlot < g_psvs.maxclients; nClientSlot++) + { + client = &g_psvs.clients[nClientSlot]; + if (NET_CompareAdr(adr, client->netchan.remote_address)) + { + reconnect = TRUE; + break; + } + } + } + + if (!SV_CheckUserInfo(&adr, userinfo, reconnect, nClientSlot, name)) + return; + + if (!SV_FinishCertificateCheck(&adr, nAuthProtocol, szRawCertificate, userinfo)) + return; + + if (reconnect) + { + Steam_NotifyClientDisconnect(client); + if ((client->active || client->spawned) && client->edict) + gEntityInterface.pfnClientDisconnect(client->edict); + + Con_Printf("%s:reconnect\n", NET_AdrToString(adr)); + } + else + { + if (!SV_FindEmptySlot(&adr, &nClientSlot, &client)) + return; + } + + if (!SV_CheckIPConnectionReuse(&adr)) + return; + + host_client = client; + client->userid = g_userid++; + if (nAuthProtocol == 3) + { + char szSteamAuthBuf[1024]; + int len = net_message.cursize - msg_readcount; + if (net_message.cursize - msg_readcount <= 0 || len >= sizeof(szSteamAuthBuf)) + { + SV_RejectConnection(&adr, "STEAM certificate length error! %i/%i\n", net_message.cursize - msg_readcount, sizeof(szSteamAuthBuf)); + return; + } + memcpy(szSteamAuthBuf, &net_message.data[msg_readcount], len); + client->network_userid.clientip = *(uint32_t *)&adr.ip[0]; + if (adr.type == NA_LOOPBACK) + { + if (sv_lan.value <= 0.0f) + client->network_userid.clientip = *(uint32_t *)&adr.ip[0]; + else + client->network_userid.clientip = 0x7F000001; //127.0.0.1 + } + + client->netchan.remote_address.port = adr.port ? adr.port : port; + if (!Steam_NotifyClientConnect(client, szSteamAuthBuf, len)) + { + if (sv_lan.value == 0.0f) + { + SV_RejectConnection(&adr, "STEAM validation rejected\n"); + return; + } + host_client->network_userid.idtype = AUTH_IDTYPE_STEAM; + host_client->network_userid.m_SteamID = 0; + } + } + else + { + if (nAuthProtocol != 2) + { + SV_RejectConnection(&adr, "Invalid authentication type\n"); + return; + } + + const char* val = Info_ValueForKey(userinfo, "*hltv"); + if (!Q_strlen(val)) + { + SV_RejectConnection(&adr, "Invalid validation type\n"); + return; + } + if (Q_atoi(val) != 1) + { + SV_RejectConnection(&adr, "Invalid validation type\n"); + return; + } + host_client->network_userid.idtype = AUTH_IDTYPE_LOCAL; + host_client->network_userid.m_SteamID = 0; + host_client->network_userid.clientip = *(uint32_t *)&adr.ip[0]; + Steam_NotifyBotConnect(client); + } + + SV_ClearResourceLists(host_client); + SV_ClearFrames(&host_client->frames); + + host_client->frames = (client_frame_t *)Mem_ZeroMalloc(sizeof(client_frame_t) * SV_UPDATE_BACKUP); + host_client->resourcesneeded.pPrev = &host_client->resourcesneeded; + host_client->resourcesneeded.pNext = &host_client->resourcesneeded; + host_client->resourcesonhand.pPrev = &host_client->resourcesonhand; + host_client->resourcesonhand.pNext = &host_client->resourcesonhand; + host_client->edict = EDICT_NUM(nClientSlot + 1); + + if (g_modfuncs.m_pfnConnectClient) + g_modfuncs.m_pfnConnectClient(nClientSlot); + + Netchan_Setup(NS_SERVER, &host_client->netchan, adr, client - g_psvs.clients, client, SV_GetFragmentSize); + host_client->next_messageinterval = 5.0; + host_client->next_messagetime = realtime + 0.05; + host_client->delta_sequence = -1; + Q_memset(&host_client->lastcmd, 0, sizeof(usercmd_t)); + host_client->nextping = -1.0; + if (host_client->netchan.remote_address.type == NA_LOOPBACK) + { + Con_DPrintf("Local connection.\n"); + } + else + { + Con_DPrintf("Client %s connected\nAdr: %s\n", name, NET_AdrToString(host_client->netchan.remote_address)); + } + Q_strncpy(host_client->hashedcdkey, cdkey, 32); + + host_client->hashedcdkey[32] = 0; + host_client->active = FALSE; + host_client->spawned = FALSE; + host_client->connected = TRUE; + host_client->uploading = FALSE; + host_client->fully_connected = FALSE; + + bIsSecure = Steam_GSBSecure(); + Netchan_OutOfBandPrint(NS_SERVER, adr, "%c %i \"%s\" %i %i", 66, host_client->userid, NET_AdrToString(host_client->netchan.remote_address), bIsSecure, build_number()); + Log_Printf("\"%s<%i><%s><>\" connected, address \"%s\"\n", name, host_client->userid, SV_GetClientIDString(host_client), NET_AdrToString(host_client->netchan.remote_address)); + Q_strncpy(host_client->userinfo, userinfo, MAX_INFO_STRING); + host_client->userinfo[MAX_INFO_STRING - 1] = 0; + + SV_ExtractFromUserinfo(host_client); + Info_SetValueForStarKey(host_client->userinfo, "*sid", va("%I64d", host_client->network_userid.m_SteamID), MAX_INFO_STRING); + + host_client->datagram.flags = 1; + host_client->datagram.data = (byte *)host_client->datagram_buf; + host_client->datagram.maxsize = sizeof(host_client->datagram_buf); + host_client->datagram.buffername = host_client->name; + host_client->sendinfo_time = 0.0f; + + g_RehldsHookchains.m_ClientConnected.callChain(NULL, GetRehldsApiClient(host_client)); +} + +/* ../engine/sv_main.c:3179 */ +void SVC_Ping(void) +{ + char data[6] = "\xff\xff\xff\xffj"; + NET_SendPacket(NS_SERVER, sizeof(data), data, net_from); +} + +/* ../engine/sv_main.c:3208 */ +void SVC_GetChallenge(void) +{ + int i; + int oldest = 0; + int oldestTime = 0x7FFFFFFFu; + char data[1024]; + qboolean steam = FALSE; + + if (Cmd_Argc() == 2 && !Q_stricmp(Cmd_Argv(1), "steam")) + { + steam = TRUE; + } + + for (i = 0; i < MAX_CHALLENGES; i++) + { + if (NET_CompareBaseAdr(net_from, g_rg_sv_challenges[i].adr)) + break; + if (g_rg_sv_challenges[i].time < oldestTime) + { + oldest = i; + oldestTime = g_rg_sv_challenges[i].time; + } + } + + if (i == MAX_CHALLENGES) + { + i = oldest; + g_rg_sv_challenges[oldest].challenge = (RandomLong(0, 0x8FFFu) << 16) | RandomLong(0, 0xFFFFu); + g_rg_sv_challenges[oldest].adr = net_from; + g_rg_sv_challenges[oldest].time = realtime; + } + if (steam) + Q_snprintf(data, sizeof(data), "\xFF\xFF\xFF\xFF%c00000000 %u 3 %I64i %d\n", S2C_CHALLENGE, g_rg_sv_challenges[i].challenge, Steam_GSGetSteamID(), Steam_GSBSecure()); + else + { + Con_DPrintf("Server requiring authentication\n"); + Q_snprintf(data, sizeof(data), "\xFF\xFF\xFF\xFF%c00000000 %u 2\n", S2C_CHALLENGE, g_rg_sv_challenges[i].challenge); + } + + // Give 3-rd party plugins a chance to modify challenge response + g_RehldsHookchains.m_SVC_GetChallenge_mod.callChain(NULL, data, g_rg_sv_challenges[i].challenge); + NET_SendPacket(NS_SERVER, Q_strlen(data) + 1, data, net_from); +} + +/* ../engine/sv_main.c:3292 */ +void SVC_ServiceChallenge(void) +{ + int i; + int oldest = 0; + int oldestTime = 0x7FFFFFFFu; + char data[128]; + const char *type; + + if (Cmd_Argc() != 2) + return; + + type = Cmd_Argv(1); + if (!type) + return; + + if (!type[0] || Q_stricmp(type, "rcon")) + return; + + for (i = 0; i < MAX_CHALLENGES; i++) + { + if (NET_CompareBaseAdr(net_from, g_rg_sv_challenges[i].adr)) + break; + + if (g_rg_sv_challenges[i].time < oldestTime) + { + oldestTime = g_rg_sv_challenges[i].time; + oldest = i; + } + } + if (i == MAX_CHALLENGES) + { + g_rg_sv_challenges[oldest].challenge = (RandomLong(0, 36863) << 16) | (RandomLong(0, 65535)); + g_rg_sv_challenges[oldest].adr = net_from; + g_rg_sv_challenges[oldest].time = (int)realtime; + i = oldest; + } + Q_snprintf(data, sizeof(data), "%c%c%c%cchallenge %s %u\n", 255, 255, 255, 255, type, g_rg_sv_challenges[i].challenge); + + NET_SendPacket(NS_SERVER, Q_strlen(data) + 1, data, net_from); +} + +/* ../engine/sv_main.c:3346 */ +void SV_ResetModInfo(void) +{ + FileHandle_t hLibListFile; + unsigned int nFileSize; + char *pszInputStream; + int nBytesRead; + char *pStreamPos; + char szDllListFile[260]; + char szValue[256]; + char szKey[64]; + + Q_memset(&gmodinfo, 0, sizeof(modinfo_t)); + gmodinfo.version = 1; + gmodinfo.svonly = TRUE; + gmodinfo.num_edicts = MAX_EDICTS; + + Q_snprintf(szDllListFile, sizeof(szDllListFile), "%s", "liblist.gam"); + hLibListFile = FS_Open(szDllListFile, "rb"); + if (!hLibListFile) + return; + + nFileSize = FS_Size(hLibListFile); + if (!nFileSize || (signed int)nFileSize > 256 * 1024) + { + Sys_Error("Game listing file size is bogus [%s: size %i]", "liblist.gam", nFileSize); + } + + pszInputStream = (char *)Mem_Malloc(nFileSize + 1); + if (!pszInputStream) + { + Sys_Error("Could not allocate space for game listing file of %i bytes", nFileSize + 1); + } + + nBytesRead = FS_Read(pszInputStream, nFileSize, 1, hLibListFile); + if (nBytesRead != nFileSize) + { + Sys_Error("Error reading in game listing file, expected %i bytes, read %i", nFileSize, nBytesRead); + } + + pszInputStream[nFileSize] = 0; + pStreamPos = pszInputStream; + com_ignorecolons = TRUE; + while (1) + { + pStreamPos = COM_Parse(pStreamPos); + if (com_token[0] == 0) + break; + Q_strncpy(szKey, com_token, sizeof(szKey) - 1); + szKey[sizeof(szKey) - 1] = 0; + pStreamPos = COM_Parse(pStreamPos); + Q_strncpy(szValue, com_token, sizeof(szValue) - 1); + szValue[sizeof(szValue) - 1] = 0; + + if (Q_stricmp(szKey, "gamedll")) + DLL_SetModKey(&gmodinfo, szKey, szValue); + } + + com_ignorecolons = FALSE; + Mem_Free(pszInputStream); + FS_Close(hLibListFile); +} + +/* ../engine/sv_main.c:3431 */ +int SV_GetFakeClientCount(void) +{ + int i; + int fakeclients = 0; + + for (i = 0; i < g_psvs.maxclients; i++) + { + client_t *client = &g_psvs.clients[i]; + + if (client->fakeclient) + fakeclients++; + } + return fakeclients; +} + +/* ../engine/sv_main.c:3445 */ +NOXREF qboolean SV_GetModInfo(char *pszInfo, char *pszDL, int *version, int *size, qboolean *svonly, qboolean *cldll, char *pszHLVersion) +{ + if (gmodinfo.bIsMod) + { + Q_strcpy(pszInfo, gmodinfo.szInfo); + Q_strcpy(pszDL, gmodinfo.szDL); + Q_strcpy(pszHLVersion, gmodinfo.szHLVersion); + + *version = gmodinfo.version; + *size = gmodinfo.size; + *svonly = gmodinfo.svonly; + *cldll = gmodinfo.cldll; + } + else + { + Q_strcpy(pszInfo, ""); + Q_strcpy(pszDL, ""); + Q_strcpy(pszHLVersion, ""); + + *version = 1; + *size = 0; + *svonly = TRUE; + *cldll = FALSE; + } + return gmodinfo.bIsMod; +} + +/* ../engine/sv_main.c:3479 */ +NOXREF qboolean RequireValidChallenge(netadr_t* /*adr*/) +{ + return sv_enableoldqueries.value == 0.0f; +} + +/* ../engine/sv_main.c:3490 */ +NOXREF qboolean ValidInfoChallenge(netadr_t *adr, const char *nugget) +{ + if (nugget && g_psv.active && g_psvs.maxclients > 1) + { + if (RequireValidChallenge(adr)) + return Q_stricmp(nugget, "Source Engine Query") == 0; + return TRUE; + } + return FALSE; +} + +/* ../engine/sv_main.c:3510 */ +NOXREF int GetChallengeNr(netadr_t *adr) +{ + int oldest = 0; + int oldestTime = 0x7FFFFFFFu; + int i; + + for (i = 0; i < MAX_CHALLENGES; i++) + { + if (NET_CompareBaseAdr(*adr, g_rg_sv_challenges[i].adr)) + break; + + if (g_rg_sv_challenges[i].time < oldestTime) + { + oldestTime = g_rg_sv_challenges[i].time; + oldest = i; + } + } + if (i == MAX_CHALLENGES) + { + g_rg_sv_challenges[oldest].challenge = RandomLong(0, 65535) | (RandomLong(0, 36863) << 16); + g_rg_sv_challenges[oldest].adr = net_from; + g_rg_sv_challenges[oldest].time = realtime; + i = oldest; + } + return g_rg_sv_challenges[i].challenge; +} + +/* ../engine/sv_main.c:3546 */ +NOXREF qboolean CheckChallengeNr(netadr_t *adr, int nChallengeValue) +{ + int i; + if (nChallengeValue == -1 || adr == NULL) + return FALSE; + + for (i = 0; i < MAX_CHALLENGES; i++) + { + if (NET_CompareBaseAdr(*adr, g_rg_sv_challenges[i].adr)) + { + if (g_rg_sv_challenges[i].challenge == nChallengeValue) + { + if (g_rg_sv_challenges[i].time + 3600.0f >= realtime) + return TRUE; + } + return FALSE; + } + } + return FALSE; +} + +/* ../engine/sv_main.c:3589 */ +NOXREF void ReplyServerChallenge(netadr_t *adr) +{ + char buffer[16]; + sizebuf_t buf; + + buf.buffername = "SVC_Challenge"; + buf.data = (byte *)buffer; + buf.maxsize = sizeof(buffer); + buf.cursize = 0; + buf.flags = SIZEBUF_ALLOW_OVERFLOW; + + MSG_WriteLong(&buf, 0xffffffff); + MSG_WriteByte(&buf, 65); + MSG_WriteLong(&buf, GetChallengeNr(adr)); + NET_SendPacket(NS_SERVER, buf.cursize, (char *)buf.data, *adr); +} + +/* ../engine/sv_main.c:3615 */ +NOXREF qboolean ValidChallenge(netadr_t *adr, int challengeNr) +{ + if (!g_psv.active) + return FALSE; + + if (g_psvs.maxclients <= 1) + return FALSE; + + if (!RequireValidChallenge(adr) || CheckChallengeNr(adr, challengeNr)) + return TRUE; + + ReplyServerChallenge(adr); + return FALSE; +} + +/* ../engine/sv_main.c:3645 */ +NOXREF void SVC_InfoString(void) +{ + int i; + int count = 0; + int proxy = 0; + sizebuf_t buf; + unsigned char data[1400]; + char address[256]; + char gd[260]; + char info[2048]; + int iHasPW = 0; + char szOS[2]; + +#ifdef _WIN32 + if (noip && noipx) + return; +#else + if (noip) + return; +#endif // _WIN32 + + if (!g_psv.active) + return; + + buf.buffername = "SVC_InfoString"; + buf.data = data; + buf.maxsize = sizeof(data); + buf.cursize = 0; + buf.flags = SIZEBUF_ALLOW_OVERFLOW; + + for (i = 0; i < g_psvs.maxclients; i++) + { + client_t *client = &g_psvs.clients[i]; + if (client->active || client->spawned || client->connected) + { + if (client->proxy) + proxy++; + else + count++; + } + } + + address[0] = 0; + +#ifdef _WIN32 + if (noip && !noipx) + Q_strncpy(address, NET_AdrToString(net_local_ipx_adr), 255); + else + Q_strncpy(address, NET_AdrToString(net_local_adr), 255); + + Q_strcpy(szOS, "w"); +#else + Q_strncpy(address, NET_AdrToString(net_local_adr), 255); + Q_strcpy(szOS, "l"); + +#endif // _WIN32 + + address[255] = 0; + + info[0] = 0; + + if (*sv_password.string) + iHasPW = Q_stricmp(sv_password.string, "none") != 0; + + Info_SetValueForKey(info, "protocol", va("%i", PROTOCOL_VERSION), sizeof(info)); + Info_SetValueForKey(info, "address", address, sizeof(info)); + Info_SetValueForKey(info, "players", va("%i", count), sizeof(info)); + Info_SetValueForKey(info, "proxytarget", va("%i", proxy), sizeof(info)); + Info_SetValueForKey(info, "lan", va("%i", Master_IsLanGame() != FALSE), sizeof(info)); + + int maxplayers = (int)sv_visiblemaxplayers.value; + if (maxplayers < 0) + maxplayers = g_psvs.maxclients; + + Info_SetValueForKey(info, "max", va("%i", maxplayers), sizeof(info)); + Info_SetValueForKey(info, "bots", va("%i", SV_GetFakeClientCount()), sizeof(info)); + + COM_FileBase(com_gamedir, gd); + Info_SetValueForKey(info, "gamedir", gd, sizeof(info)); + +#ifdef REHLDS_FIXES + if (gEntityInterface.pfnGetGameDescription) + Info_SetValueForKey(info, "description", gEntityInterface.pfnGetGameDescription(), ARRAYSIZE(info)); +#else + Info_SetValueForKey(info, "description", gEntityInterface.pfnGetGameDescription(), ARRAYSIZE(info)); +#endif // REHLDS_FIXES + Info_SetValueForKey(info, "hostname", Cvar_VariableString("hostname"), ARRAYSIZE(info)); + Info_SetValueForKey(info, "map", g_psv.name, ARRAYSIZE(info)); + + const char *type; + if (g_pcls.state) + type = "l"; + else + type = "d"; + Info_SetValueForKey(info, "type", type, sizeof(info)); + Info_SetValueForKey(info, "password", va("%i", iHasPW), sizeof(info)); + Info_SetValueForKey(info, "os", szOS, sizeof(info)); + Info_SetValueForKey(info, "secure", Steam_GSBSecure() ? "0" : "1", sizeof(info)); + + if (gmodinfo.bIsMod) + { + Info_SetValueForKey(info, "mod", va("%i", 1), sizeof(info)); + Info_SetValueForKey(info, "modversion", va("%i", gmodinfo.version), sizeof(info)); + Info_SetValueForKey(info, "svonly", va("%i", gmodinfo.svonly), sizeof(info)); + Info_SetValueForKey(info, "cldll", va("%i", gmodinfo.cldll), sizeof(info)); + } + + MSG_WriteLong(&buf, 0xffffffff); + MSG_WriteString(&buf, "infostringresponse"); + MSG_WriteString(&buf, info); + NET_SendPacket(NS_SERVER, buf.cursize, (char *)buf.data, net_from); +} + +/* ../engine/sv_main.c:3783 */ +NOXREF void SVC_Info(qboolean bDetailed) +{ + int i; + int count = 0; + sizebuf_t buf; + unsigned char data[1400]; + char szModURL_Info[512]; + char szModURL_DL[512]; + int mod_version; + int mod_size; + char gd[260]; + qboolean cldll; + qboolean svonly; + char szHLVersion[32]; + + if (!g_psv.active) + return; + + buf.buffername = "SVC_Info"; + buf.data = data; + buf.maxsize = sizeof(data); + buf.cursize = 0; + buf.flags = SIZEBUF_ALLOW_OVERFLOW; + + for (i = 0; i < g_psvs.maxclients; i++) + { + client_t *client = &g_psvs.clients[i]; + if (client->active || client->spawned || client->connected) + count++; + } + + MSG_WriteLong(&buf, 0xffffffff); + MSG_WriteByte(&buf, bDetailed ? 109 : 67); + + if (noip) + { +#ifdef _WIN32 + if (!noipx) + MSG_WriteString(&buf, NET_AdrToString(net_local_ipx_adr)); + else +#endif // _WIN32 + + MSG_WriteString(&buf, "LOOPBACK"); + } + else + MSG_WriteString(&buf, NET_AdrToString(net_local_adr)); + + MSG_WriteString(&buf, Cvar_VariableString("hostname")); + MSG_WriteString(&buf, g_psv.name); + COM_FileBase(com_gamedir, gd); + MSG_WriteString(&buf, gd); + +#ifdef REHLDS_FIXES + if (gEntityInterface.pfnGetGameDescription) + MSG_WriteString(&buf, gEntityInterface.pfnGetGameDescription()); + else + MSG_WriteString(&buf, ""); +#else + MSG_WriteString(&buf, gEntityInterface.pfnGetGameDescription()); +#endif // REHLDS_FIXES + + MSG_WriteByte(&buf, count); + int maxplayers = (int)sv_visiblemaxplayers.value; + if (maxplayers < 0) + maxplayers = g_psvs.maxclients; + + MSG_WriteByte(&buf, maxplayers); + MSG_WriteByte(&buf, PROTOCOL_VERSION); + + if (bDetailed) + { + MSG_WriteByte(&buf, g_pcls.state != ca_dedicated ? 108 : 100); + +#ifdef _WIN32 + MSG_WriteByte(&buf, 119); +#else + MSG_WriteByte(&buf, 108); +#endif // _WIN32 + + if (Q_strlen(sv_password.string) > 0 && Q_stricmp(sv_password.string, "none")) + MSG_WriteByte(&buf, 1); + else + MSG_WriteByte(&buf, 0); + + if (SV_GetModInfo(szModURL_Info, szModURL_DL, &mod_version, &mod_size, &svonly, &cldll, szHLVersion)) + { + MSG_WriteByte(&buf, 1); + MSG_WriteString(&buf, szModURL_Info); + MSG_WriteString(&buf, szModURL_DL); + MSG_WriteString(&buf, ""); + MSG_WriteLong(&buf, mod_version); + MSG_WriteLong(&buf, mod_size); + MSG_WriteByte(&buf, svonly != FALSE); + MSG_WriteByte(&buf, cldll != FALSE); + } + else + MSG_WriteByte(&buf, 0); + + MSG_WriteByte(&buf, Steam_GSBSecure() != FALSE); + MSG_WriteByte(&buf, SV_GetFakeClientCount()); + } + NET_SendPacket(NS_SERVER, buf.cursize, (char *)buf.data, net_from); +} + +/* ../engine/sv_main.c:3940 */ +typedef struct entcount_s +{ + int entdata; + int playerdata; +} entcount_t; + +//entcount_t ent_datacounts[32]; + +/* ../engine/sv_main.c:3954 */ +NOXREF void SVC_PlayerInfo(void) +{ + int i; + int count = 0; + client_t *client; + sizebuf_t buf; + unsigned char data[2048]; + + if (!g_psv.active) + return; + + if (g_psvs.maxclients <= 1) + return; + + buf.buffername = "SVC_PlayerInfo"; + buf.data = data; + buf.maxsize = sizeof(data); + buf.cursize = 0; + buf.flags = SIZEBUF_ALLOW_OVERFLOW; + + MSG_WriteLong(&buf, 0xffffffff); + MSG_WriteByte(&buf, 68); + + for (i = 0; i < g_psvs.maxclients; i++) + { + client = &g_psvs.clients[i]; + if (client->active) + count++; + } + + MSG_WriteByte(&buf, count); + + count = 0; + for (i = 0; i < g_psvs.maxclients; i++) + { + client = &g_psvs.clients[i]; + + if (client->active) + { + MSG_WriteByte(&buf, ++count); + MSG_WriteString(&buf, client->name); + MSG_WriteLong(&buf, client->edict->v.frags); + MSG_WriteFloat(&buf, (float)(realtime - client->netchan.connect_time)); + } + } + NET_SendPacket(NS_SERVER, buf.cursize, (char *)buf.data, net_from); +} + +/* ../engine/sv_main.c:4017 */ +NOXREF void SVC_RuleInfo(void) +{ + int nNumRules; + cvar_t *var; + sizebuf_t buf; + unsigned char data[8192]; + + if (!g_psv.active) + return; + + if (g_psvs.maxclients <= 1) + return; + + buf.buffername = "SVC_RuleInfo"; + buf.data = data; + buf.maxsize = sizeof(data); + buf.cursize = 0; + buf.flags = SIZEBUF_ALLOW_OVERFLOW; + + nNumRules = Cvar_CountServerVariables(); + if (!nNumRules) + return; + + MSG_WriteLong(&buf, 0xffffffff); + MSG_WriteByte(&buf, 69); + MSG_WriteShort(&buf, nNumRules); + + var = cvar_vars; + while (var != NULL) + { + if (var->flags & FCVAR_SERVER) + { + MSG_WriteString(&buf, var->name); + if (var->flags & FCVAR_PROTECTED) + { + if (Q_strlen(var->string) > 0 && Q_stricmp(var->string, "none")) + MSG_WriteString(&buf, "1"); + else + MSG_WriteString(&buf, "0"); + } + else + MSG_WriteString(&buf, var->string); + } + var = var->next; + } + NET_SendPacket(NS_SERVER, buf.cursize, (char *)buf.data, net_from); +} + +/* ../engine/sv_main.c:4083 */ +int SVC_GameDllQuery(const char *s) +{ + int len; + unsigned char data[4096]; + int valid; + + if (!g_psv.active || g_psvs.maxclients <= 1) + return 0; + + Q_memset(data, 0, sizeof(data)); + len = 2044 - sizeof(data); + valid = gEntityInterface.pfnConnectionlessPacket(&net_from, s, (char *) &data[4], &len); + if (len && len <= 2044) + { + *(uint32_t *)data = 0xFFFFFFFF; //connectionless packet + NET_SendPacket(NS_SERVER, len + 4, data, net_from); + } + return valid; +} + +/* ../engine/sv_main.c:4133 */ +void SV_FlushRedirect(void) +{ + unsigned char *data; + sizebuf_t buf; + + if (sv_redirected == RD_PACKET) + { + int allocLen = Q_strlen(outputbuf) + 10; + allocLen &= 0xFFFFFFFC; + data = (unsigned char *)alloca(allocLen); + + buf.buffername = "Redirected Text"; + buf.data = data; + buf.maxsize = Q_strlen(outputbuf) + 7; + buf.cursize = 0; + buf.flags = SIZEBUF_ALLOW_OVERFLOW; + + MSG_WriteLong(&buf, -1); + MSG_WriteByte(&buf, 0x6Cu); + MSG_WriteString(&buf, outputbuf); + MSG_WriteByte(&buf, 0); + NET_SendPacket(NS_SERVER, buf.cursize, buf.data, sv_redirectto); + outputbuf[0] = 0; + } + else + { + if (sv_redirected == RD_CLIENT) + { + MSG_WriteByte(&host_client->netchan.message, svc_print); + MSG_WriteString(&host_client->netchan.message, outputbuf); + } + outputbuf[0] = 0; + } +} + +/* ../engine/sv_main.c:4184 */ +void SV_EndRedirect(void) +{ + SV_FlushRedirect(); + sv_redirected = RD_NONE; +} + +/* ../engine/sv_main.c:4170 */ +void SV_BeginRedirect(redirect_t rd, netadr_t *addr) +{ + memcpy(&sv_redirectto, addr, sizeof(sv_redirectto)); + sv_redirected = rd; + outputbuf[0] = 0; +} + +#define MAX_RCON_FAILURES_STORAGE 32 +#define MAX_RCON_FAILURES 20 + +/* ../engine/sv_main.c:4214 */ +typedef struct rcon_failure_s +{ + qboolean active; + qboolean shouldreject; + netadr_t adr; + int num_failures; + float last_update; + float failure_times[MAX_RCON_FAILURES]; +} rcon_failure_t; + +rcon_failure_t g_rgRconFailures[MAX_RCON_FAILURES_STORAGE]; + +/* ../engine/sv_main.c:4229 */ +void SV_ResetRcon_f(void) +{ + Q_memset(g_rgRconFailures, 0, sizeof(g_rgRconFailures)); +} + +/* ../engine/sv_main.c:4238 */ +void SV_AddFailedRcon(netadr_t *adr) +{ + int i; + int best = 0; + float best_update = -99999.0f; + float time; + qboolean found = FALSE; + rcon_failure_t *r; + int failed; + + if (sv_rcon_minfailures.value < 1.0f) + { + Cvar_SetValue("sv_rcon_minfailures", 1.0); + } + else if (sv_rcon_minfailures.value > 20.0f) + { + Cvar_SetValue("sv_rcon_minfailures", 20.0); + } + if (sv_rcon_maxfailures.value < 1.0f) + { + Cvar_SetValue("sv_rcon_maxfailures", 1.0); + } + else if (sv_rcon_maxfailures.value > 20.0f) + { + Cvar_SetValue("sv_rcon_maxfailures", 20.0); + } + if (sv_rcon_maxfailures.value < sv_rcon_minfailures.value) + { + float temp = sv_rcon_maxfailures.value; + Cvar_SetValue("sv_rcon_maxfailures", sv_rcon_minfailures.value); + Cvar_SetValue("sv_rcon_minfailures", temp); + } + if (sv_rcon_minfailuretime.value < 1.0f) + { + Cvar_SetValue("sv_rcon_minfailuretime", 1.0); + } + + for (i = 0; i < MAX_RCON_FAILURES_STORAGE; i++) + { + r = &g_rgRconFailures[i]; + if (!r->active) + { + break; + } + if (NET_CompareAdr(r->adr, *adr)) + { + found = TRUE; + break; + } + time = (float)(realtime - r->last_update); + if (time >= best_update) + { + best = i; + best_update = time; + } + } + + // If no match found, take the oldest entry for usage + if (i >= MAX_RCON_FAILURES_STORAGE) + { + r = &g_rgRconFailures[best]; + } + + // Prepare new or stale entry + if (!found) + { + r->shouldreject = FALSE; + r->num_failures = 0; + Q_memcpy(&r->adr, adr, sizeof(netadr_t)); + } + else if (r->shouldreject) + { + return; + } + + r->active = TRUE; + r->last_update = (float)realtime; + + if (r->num_failures >= sv_rcon_maxfailures.value) + { +#ifdef REHLDS_FIXES + // FIXED: Accessing beyond array + for (i = 0; i < sv_rcon_maxfailures.value - 1; i++) + { + r->failure_times[i] = r->failure_times[i + 1]; + } + r->num_failures = sv_rcon_maxfailures.value - 1; +#else // REHLDS_FIXES + for (i = 0; i < sv_rcon_maxfailures.value; i++) + { + r->failure_times[i] = r->failure_times[i + 1]; + } + r->num_failures--; +#endif // REHLDS_FIXES + } + + r->failure_times[r->num_failures] = (float)realtime; + r->num_failures++; + + failed = 0; + for (i = 0; i < r->num_failures; i++) + { + if (realtime - r->failure_times[i] <= sv_rcon_minfailuretime.value) + failed++; + } + + if (failed >= sv_rcon_minfailures.value) + { + Con_Printf("User %s will be banned for rcon hacking\n", NET_AdrToString(*adr)); + r->shouldreject = TRUE; + } +} + +/* ../engine/sv_main.c:4364 */ +qboolean SV_CheckRconFailure(netadr_t *adr) +{ + for (int i = 0; i < 32; i++) + { + rcon_failure_t *r = &g_rgRconFailures[i]; + if (NET_CompareAdr(*adr, r->adr)) + { + if (r->shouldreject) + return TRUE; + } + } + + return FALSE; +} + +/* ../engine/sv_main.c:4400 */ +int SV_Rcon_Validate(void) +{ + if (Cmd_Argc() < 3 || Q_strlen(rcon_password.string) == 0) + return 1; + + if (sv_rcon_banpenalty.value < 0.0f) + Cvar_SetValue("sv_rcon_banpenalty", 0.0); + + if (SV_CheckRconFailure(&net_from)) + { + Con_Printf("Banning %s for rcon hacking attempts\n", NET_AdrToString(net_from)); + Cbuf_AddText(va("addip %i %s\n", (int)sv_rcon_banpenalty.value, NET_BaseAdrToString(net_from))); + return 3; + } + + if (!SV_CheckChallenge(&net_from, Q_atoi(Cmd_Argv(1)))) + return 2; + + if (Q_strcmp(Cmd_Argv(2), rcon_password.string)) + { + SV_AddFailedRcon(&net_from); + return 1; + } + return 0; +} + +/* ../engine/sv_main.c:4452 */ +void SV_Rcon(netadr_t *net_from_) +{ + char remaining[512]; + char rcon_buff[1024]; + + int invalid = SV_Rcon_Validate(); + int len = net_message.cursize - Q_strlen("rcon"); + if (len <= 0 || len >= sizeof(remaining)) + return; + + Q_memcpy(remaining, &net_message.data[Q_strlen("rcon")], len); + remaining[len] = 0; + if (invalid) + { + Con_Printf("Bad Rcon from %s:\n%s\n", NET_AdrToString(*net_from_), remaining); + Log_Printf("Bad Rcon: \"%s\" from \"%s\"\n", remaining, NET_AdrToString(*net_from_)); + } + else + { + Con_Printf("Rcon from %s:\n%s\n", NET_AdrToString(*net_from_), remaining); + Log_Printf("Rcon: \"%s\" from \"%s\"\n", remaining, NET_AdrToString(*net_from_)); + } + + SV_BeginRedirect(RD_PACKET, net_from_); + if (invalid) + { + if (invalid == 2) + Con_Printf("Bad rcon_password.\n"); + else if (strlen(rcon_password.string) == 0) + Con_Printf("Bad rcon_password.\nNo password set for this server.\n"); + else + Con_Printf("Bad rcon_password.\n"); + + SV_EndRedirect(); + return; + } + char *data = COM_Parse(COM_Parse(COM_Parse(remaining))); + if (!data) + { + Con_Printf("Empty rcon\n"); + +#ifdef REHLDS_FIXES + //missing SV_EndRedirect() + SV_EndRedirect(); +#endif // REHLDS_FIXES + return; + } + + Q_strncpy(rcon_buff, data, sizeof(rcon_buff) - 1); + rcon_buff[sizeof(rcon_buff) - 1] = 0; + Cmd_ExecuteString(rcon_buff, src_command); + SV_EndRedirect(); +} + +/* ../engine/sv_main.c:4564 */ +void SV_ConnectionlessPacket(void) +{ + char *args; + const char *c; + + MSG_BeginReading(); + MSG_ReadLong(); + args = MSG_ReadStringLine(); + Cmd_TokenizeString(args); + c = Cmd_Argv(0); + + if (!Q_strcmp(c, "ping") || (c[0] == A2A_PING && (c[1] == 0 || c[1] == '\n'))) + { + SVC_Ping(); + } + else if (c[0] == A2A_ACK && (c[1] == 0 || c[1] == '\n')) + { + Con_Printf("A2A_ACK from %s\n", NET_AdrToString(net_from)); + } + else if (c[0] == A2A_GETCHALLENGE || c[0] == A2S_INFO || c[0] == A2S_PLAYER || c[0] == A2S_RULES || + c[0] == S2A_LOGSTRING || c[0] == M2S_REQUESTRESTART || c[0] == M2A_CHALLENGE) + return; + + else if (!Q_stricmp(c, "log")) + { + if (sv_logrelay.value != 0.0f && args && Q_strlen(args) > 4) + { + const char *s = &args[Q_strlen("log ")]; + if (s && s[0]) + { + Con_Printf("%s\n", s); + } + } + } + else if (!Q_strcmp(c, "getchallenge")) + { + SVC_GetChallenge(); + } + else if (!Q_stricmp(c, "challenge")) + { + SVC_ServiceChallenge(); + } + else if (!Q_strcmp(c, "connect")) + { + SV_ConnectClient(); + } + else if (!Q_strcmp(c, "pstat")) + { + if (g_modfuncs.m_pfnPlayerStatus) + g_modfuncs.m_pfnPlayerStatus(net_message.data, net_message.cursize); + } + else if (!Q_strcmp(c, "rcon")) + { + SV_Rcon(&net_from); + } + else + SVC_GameDllQuery(args); +} + +/* ../engine/sv_main.c:4656 */ +void SV_CheckRate(client_t *cl) +{ + if (sv_maxrate.value > 0.0f) + { + if (cl->netchan.rate > sv_maxrate.value) + { + if (sv_maxrate.value > 100000.0f) + cl->netchan.rate = 100000.0; + else + cl->netchan.rate = sv_maxrate.value; + } + } + if (sv_minrate.value > 0.0f) + { + if (cl->netchan.rate < sv_minrate.value) + { + if (sv_minrate.value < 1000.0f) + cl->netchan.rate = 1000.0; + else + cl->netchan.rate = sv_minrate.value; + } + } +} + +/* ../engine/sv_main.c:4675 */ +void SV_ProcessFile(client_t *cl, char *filename) +{ + customization_t *pList; + resource_t *resource; + unsigned char md5[16]; + qboolean bFound; + + if (filename[0] != '!') + { + Con_Printf("Ignoring non-customization file upload of %s\n", filename); + return; + } + + COM_HexConvert(filename + 4, 32, md5); + resource = cl->resourcesneeded.pNext; + bFound = FALSE; + while (resource != &cl->resourcesneeded) + { + if (!Q_memcmp(resource->rgucMD5_hash, md5, 16)) + { + bFound = TRUE; + break; + } + + resource = resource->pNext; + } + + if (!bFound) + { + Con_Printf("SV_ProcessFile: Unrequested decal\n"); + return; + } + + if (resource->nDownloadSize != cl->netchan.tempbuffersize) + { + Con_Printf("SV_ProcessFile: Downloaded %i bytes for purported %i byte file\n", cl->netchan.tempbuffersize, resource->nDownloadSize); + return; + } + + HPAK_AddLump(TRUE, "custom.hpk", resource, cl->netchan.tempbuffer, NULL); + resource->ucFlags &= ~RES_WASMISSING; + SV_MoveToOnHandList(resource); + pList = cl->customdata.pNext; + while (pList) { + if (!Q_memcmp(pList->resource.rgucMD5_hash, resource->rgucMD5_hash, 16)) + { + Con_DPrintf("Duplicate resource received and ignored.\n"); + return; + } + pList = pList->pNext; + } + + if (!COM_CreateCustomization(&cl->customdata, resource, -1, 7, NULL, NULL)) + Con_Printf("Error parsing custom decal from %s\n", cl->name); +} + +/* ../engine/sv_main.c:4760 */ +qboolean SV_FilterPacket(void) +{ + for (int i = numipfilters - 1; i >= 0; i--) + { + ipfilter_t* curFilter = &ipfilters[i]; + if (curFilter->compare.u32 == 0xFFFFFFFF || curFilter->banEndTime == 0.0f || curFilter->banEndTime > realtime) + { + if ((*(uint32_t*)net_from.ip & curFilter->mask) == curFilter->compare.u32) + return (int)sv_filterban.value; + } + else + { + if (i < numipfilters - 1) + memcpy(curFilter, &curFilter[1], sizeof(ipfilter_t) * (numipfilters - i - 1)); + + --numipfilters; + } + } + return sv_filterban.value == 0.0f; +} + +/* ../engine/sv_main.c:4796 */ +void SV_SendBan(void) +{ + char szMessage[64]; + _snprintf(szMessage, sizeof(szMessage), "You have been banned from this server.\n"); + + SZ_Clear(&net_message); + + MSG_WriteLong(&net_message, -1); + MSG_WriteByte(&net_message, 108); + MSG_WriteString(&net_message, szMessage); + NET_SendPacket(NS_SERVER, net_message.cursize, net_message.data, net_from); + + SZ_Clear(&net_message); +} + +/* ../engine/sv_main.c:4818 */ +void SV_ReadPackets(void) +{ + while (NET_GetPacket(NS_SERVER)) + { + if (SV_FilterPacket()) + { + SV_SendBan(); + continue; + } + + if (*(uint32_t *)net_message.data == 0xFFFFFFFF) + { + // Connectionless packet + if (CheckIP(net_from)) + { + Steam_HandleIncomingPacket(net_message.data, net_message.cursize, ntohl(*(u_long *)&net_from.ip[0]), htons(net_from.port)); + SV_ConnectionlessPacket(); + } + else if (sv_logblocks.value != 0.0f) + { + Log_Printf("Traffic from %s was blocked for exceeding rate limits\n", NET_AdrToString(net_from)); + } + continue; + } + + for (int i = 0 ; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + if (!cl->connected && !cl->active && !cl->spawned) + { + continue; + } + + if (NET_CompareAdr(net_from, cl->netchan.remote_address) != TRUE) + { + continue; + } + + if (Netchan_Process(&cl->netchan)) + { + if (g_psvs.maxclients == 1 || !cl->active || !cl->spawned || !cl->fully_connected) + { + cl->send_message = TRUE; + } + + SV_ExecuteClientMessage(cl); + gGlobalVariables.frametime = host_frametime; + } + + if (Netchan_IncomingReady(&cl->netchan)) + { + if (Netchan_CopyNormalFragments(&cl->netchan)) + { + MSG_BeginReading(); + SV_ExecuteClientMessage(cl); + } + if (Netchan_CopyFileFragments(&cl->netchan)) + { + host_client = cl; + SV_ProcessFile(cl, cl->netchan.incomingfilename); + } + } + } + } +} + +/* ../engine/sv_main.c:4842 */ +//NOBODY int ntohl(void); +//{ +//} + +/* ../engine/sv_main.c:4842 */ +//NOBODY int htons(void); +//{ +//} + +/* ../engine/sv_main.c:4914 */ +void SV_CheckTimeouts(void) +{ + int i; + client_t *cl; + float droptime; + + droptime = realtime - sv_timeout.value; + + for (i = 0, cl = g_psvs.clients; i < g_psvs.maxclients; i++, cl++) + { + if (cl->fakeclient) + continue; + if (!cl->connected && !cl->active && !cl->spawned) + continue; + if (cl->netchan.last_received < droptime) + { + SV_BroadcastPrintf("%s timed out\n", cl->name); + SV_DropClient(cl, FALSE, "Timed out"); + } + } +} + +/* ../engine/sv_main.c:4943 */ +int SV_CalcPing(client_t *cl) +{ + float ping; + int i; + int count; + int back; + client_frame_t *frame; + int idx; + + if (cl->fakeclient) + { + return 0; + } + + if (SV_UPDATE_BACKUP <= 31) + { + back = SV_UPDATE_BACKUP / 2; + if (back <= 0) + { + return 0; + } + } + else + { + back = 16; + } + + ping = 0.0f; + count = 0; + for (i = 0; i < back; i++) + { + idx = cl->netchan.incoming_acknowledged + ~i; + frame = &cl->frames[SV_UPDATE_MASK & idx]; + + if (frame->ping_time > 0.0f) + { + ping += frame->ping_time; + count++; + } + } + + if (count) + { + ping /= count; + if (ping > 0.0f) + { + return ping * 1000.0f; + } + } + return 0; +} + +/* ../engine/sv_main.c:4991 */ +void SV_FullClientUpdate(client_t *cl, sizebuf_t *sb) +{ + unsigned int i; + char info[MAX_INFO_STRING]; + MD5Context_t ctx; + unsigned char digest[16]; + + i = cl - g_psvs.clients; + Q_strncpy(info, cl->userinfo, sizeof(info) - 1); + info[sizeof(info) - 1] = 0; + Info_RemovePrefixedKeys(info, '_'); + + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char*)cl->hashedcdkey, sizeof(cl->hashedcdkey)); + MD5Final(digest, &ctx); + + MSG_WriteByte(sb, svc_updateuserinfo); + MSG_WriteByte(sb, i); + MSG_WriteLong(sb, cl->userid); + MSG_WriteString(sb, info); + MSG_WriteBuf(sb, sizeof(digest), digest); +} + +/* ../engine/sv_main.c:5027 */ +void SV_EmitEvents(client_t *cl, packet_entities_t *pack, sizebuf_t *msg) +{ + int i; + int ev; + event_state_t *es; + event_info_t *info; + entity_state_t *state; + int ev_count = 0; + int etofind; + int c; + event_args_t nullargs; + + Q_memset(&nullargs, 0, sizeof(event_args_t)); + + es = &cl->events; + + for (ev = 0; ev < MAX_EVENT_QUEUE; ev++) + { + info = &es->ei[ev]; + + if (info->index != 0) + { + ev_count++; + } + } + + if (ev_count == 0) + { + return; + } + + if (ev_count > 31) + { + ev_count = 31; + } + + for (ev = 0; ev < MAX_EVENT_QUEUE; ev++) + { + info = &es->ei[ev]; + + if (info->index == 0) + { + continue; + } + + etofind = info->entity_index; + + for (i = 0; i < pack->num_entities; i++) + { + state = &pack->entities[i]; + + if (state->number == etofind) + { + break; + } + } + + if (i < pack->num_entities) + { + info->packet_index = i; + info->args.ducking = 0; + + if (!(info->args.flags & FEVENT_ORIGIN)) + { + info->args.origin[0] = 0.0f; + info->args.origin[1] = 0.0f; + info->args.origin[2] = 0.0f; + } + if (!(info->args.flags & FEVENT_ANGLES)) + { + info->args.angles[0] = 0.0f; + info->args.angles[1] = 0.0f; + info->args.angles[2] = 0.0f; + } + } + else + { + info->args.entindex = etofind; + info->packet_index = pack->num_entities; + } + } + + MSG_WriteByte(msg, svc_event); + MSG_StartBitWriting(msg); + MSG_WriteBits(ev_count, 5); + + c = 0; + + for (ev = 0; ev < MAX_EVENT_QUEUE; ev++) + { + info = &es->ei[ev]; + + if (info->index == 0) + { + info->packet_index = -1; + info->entity_index = -1; + continue; + } + + if (c < ev_count) + { + MSG_WriteBits(info->index, 10); + + if (info->packet_index != -1) + { + MSG_WriteBits(1, 1); + MSG_WriteBits(info->packet_index, 11); + if (Q_memcmp(&nullargs, &info->args, sizeof(event_args_t))) + { + MSG_WriteBits(1, 1); + DELTA_WriteDelta((byte *)&nullargs, (byte *)&info->args, TRUE, g_peventdelta, NULL); + } + } + else + { + MSG_WriteBits(0, 1); + } + + if (info->fire_time == 0.0f) + { + MSG_WriteBits(0, 1); + } + else + { + MSG_WriteBits(1, 1); + MSG_WriteBits(info->fire_time * 100.0f, 16); + } + } + + info->index = 0; + info->packet_index = -1; + info->entity_index = -1; + + c++; + } + MSG_EndBitWriting(msg); +} + +int fatbytes; +unsigned char fatpvs[1024]; +int fatpasbytes; +unsigned char fatpas[1024]; + +/* ../engine/sv_main.c:5196 */ +void SV_AddToFatPVS(vec_t *org, mnode_t *node) +{ + while (node->contents >= 0) + { + mplane_t *plane = node->plane; + float d = plane->normal[2] * org[2] + plane->normal[1] * org[1] + plane->normal[0] * org[0] - plane->dist; + if (d <= 8.0f) + { + if (d >= -8.0f) + { + SV_AddToFatPVS(org, node->children[0]); + node = node->children[1]; + } + else + { + node = node->children[1]; + } + } + else + { + node = node->children[0]; + } + } + if (node->contents != CONTENTS_SOLID) + { + unsigned char *pvs = Mod_LeafPVS((mleaf_t *)node, g_psv.worldmodel); + for (int i = 0; i < fatbytes; i++) + fatpvs[i] |= pvs[i]; + } +} + +/* ../engine/sv_main.c:5239 */ +unsigned char *SV_FatPVS(float *org) +{ + fatbytes = (g_psv.worldmodel->numleafs + 31) >> 3; + Q_memset(fatpvs, 0, fatbytes); + SV_AddToFatPVS(org, g_psv.worldmodel->nodes); + return fatpvs; +} + +/* ../engine/sv_main.c:5249 */ +void SV_AddToFatPAS(vec_t *org, mnode_t *node) +{ + int i; + unsigned char *pas; + mplane_t *plane; + float d; + + while (node->contents >= 0) + { + plane = node->plane; + d = org[0] * plane->normal[0] + + org[1] * plane->normal[1] + + org[2] * plane->normal[2] - plane->dist; + + if (d > 8.0f) + { + node = node->children[0]; + } + else if (d < -8.0f) + { + node = node->children[1]; + } + else + { + SV_AddToFatPAS(org, node->children[0]); + node = node->children[1]; + } + } + + if (node->contents == CONTENTS_SOLID) + { + return; + } + + int leafnum = (mleaf_t *)node - g_psv.worldmodel->leafs; + pas = CM_LeafPAS(leafnum); + + for (i = 0; i < fatpasbytes; ++i) + { + fatpas[i] |= pas[i]; + } +} + +/* ../engine/sv_main.c:5295 */ +unsigned char *SV_FatPAS(float *org) +{ + fatpasbytes = (g_psv.worldmodel->numleafs + 31) >> 3; + Q_memset(fatpas, 0, fatpasbytes); + SV_AddToFatPAS(org, g_psv.worldmodel->nodes); + return fatpas; +} + +/* ../engine/sv_main.c:5304 */ +int SV_PointLeafnum(vec_t *p) +{ + mleaf_t *mleaf = Mod_PointInLeaf(p, g_psv.worldmodel); + return mleaf ? (mleaf - g_psv.worldmodel->leafs) : 0; +} + +/* ../engine/sv_main.c:5313 */ +void TRACE_DELTA(char *fmt, ...) +{ +} + +deltacallback_t g_svdeltacallback; + +/* ../engine/sv_main.c:5349 */ +void SV_SetCallback(int num, qboolean remove, qboolean custom, int *numbase, qboolean full, int offset) +{ + g_svdeltacallback.num = num; + g_svdeltacallback.remove = remove; + g_svdeltacallback.custom = custom; + g_svdeltacallback.numbase = numbase; + g_svdeltacallback.full = full; + g_svdeltacallback.newbl = FALSE; + g_svdeltacallback.newblindex = 0; + g_svdeltacallback.offset = offset; +} + +/* ../engine/sv_main.c:5361 */ +void SV_SetNewInfo(int newblindex) +{ + g_svdeltacallback.newbl = TRUE; + g_svdeltacallback.newblindex = newblindex; +} + +/* ../engine/sv_main.c:5367 */ +void SV_WriteDeltaHeader(int num, qboolean remove, qboolean custom, int *numbase, qboolean newbl, int newblindex, qboolean full, int offset) +{ + int delta; + + delta = num - *numbase; + if (full) + { + if (delta == 1) + { + MSG_WriteBits(1, 1); + } + else + { + MSG_WriteBits(0, 1); + } + } + else + { + MSG_WriteBits((remove != 0) ? 1 : 0, 1); + } + + if (!full || delta != 1) + { + if (delta <= 0 || delta > 63) + { + MSG_WriteBits(1u, 1); + MSG_WriteBits(num, 11); + } + else + { + MSG_WriteBits(0, 1); + MSG_WriteBits(delta, 6); + } + } + + *numbase = num; + if (!remove) + { + MSG_WriteBits(custom != 0, 1); + if (g_psv.instance_baselines->number) + { + if (newbl) + { + MSG_WriteBits(1u, 1); + MSG_WriteBits(newblindex, 6); + } + else + { + MSG_WriteBits(0, 1); + } + } + if (full && !newbl) + { + if (offset) + { + MSG_WriteBits(1u, 1); + MSG_WriteBits(offset, 6); + } + else + { + MSG_WriteBits(0, 1); + } + } + } +} + +/* ../engine/sv_main.c:5445 */ +void SV_InvokeCallback(void) +{ + SV_WriteDeltaHeader( + g_svdeltacallback.num, + g_svdeltacallback.remove, + g_svdeltacallback.custom, + g_svdeltacallback.numbase, + g_svdeltacallback.newbl, + g_svdeltacallback.newblindex, + g_svdeltacallback.full, + g_svdeltacallback.offset + ); +} + +/* ../engine/sv_main.c:5467 */ +int SV_FindBestBaseline(int index, entity_state_t ** baseline, entity_state_t *to, int num, qboolean custom) +{ + int bestbitnumber; + + if (custom) + { + bestbitnumber = DELTA_TestDelta((byte *)*baseline, (byte *)&to[index], g_pcustomentitydelta); + } + else + { + if (SV_IsPlayerIndex(num)) + { + bestbitnumber = DELTA_TestDelta((byte *)*baseline, (byte *)&to[index], g_pplayerdelta); + } + else + { + bestbitnumber = DELTA_TestDelta((byte *)*baseline, (byte *)&to[index], g_pentitydelta); + } + } + + bestbitnumber -= 6; + + int i = 0; + int bitnumber = 0; + int bestfound = index; + + for (i = index - 1; bestbitnumber > 0 && i >= 0 && (index - i) <= 64; i--) + { + if (to[index].entityType == to[i].entityType) + { + if (custom) + { + bitnumber = DELTA_TestDelta((byte *)&to[i], (byte *)&to[index], g_pcustomentitydelta); + } + else + { + if (SV_IsPlayerIndex(num)) + { + bitnumber = DELTA_TestDelta((byte *)&to[i], (byte *)&to[index], g_pplayerdelta); + } + else + { + bitnumber = DELTA_TestDelta((byte *)&to[i], (byte *)&to[index], g_pentitydelta); + } + } + if (bitnumber < bestbitnumber) + { + bestbitnumber = bitnumber; + bestfound = i; + } + } + } + + if (index != bestfound) + *baseline = &to[bestfound]; + + return index - bestfound; +} + +/* ../engine/sv_main.c:5525 */ +int SV_CreatePacketEntities(sv_delta_t type, client_t *client, packet_entities_t *to, sizebuf_t *msg) +{ + packet_entities_t *from; + int oldindex; + int newindex; + int oldnum; + int newnum; + int oldmax; + int numbase; + + numbase = 0; + if (type == sv_packet_delta) + { + client_frame_t *fromframe = &client->frames[SV_UPDATE_MASK & client->delta_sequence]; + from = &fromframe->entities; + oldmax = from->num_entities; + MSG_WriteByte(msg, svc_deltapacketentities); + MSG_WriteShort(msg, to->num_entities); + MSG_WriteByte(msg, client->delta_sequence); + } + else + { + oldmax = 0; + from = NULL; + MSG_WriteByte(msg, svc_packetentities); + MSG_WriteShort(msg, to->num_entities); + } + + newnum = 0; + oldnum = 0; + MSG_StartBitWriting(msg); + while (1) + { + if (newnum < to->num_entities) + { + newindex = to->entities[newnum].number; + } + else + { + if (oldnum >= oldmax) + break; + + if (newnum < to->num_entities) + newindex = to->entities[newnum].number; + else + newindex = 9999; + } + + if (oldnum < oldmax) + oldindex = from->entities[oldnum].number; + else + oldindex = 9999; + + if (newindex == oldindex) + { + entity_state_t *baseline_ = &to->entities[newnum]; + qboolean custom = baseline_->entityType & 0x2 ? TRUE : FALSE; + SV_SetCallback(newindex, FALSE, custom, &numbase, FALSE, 0); + DELTA_WriteDelta((uint8 *)&from->entities[oldnum], (uint8 *)baseline_, FALSE, custom ? g_pcustomentitydelta : (SV_IsPlayerIndex(newindex) ? g_pplayerdelta : g_pentitydelta), &SV_InvokeCallback); + ++oldnum; + ++newnum; + continue; + } + + if (newindex >= oldindex) + { + if (newindex > oldindex) + { + SV_WriteDeltaHeader(oldindex, TRUE, FALSE, &numbase, FALSE, 0, FALSE, 0); + ++oldnum; + } + continue; + } + + edict_t *ent = EDICT_NUM(newindex); + qboolean custom = to->entities[newnum].entityType & 0x2 ? TRUE : FALSE; + SV_SetCallback( + newindex, + FALSE, + custom, + &numbase, + from == 0, + 0); + + entity_state_t *baseline_ = &g_psv.baselines[newindex]; + if (sv_instancedbaseline.value != 0.0f && g_psv.instance_baselines->number != 0 && newindex > sv_lastnum) + { + for (int i = 0; i < g_psv.instance_baselines->number; i++) + { + if (g_psv.instance_baselines->classname[i] == ent->v.classname) + { + SV_SetNewInfo(i); + baseline_ = &g_psv.instance_baselines->baseline[i]; + break; + } + } + } + else + { + if (!from) + { + int offset = SV_FindBestBaseline(newnum, &baseline_, to->entities, newindex, custom); + if (offset) + SV_SetCallback(newindex, 0, custom, &numbase, 1, offset); + } + } + + DELTA_WriteDelta( + (uint8 *)baseline_, + (uint8 *)&to->entities[newnum], + TRUE, + custom ? g_pcustomentitydelta : (SV_IsPlayerIndex(newindex) ? g_pplayerdelta : g_pentitydelta), + &SV_InvokeCallback + ); + ++newnum; + } + + MSG_WriteBits(0, 16); + MSG_EndBitWriting(msg); + return msg->cursize; +} + +/* ../engine/sv_main.c:5685 */ +void SV_EmitPacketEntities(client_t *client, packet_entities_t *to, sizebuf_t *msg) +{ + SV_CreatePacketEntities(client->delta_sequence == -1 ? sv_packet_nodelta : sv_packet_delta, client, to, msg); +} + +/* ../engine/sv_main.c:5708 */ +qboolean SV_ShouldUpdatePing(client_t *client) +{ + if (client->proxy) + { + if (realtime < client->nextping) + return 0; + + client->nextping = realtime + 2.0; + return 1; + } + + SV_CalcPing(client); + return client->lastcmd.buttons & 0x8000; +} + +/* ../engine/sv_main.c:5734 */ +NOXREF qboolean SV_HasEventsInQueue(client_t *client) +{ + int i; + event_state_t *es; + event_info_t *ei; + + es = &client->events; + + for (i = 0; i < MAX_EVENT_QUEUE; i++) + { + ei = &es->ei[i]; + + if (ei->index) + return TRUE; + } + return FALSE; +} + +/* ../engine/sv_main.c:5756 */ +void SV_GetNetInfo(client_t *client, int *ping, int *packet_loss) +{ + static uint16 lastping[32]; + static uint8 lastloss[32]; + + int i = client - g_psvs.clients; + if (realtime >= client->nextping) + { + client->nextping = realtime + 2.0; + lastping[i] = SV_CalcPing(client); + lastloss[i] = client->packet_loss; + } + + *ping = lastping[i]; + *packet_loss = lastloss[i]; +} + +/* ../engine/sv_main.c:5775 */ +int SV_CheckVisibility(edict_t *entity, unsigned char *pset) +{ + int leaf; + + if (!pset) + return 1; + + if (entity->headnode < 0) + { + for (int i = 0; i < entity->num_leafs; i++) + { + leaf = entity->leafnums[i]; + if (pset[leaf >> 3] & (1 << (leaf & 7))) + return 1; + } + return 0; + } + else + { + for (int i = 0; i < 48; i++) + { + leaf = entity->leafnums[i]; + if (leaf == -1) + break; + + if (pset[leaf >> 3] & (1 << (leaf & 7))) + return 1; + } + + if (CM_HeadnodeVisible(&g_psv.worldmodel->nodes[entity->headnode], pset, &leaf)) + { + entity->leafnums[entity->num_leafs] = leaf; + entity->num_leafs = (entity->num_leafs + 1) % 48; + return 2; + } + + return 0; + } +} + +/* ../engine/sv_main.c:5844 */ +void SV_EmitPings(client_t *client, sizebuf_t *msg) +{ + int ping; + int packet_loss; + + MSG_WriteByte(msg, svc_pings); + MSG_StartBitWriting(msg); + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + if (!cl->active) + continue; + + SV_GetNetInfo(cl, &ping, &packet_loss); + MSG_WriteBits(1, 1); + MSG_WriteBits(i, 5); + MSG_WriteBits(ping, 12); + MSG_WriteBits(packet_loss, 7); + } + + MSG_WriteBits(0, 1); + MSG_EndBitWriting(msg); +} + +/* ../engine/sv_main.c:5878 */ +void SV_WriteEntitiesToClient(client_t *client, sizebuf_t *msg) +{ + full_packet_entities_t fullpack; + client_frame_t *frame = &client->frames[SV_UPDATE_MASK & client->netchan.outgoing_sequence]; + + unsigned char *pvs = NULL; + unsigned char *pas = NULL; + gEntityInterface.pfnSetupVisibility((edict_t*)client->pViewEntity, client->edict, &pvs, &pas); + unsigned char *pSet = pvs; + + SV_ClearPacketEntities(frame); + packet_entities_t *pack = &frame->entities; + fullpack.num_entities = 0; + + qboolean sendping = SV_ShouldUpdatePing(client); + + int flags = client->lw != 0; + + for (int e = 1; e < g_psv.num_edicts; e++) + { + edict_t *ent = &g_psv.edicts[e]; + int player = 0; + if (e >= 1 && e <= g_psvs.maxclients) + { + client_t *cl = &g_psvs.clients[e - 1]; + if ((!cl->active && !cl->spawned) || cl->proxy) + continue; + + player = 1; + } + + if (fullpack.num_entities >= 256) + { + Con_DPrintf("Too many entities in visible packet list.\n"); + break; + } + + qboolean add = gEntityInterface.pfnAddToFullPack(&fullpack.entities[fullpack.num_entities], e, ent, host_client->edict, flags, player, pSet); + if (add) + ++fullpack.num_entities; + } + + SV_AllocPacketEntities(frame, fullpack.num_entities); + if (pack->num_entities) + Q_memcpy(pack->entities, fullpack.entities, sizeof(entity_state_t) * pack->num_entities); + + SV_EmitPacketEntities(client, pack, msg); + SV_EmitEvents(client, pack, msg); + if (sendping) + SV_EmitPings(client, msg); +} + +/* ../engine/sv_main.c:5981 */ +void SV_CleanupEnts(void) +{ + for (int e = 1; e < g_psv.num_edicts; e++) + { + edict_t *ent = &g_psv.edicts[e]; + ent->v.effects &= ~(EF_NOINTERP | EF_MUZZLEFLASH); + } +} + +/* ../engine/sv_main.c:5999 */ +qboolean SV_SendClientDatagram(client_t *client) +{ + unsigned char buf[4000]; + sizebuf_t msg; + + msg.buffername = "Client Datagram"; + msg.data = buf; + msg.maxsize = sizeof(buf); + msg.cursize = 0; + msg.flags = SIZEBUF_ALLOW_OVERFLOW; + + MSG_WriteByte(&msg, svc_time); + MSG_WriteFloat(&msg, g_psv.time); + + SV_WriteClientdataToMessage(client, &msg); + SV_WriteEntitiesToClient(client, &msg); + + if (client->datagram.flags & SIZEBUF_OVERFLOWED) + { + Con_Printf("WARNING: datagram overflowed for %s\n", client->name); + } + else + { + SZ_Write(&msg, client->datagram.data, client->datagram.cursize); + } + + SZ_Clear(&client->datagram); + + if (msg.flags & SIZEBUF_OVERFLOWED) + { + Con_Printf("WARNING: msg overflowed for %s\n", client->name); + SZ_Clear(&msg); + } + + Netchan_Transmit(&client->netchan, msg.cursize, buf); + + return TRUE; +} + +/* ../engine/sv_main.c:6062 */ +void SV_UpdateToReliableMessages(void) +{ + int i; + client_t *client; + + // Prepare setinfo changes and send new user messages + for (i = 0; i < g_psvs.maxclients; i++) + { + client = &g_psvs.clients[i]; + + if (!client->edict) + continue; + + host_client = client; + + if (client->sendinfo && client->sendinfo_time <= realtime) + { + client->sendinfo = FALSE; + client->sendinfo_time = realtime + 1.0; + SV_ExtractFromUserinfo(client); + SV_FullClientUpdate(client, &g_psv.reliable_datagram); + } + + if (!client->fakeclient && (client->active || client->connected)) + { + if (sv_gpNewUserMsgs != NULL) + { + SV_SendUserReg(&client->netchan.message); + } + } + } + + // Link new user messages to sent chain + if (sv_gpNewUserMsgs != NULL) + { + UserMsg *pMsg = sv_gpUserMsgs; + if (pMsg != NULL) + { + while (pMsg->next) + { + pMsg = pMsg->next; + } + pMsg->next = sv_gpNewUserMsgs; + } + else + { + sv_gpUserMsgs = sv_gpNewUserMsgs; + } + sv_gpNewUserMsgs = NULL; + } + + if (g_psv.datagram.flags & SIZEBUF_OVERFLOWED) + { + Con_DPrintf("sv.datagram overflowed!\n"); + SZ_Clear(&g_psv.datagram); + } + if (g_psv.spectator.flags & SIZEBUF_OVERFLOWED) + { + Con_DPrintf("sv.spectator overflowed!\n"); + SZ_Clear(&g_psv.spectator); + } + + // Send broadcast data + for (i = 0; i < g_psvs.maxclients; i++) + { + client = &g_psvs.clients[i]; + + if (!client->fakeclient && client->active) + { + if (g_psv.reliable_datagram.cursize + client->netchan.message.cursize < client->netchan.message.maxsize) + { + SZ_Write(&client->netchan.message, g_psv.reliable_datagram.data, g_psv.reliable_datagram.cursize); + } + else + { + Netchan_CreateFragments(TRUE, &client->netchan, &g_psv.reliable_datagram); + } + + if (g_psv.datagram.cursize + client->datagram.cursize < client->datagram.maxsize) + { + SZ_Write(&client->datagram, g_psv.datagram.data, g_psv.datagram.cursize); + } + else + { + Con_DPrintf("Warning: Ignoring unreliable datagram for %s, would overflow\n", client->name); + } + + if (client->proxy) + { + if (g_psv.spectator.cursize + client->datagram.cursize < client->datagram.maxsize) + { + SZ_Write(&client->datagram, g_psv.spectator.data, g_psv.spectator.cursize); + } +#ifdef REHLDS_FIXES + else + { + Con_DPrintf("Warning: Ignoring spectator datagram for %s, would overflow\n", client->name); + } +#endif + } + } + } + + SZ_Clear(&g_psv.reliable_datagram); + SZ_Clear(&g_psv.datagram); + SZ_Clear(&g_psv.spectator); +} + +/* ../engine/sv_main.c:6184 */ +void SV_SkipUpdates(void) +{ + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *client = &g_psvs.clients[i]; + if (!client->active && !client->connected && !client->spawned) + continue; + + if (!host_client->fakeclient) //TODO: should be client, not host_client; investigation needed + client->skip_message = TRUE; + } +} + +/* ../engine/sv_main.c:6204 */ +void SV_SendClientMessages(void) +{ + SV_UpdateToReliableMessages(); + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + host_client = cl; + + if ((!cl->active && !cl->connected && !cl->spawned) || cl->fakeclient) + continue; + + if (cl->skip_message) + { + cl->skip_message = FALSE; + continue; + } + + if (host_limitlocal.value == 0.0f && cl->netchan.remote_address.type == NA_LOOPBACK) + cl->send_message = TRUE; + + if (cl->active && cl->spawned && cl->fully_connected && host_frametime + realtime >= cl->next_messagetime) + cl->send_message = TRUE; + + if (cl->netchan.message.flags & SIZEBUF_OVERFLOWED) + { + SZ_Clear(&cl->netchan.message); + SZ_Clear(&cl->datagram); + SV_BroadcastPrintf("%s overflowed\n", cl->name); + Con_Printf("WARNING: reliable overflow for %s\n", cl->name); + SV_DropClient(cl, FALSE, "Reliable channel overflowed"); + cl->send_message = TRUE; + cl->netchan.cleartime = 0; + } + else if (cl->send_message) + { + if (sv_failuretime.value < realtime - cl->netchan.last_received) + cl->send_message = FALSE; + } + + if (cl->send_message) + { + if (!Netchan_CanPacket(&cl->netchan)) + { + ++cl->chokecount; + continue; + } + + host_client->send_message = FALSE; + cl->next_messagetime = host_frametime + cl->next_messageinterval + realtime; + if (cl->active && cl->spawned && cl->fully_connected) + SV_SendClientDatagram(cl); + else + Netchan_Transmit(&cl->netchan, 0, NULL); + } + } + SV_CleanupEnts(); +} + +/* ../engine/sv_main.c:6307 */ +void SV_ExtractFromUserinfo(client_t *cl) +{ + const char *val; + int i; + client_t *client; + int dupc; + char newname[MAX_NAME]; + char rawname[MAX_NAME]; + + char *userinfo = cl->userinfo; + + // TODO: Refactor names checking in SV_CheckForDuplicateNames, SV_CheckUserInfo and SV_ExtractFromUserinfo + val = Info_ValueForKey(userinfo, "name"); + Q_strncpy(rawname, val, sizeof(rawname) - 1); + rawname[sizeof(rawname) - 1] = 0; + + // Fix name to not start with '#', so it will not resemble userid + for (char *p = rawname; *p == '#'; p++) *p = ' '; + + TrimSpace(rawname, newname); + + if (!Q_UnicodeValidate(newname)) + { + Q_UnicodeRepair(newname); + } + + if (newname[0] == 0 || !Q_stricmp(newname, "console") +#ifdef REHLDS_FIXES + || Q_strstr(newname, "..") != NULL) +#else // REHLDS_FIXES + ) +#endif // REHLDS_FIXES + { + Info_SetValueForKey(userinfo, "name", "unnamed", MAX_INFO_STRING); + val = Info_ValueForKey(userinfo, "name"); + } + else if (Q_strcmp(val, newname)) + { + Info_SetValueForKey(userinfo, "name", newname, MAX_INFO_STRING); + val = Info_ValueForKey(userinfo, "name"); + } + + // Check for duplicate names + dupc = 1; + while (true) + { + client = g_psvs.clients; + + i = 0; + while (!client->active || !client->spawned || client == cl || Q_stricmp(client->name, val)) + { + client++; + i++; + if (i >= g_psvs.maxclients) + break; + } + if (i >= g_psvs.maxclients) + break; + + // Doesn't look we need this stuff, snprintf will do this work + //if (Q_strlen(val) > 31) + // val[28] = 0; + + if (val[0] == '(') + { + if (val[2] == ')') + val += 3; + else if (val[3] == ')') + val += 4; + } + + Q_snprintf(newname, sizeof(newname), "(%d)%-0.*s", dupc, 28, val); +#ifdef REHLDS_FIXES + // Fix possibly incorrectly cut UTF8 chars + if (!Q_UnicodeValidate(newname)) + { + Q_UnicodeRepair(newname); + } +#endif // REHLDS_FIXES + Info_SetValueForKey(userinfo, "name", newname, MAX_INFO_STRING); + + dupc++; + + val = Info_ValueForKey(userinfo, "name"); + } + + gEntityInterface.pfnClientUserInfoChanged(cl->edict, userinfo); + + val = Info_ValueForKey(userinfo, "name"); + Q_strncpy(cl->name, val, sizeof(cl->name) - 1); + cl->name[sizeof(cl->name) - 1] = 0; + + ISteamGameServer_BUpdateUserData(cl->network_userid.m_SteamID, cl->name, 0); + + val = Info_ValueForKey(userinfo, "rate"); + if (val[0] != 0) + { + i = Q_atoi(val); + cl->netchan.rate = clamp(i, 1000, 100000); + } + + val = Info_ValueForKey(userinfo, "topcolor"); + if (val[0] != 0) + cl->topcolor = Q_atoi(val); + else + Con_DPrintf("topcolor unchanged for %s\n", cl->name); + + val = Info_ValueForKey(userinfo, "bottomcolor"); + if (val[0] != 0) + cl->bottomcolor = Q_atoi(val); + else + Con_DPrintf("bottomcolor unchanged for %s\n", cl->name); + + val = Info_ValueForKey(userinfo, "cl_updaterate"); + if (val[0] != 0) + { + i = Q_atoi(val); + if (i >= 10) + cl->next_messageinterval = 1.0 / i; + else + cl->next_messageinterval = 0.1; + } + + val = Info_ValueForKey(userinfo, "cl_lw"); + cl->lw = val[0] != 0 ? Q_atoi(val) != 0 : 0; + + val = Info_ValueForKey(userinfo, "cl_lc"); + cl->lc = val[0] != 0 ? Q_atoi(val) != 0 : 0; + + val = Info_ValueForKey(userinfo, "*hltv"); + cl->proxy = val[0] != 0 ? Q_atoi(val) == 1 : 0; + + SV_CheckUpdateRate(&cl->next_messageinterval); + SV_CheckRate(cl); +} + +/* ../engine/sv_main.c:6507 */ +int SV_ModelIndex(const char *name) +{ + if (!name || !name[0]) + return 0; + + for (int i = 0; i < 512; i++) + { + if (!g_psv.model_precache[i]) + break; + + if (!Q_stricmp(g_psv.model_precache[i], name)) + return i; + }; + + Sys_Error("SV_ModelIndex: model %s not precached", name); +} + +/* ../engine/sv_main.c:6529 */ +void SV_AddResource(resourcetype_t type, char *name, int size, unsigned char flags, int index) +{ + resource_t *r; + if (g_psv.num_resources >= 1280) + Sys_Error("Too many resources on server."); + + r = &g_psv.resourcelist[g_psv.num_resources++]; + r->type = type; + Q_strncpy(r->szFileName, name, sizeof(r->szFileName) - 1); + r->szFileName[sizeof(r->szFileName) - 1] = 0; + r->ucFlags = flags; + r->nDownloadSize = size; + r->nIndex = index; +} + +/* ../engine/sv_main.c:6557 */ +void SV_CreateGenericResources(void) +{ + char filename[MAX_PATH]; + char *buffer; + char *data; + + COM_StripExtension(g_psv.modelname, filename); + COM_DefaultExtension(filename, ".res"); + COM_FixSlashes(filename); + + buffer = (char *)COM_LoadFile(filename, 5, NULL); + if (buffer == NULL) + return; + + data = buffer; + Con_DPrintf("Precaching from %s\n", filename); + Con_DPrintf("----------------------------------\n"); + g_psv.num_generic_names = 0; + + while (1) + { + data = COM_Parse(data); + if (Q_strlen(com_token) <= 0) + break; + + if (Q_strstr(com_token, "..")) + Con_Printf("Can't precache resource with invalid relative path %s\n", com_token); + else if (Q_strstr(com_token, ":")) + Con_Printf("Can't precache resource with absolute path %s\n", com_token); + else if (Q_strstr(com_token, "\\")) + Con_Printf("Can't precache resource with invalid relative path %s\n", com_token); + else if (Q_strstr(com_token, ".cfg")) + Con_Printf("Can't precache .cfg files: %s\n", com_token); + else if (Q_strstr(com_token, ".lst")) + Con_Printf("Can't precache .lst files: %s\n", com_token); + else if (Q_strstr(com_token, ".exe")) + Con_Printf("Can't precache .exe files: %s\n", com_token); + else if (Q_strstr(com_token, ".vbs")) + Con_Printf("Can't precache .vbs files: %s\n", com_token); + else if (Q_strstr(com_token, ".com")) + Con_Printf("Can't precache .com files: %s\n", com_token); + else if (Q_strstr(com_token, ".bat")) + Con_Printf("Can't precache .bat files: %s\n", com_token); + else if (Q_strstr(com_token, ".dll")) + Con_Printf("Can't precache .dll files: %s\n", com_token); + else + { + Q_strncpy(g_psv.generic_precache_names[g_psv.num_generic_names], com_token, sizeof(g_psv.generic_precache_names[g_psv.num_generic_names]) - 1); + g_psv.generic_precache_names[g_psv.num_generic_names][sizeof(g_psv.generic_precache_names[g_psv.num_generic_names]) - 1] = 0; + PF_precache_generic_I(g_psv.generic_precache_names[g_psv.num_generic_names]); + Con_DPrintf(" %s\n", g_psv.generic_precache_names[g_psv.num_generic_names++]); + } + } + Con_DPrintf("----------------------------------\n"); + COM_FreeFile(buffer); +} + +/* ../engine/sv_main.c:6675 */ +void SV_CreateResourceList(void) +{ + char ** s; + int ffirstsent = 0; + int i; + int nSize; + event_t *ep; + + g_psv.num_resources = 0; + for (i = 1, s = &g_psv.generic_precache[1]; *s != NULL; i++, s++) + { + if (g_psvs.maxclients > 1) + nSize = FS_FileSize(*s); + else + nSize = 0; + + SV_AddResource(t_generic, *s, nSize, 1, i); + } + for (i = 1, s = &g_psv.sound_precache[1]; *s != NULL; i++, s++) + { + if (**s == '!') + { + if (!ffirstsent) + { + ffirstsent = 1; + SV_AddResource(t_sound, "!", 0, 1, i); + } + } + else + { + nSize = 0; + if (g_psvs.maxclients > 1) + nSize = FS_FileSize(va("sound/%s", *s)); + SV_AddResource(t_sound, *s, nSize, 0, i); + } + } + for (i = 1, s = &g_psv.model_precache[1]; *s != NULL; i++, s++) + { + if (g_psvs.maxclients > 1 && **s != '*') + nSize = FS_FileSize(*s); + else + nSize = 0; + + SV_AddResource(t_model, *s, nSize, g_psv.model_precache_flags[i], i); + } + for (i = 0; i < sv_decalnamecount; i++) + SV_AddResource(t_decal, sv_decalnames[i].name, Draw_DecalSize(i), 0, i); + + for (i = 1; i < 255; i++) + { + ep = &g_psv.event_precache[i]; + if (!ep->filename) + break; + + SV_AddResource(t_eventscript, (char *)ep->filename, ep->filesize, 1, i); + } +} + +/* ../engine/sv_main.c:6766 */ +void SV_ClearCaches(void) +{ + int i; + event_t *ep; + for (i = 1; i < 255; i++) + { + ep = &g_psv.event_precache[i]; + if (ep->filename == NULL) + break; + + ep->filename = NULL; + if (ep->pszScript) + Mem_Free((void *)ep->pszScript); + ep->pszScript = NULL; + } +} + +/* ../engine/sv_main.c:6790 */ +// Sends customizations from all active players to the current player. +void SV_PropagateCustomizations(void) +{ + client_t *pHost; + customization_t *pCust; + resource_t *pResource; + int i; + + // For each active player + for (i = 0, pHost = g_psvs.clients; i < g_psvs.maxclients; i++, pHost++) + { + if (!pHost->active && !pHost->spawned || pHost->fakeclient) + continue; + + // Send each customization to current player + pCust = pHost->customdata.pNext; + while (pCust != NULL) + { + if (pCust->bInUse) + { + pResource = &pCust->resource; + MSG_WriteByte(&host_client->netchan.message, svc_customization); + MSG_WriteByte(&host_client->netchan.message, i); + MSG_WriteByte(&host_client->netchan.message, pResource->type); + MSG_WriteString(&host_client->netchan.message, pResource->szFileName); + MSG_WriteShort(&host_client->netchan.message, pResource->nIndex); + MSG_WriteLong(&host_client->netchan.message, pResource->nDownloadSize); + MSG_WriteByte(&host_client->netchan.message, pResource->ucFlags); + if (pResource->ucFlags & RES_CUSTOM) + { + SZ_Write(&host_client->netchan.message, pResource->rgucMD5_hash, 16); + } + } + + pCust = pCust->pNext; + } + } +} + +/* ../engine/sv_main.c:6850 */ +void SV_WriteVoiceCodec(sizebuf_t *pBuf) +{ + MSG_WriteByte(pBuf, svc_voiceinit); + MSG_WriteString(pBuf, ""); + MSG_WriteByte(pBuf, 0); +} + +/* + * Interface between engine and gamedll has a flaw which can lead to inconsistent behavior when passing arguments of type vec3_t to gamedll + * Consider function func(vec3_t v) defined in gamedll. vec3_t defined in gamedll as a class (not array), therefore it's expected that all vector components (12 bytes) will be written in the stack, + * i.e. the function signature may be represented as func(float v_0, float v_1, float v_2). + * In the engine, on the other hand, vec3_t is an array of vec_t (vec_t[3]). C/C++ compiler treats arguments of array type as pointers to array's first element, thus, on attempt to + * invoke gamedll's func(vec3_t v) from engine, only pointer to first vector's element will be passed in stack, while gamedll expects all 3 vector elements. + * This inconsistency in the interface between gamedll and engine leads to exposure of some data from stack of caller function to vector's elements in gamedll, which, in turn, + * leads to inconsistent behavior (since stack data may contain pointers) across different systems + * + * This functions emulates swds.dll behavior, i.e. it sends the same garbage when invoking CreateBaseline as swds.dll does. + * This is required since not emulating this behavior will break rehlds test demos + */ +void __invokeValvesBuggedCreateBaseline(void* func, int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec_t* pmins, vec_t* pmaxs) +{ + __asm { + mov ecx, func + push 0 + push 1 + push 0 + push 0 + push pmaxs + push pmins + push playermodelindex + push entity + push baseline + push eindex + push player + call ecx + add esp, 0x2C + } +} + +/* ../engine/sv_main.c:6866 */ +void SV_CreateBaseline(void) +{ + edict_t *svent; + int entnum; + qboolean player; + qboolean custom; + entity_state_t nullstate; + delta_t *pDelta; + + g_psv.instance_baselines = &g_sv_instance_baselines; + Q_memset(&nullstate, 0, sizeof(entity_state_t)); + SV_FindModelNumbers(); + + for (entnum = 0; entnum < g_psv.num_edicts; entnum++) + { + svent = &g_psv.edicts[entnum]; + if (!svent->free) + { + if (g_psvs.maxclients >= entnum || svent->v.modelindex) + { + player = SV_IsPlayerIndex(entnum); + g_psv.baselines[entnum].number = entnum; + g_psv.baselines[entnum].entityType = 1; + + if (svent->v.flags & FL_CUSTOMENTITY) + g_psv.baselines[entnum].entityType = 2; + + __invokeValvesBuggedCreateBaseline((void *)gEntityInterface.pfnCreateBaseline, player, entnum, &(g_psv.baselines[entnum]), svent, sv_playermodel, player_mins[0], player_maxs[0]); + sv_lastnum = entnum; + } + } + } + gEntityInterface.pfnCreateInstancedBaselines(); + MSG_WriteByte(&g_psv.signon, svc_spawnbaseline); + MSG_StartBitWriting(&g_psv.signon); + for (entnum = 0; entnum < g_psv.num_edicts; entnum++) + { + svent = &g_psv.edicts[entnum]; + if (!svent->free && (g_psvs.maxclients >= entnum || svent->v.modelindex)) + { + MSG_WriteBits(entnum, 11); + MSG_WriteBits(g_psv.baselines[entnum].entityType, 2); + custom = ~g_psv.baselines[entnum].entityType & 1; + if (custom) + pDelta = g_pcustomentitydelta; + else + { + pDelta = g_pplayerdelta; + if (!SV_IsPlayerIndex(entnum)) + pDelta = g_pentitydelta; + } + + DELTA_WriteDelta((byte *)&nullstate, (byte *)&(g_psv.baselines[entnum]), TRUE, pDelta, NULL); + } + } + + MSG_WriteBits(0xFFFF, 16); + MSG_WriteBits(g_psv.instance_baselines->number, 6); + for (entnum = 0; entnum < g_psv.instance_baselines->number; entnum++) + DELTA_WriteDelta((byte *)&nullstate, (byte *)&(g_psv.instance_baselines->baseline[entnum]), TRUE, g_pentitydelta, NULL); + + MSG_EndBitWriting(&g_psv.signon); +} + +/* ../engine/sv_main.c:6969 */ +void SV_BroadcastCommand(char *fmt, ...) +{ + va_list argptr; + char string[1024]; + char data[128]; + sizebuf_t msg; + + if (!g_psv.active) + return; + + va_start(argptr, fmt); + msg.data = (byte *)data; + msg.buffername = "Broadcast Command"; + msg.cursize = 0; + msg.maxsize = sizeof(data); + msg.flags = SIZEBUF_ALLOW_OVERFLOW; + + Q_vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + MSG_WriteByte(&msg, svc_stufftext); + MSG_WriteString(&msg, string); + if (msg.flags & SIZEBUF_OVERFLOWED) + Sys_Error("SV_BroadcastCommand: Overflowed on %s, %i is max size\n", string, msg.maxsize); + + for (int i = 0; i < g_psvs.maxclients; ++i) + { + client_t *cl = &g_psvs.clients[i]; + if (cl->active || cl->connected || (cl->spawned && !cl->fakeclient)) + { + SZ_Write(&cl->netchan.message, msg.data, msg.cursize); + } + } +} + +/* ../engine/sv_main.c:7017 */ +void SV_BuildReconnect(sizebuf_t *msg) +{ + MSG_WriteByte(msg, svc_stufftext); + MSG_WriteString(msg, "reconnect\n"); +} + +/* ../engine/sv_main.c:7032 */ +NOXREF void SV_ReconnectAllClients(void) +{ + int i; + char message[34]; + Q_snprintf(message, sizeof(message), "Server updating Security Module.\n"); + + for (i = 0; i < g_psvs.maxclients; i++) + { + client_t *client = &g_psvs.clients[i]; + + if ((client->active || client->connected) && !client->fakeclient) + { + Netchan_Clear(&client->netchan); + + MSG_WriteByte(&client->netchan.message, svc_print); + MSG_WriteString(&client->netchan.message, message); + + MSG_WriteByte(&client->netchan.message, svc_stufftext); + MSG_WriteString(&client->netchan.message, "retry\n"); + + SV_DropClient(client, FALSE, message); + } + } + +} + +/* ../engine/sv_main.c:7068 */ +void SetCStrikeFlags(void) +{ + if (!g_bCS_CZ_Flags_Initialized) // TODO: Convert these to enum + { + if (!Q_stricmp(com_gamedir, "valve")) + { + g_bIsHL1 = 1; + } + else if (!Q_stricmp(com_gamedir, "cstrike") || !Q_stricmp(com_gamedir, "cstrike_beta")) + { + g_bIsCStrike = 1; + } + else if (!Q_stricmp(com_gamedir, "czero")) + { + g_bIsCZero = 1; + } + else if (!Q_stricmp(com_gamedir, "czeror")) + { + g_bIsCZeroRitual = 1; + } + else if (!Q_stricmp(com_gamedir, "terror")) + { + g_bIsTerrorStrike = 1; + } + else if (!Q_stricmp(com_gamedir, "tfc")) + { + g_bIsTFC = 1; + } + + g_bCS_CZ_Flags_Initialized = 1; + } +} + +/* ../engine/sv_main.c:7107 */ +void SV_ActivateServer(int runPhysics) +{ + int i; + unsigned char data[65536]; + sizebuf_t msg; + client_t *cl; + UserMsg *pTemp; + char szCommand[256]; + + Q_memset(&msg, 0, sizeof(sizebuf_t)); + msg.buffername = "Activate Server"; + msg.data = data; + msg.maxsize = sizeof(data); + msg.cursize = 0; + msg.flags = SIZEBUF_CHECK_OVERFLOW; + + SetCStrikeFlags(); + Cvar_Set("sv_newunit", "0"); + + ContinueLoadingProgressBar("Server", 8, 0.0f); + gEntityInterface.pfnServerActivate(g_psv.edicts, g_psv.num_edicts, g_psvs.maxclients); + Steam_Activate(); + ContinueLoadingProgressBar("Server", 9, 0.0f); + SV_CreateGenericResources(); + g_psv.active = TRUE; + g_psv.state = ss_active; + ContinueLoadingProgressBar("Server", 10, 0.0f); + + if (!runPhysics) + { + host_frametime = 0.001; + SV_Physics(); + } + else + { + if (g_psvs.maxclients <= 1) + { + host_frametime = 0.1; + SV_Physics(); + SV_Physics(); + } + else + { + host_frametime = 0.8; + for (i = 0; i < 16; i++) + SV_Physics(); + } + } + SV_CreateBaseline(); + SV_CreateResourceList(); + g_psv.num_consistency = SV_TransferConsistencyInfo(); + for (i = 0, cl = g_psvs.clients; i < g_psvs.maxclients; cl++, i++) + { + if (!cl->fakeclient && (cl->active || cl->connected)) + { + Netchan_Clear(&cl->netchan); + if (g_psvs.maxclients > 1) + { + SV_BuildReconnect(&cl->netchan.message); + Netchan_Transmit(&cl->netchan, 0, NULL); + } + else + SV_SendServerinfo(&msg, cl); + + if (sv_gpUserMsgs) + { + pTemp = sv_gpNewUserMsgs; + sv_gpNewUserMsgs = sv_gpUserMsgs; + SV_SendUserReg(&msg); + sv_gpNewUserMsgs = pTemp; + } + cl->hasusrmsgs = TRUE; + Netchan_CreateFragments(TRUE, &cl->netchan, &msg); + Netchan_FragSend(&cl->netchan); + SZ_Clear(&msg); + } + } + HPAK_FlushHostQueue(); + if (g_psvs.maxclients <= 1) + Con_DPrintf("Game Started\n"); + else + Con_DPrintf("%i player server started\n",g_psvs.maxclients); + Log_Printf("Started map \"%s\" (CRC \"%i\")\n", g_psv.name, g_psv.worldmapCRC); + + if (mapchangecfgfile.string && *mapchangecfgfile.string) + { + AlertMessage(at_console, "Executing map change config file\n"); + Q_sprintf(szCommand, "exec %s\n", mapchangecfgfile.string); + Cbuf_AddText(szCommand); + } +} + +/* ../engine/sv_main.c:7245 */ +void SV_ServerShutdown(void) +{ + Steam_NotifyOfLevelChange(); + gGlobalVariables.time = g_psv.time; + + if (g_psvs.dll_initialized) + { + if (g_psv.active) + gEntityInterface.pfnServerDeactivate(); + } +} +/* ../engine/sv_main.c:7265 */ +int SV_SpawnServer(qboolean bIsDemo, char *server, char *startspot) +{ + client_t *cl; + edict_t *ent; + int i; + char *pszhost; + char oldname[64]; + + if (g_psv.active) + { + cl = g_psvs.clients; + for (i = 0; i < g_psvs.maxclients; i++, cl++) + { + if (cl->active || cl->spawned || cl->connected) + { + ent = cl->edict; + if (ent == NULL || ent->free) + continue; + + if (ent->pvPrivateData) + gEntityInterface.pfnClientDisconnect(ent); + else + Con_Printf("Skipping reconnect on %s, no pvPrivateData\n", cl->name); + } + } + } + if (g_bOutOfDateRestart) + { + g_bOutOfDateRestart = FALSE; + Cmd_ExecuteString("quit\n", src_command); + } + + Log_Open(); + Log_Printf("Loading map \"%s\"\n", server); + Log_PrintServerVars(); + NET_Config((qboolean)(g_psvs.maxclients > 1)); + + pszhost = Cvar_VariableString("hostname"); + if (pszhost && *pszhost == '\0') + { + if (gEntityInterface.pfnGetGameDescription != NULL) + Cvar_Set("hostname", gEntityInterface.pfnGetGameDescription()); + else + Cvar_Set("hostname", "Half-Life"); + } + + scr_centertime_off = 0.0f; + if (startspot) + Con_DPrintf("Spawn Server %s: [%s]\n", server, startspot); + else + Con_DPrintf("Spawn Server %s\n", server); + + g_LastScreenUpdateTime = 0.0f; + g_psvs.spawncount = ++gHostSpawnCount; + + if (coop.value != 0.0f) + Cvar_SetValue("deathmatch", 0.0f); + + current_skill = (int)(skill.value + 0.5f); + if (current_skill < 0) + current_skill = 0; + else if (current_skill > 3) + current_skill = 3; + + Cvar_SetValue("skill", current_skill); + ContinueLoadingProgressBar("Server", 2, 0.0f); + + HPAK_CheckSize("custom"); + oldname[0] = 0; + Q_strncpy(oldname, g_psv.name, sizeof(oldname) - 1); + oldname[sizeof(oldname) - 1] = 0; + Host_ClearMemory(FALSE); + + cl = g_psvs.clients; + for (i = 0; i < g_psvs.maxclientslimit; i++, cl++) + SV_ClearFrames(&cl->frames); + + SV_UPDATE_BACKUP = g_psvs.maxclients != 1 ? 64 : 8; + SV_UPDATE_MASK = g_psvs.maxclients != 1 ? 63 : 7; + + SV_AllocClientFrames(); + Q_memset(&g_psv, 0, sizeof(server_t)); + Q_strncpy(g_psv.oldname, oldname, sizeof(oldname) - 1); + g_psv.oldname[sizeof(oldname) - 1] = 0; + Q_strncpy(g_psv.name, server, sizeof(g_psv.name) - 1); + g_psv.name[sizeof(g_psv.name) - 1] = 0; + + if (startspot) + { + Q_strncpy(g_psv.startspot, startspot, sizeof(g_psv.startspot) - 1); + g_psv.startspot[sizeof(g_psv.startspot) - 1] = 0; + } + else + g_psv.startspot[0] = 0; + + pr_strings = gNullString; + gGlobalVariables.pStringBase = gNullString; + + if (g_psvs.maxclients == 1) + Cvar_SetValue("sv_clienttrace", 1.0); + + g_psv.max_edicts = COM_EntsForPlayerSlots(g_psvs.maxclients); + + SV_DeallocateDynamicData(); + SV_ReallocateDynamicData(); + + gGlobalVariables.maxEntities = g_psv.max_edicts; + + g_psv.edicts = (edict_t *)Hunk_AllocName(sizeof(edict_t) * g_psv.max_edicts, "edicts"); + g_psv.baselines = (entity_state_s *)Hunk_AllocName(sizeof(entity_state_t) * g_psv.max_edicts, "baselines"); + + g_psv.datagram.buffername = "Server Datagram"; + g_psv.datagram.data = g_psv.datagram_buf; + g_psv.datagram.maxsize = sizeof(g_psv.datagram_buf); + g_psv.datagram.cursize = 0; + + g_psv.reliable_datagram.buffername = "Server Reliable Datagram"; + g_psv.reliable_datagram.data = g_psv.reliable_datagram_buf; + g_psv.reliable_datagram.maxsize = sizeof(g_psv.reliable_datagram_buf); + g_psv.reliable_datagram.cursize = 0; + + g_psv.spectator.buffername = "Server Spectator Buffer"; + g_psv.spectator.data = g_psv.spectator_buf; + g_psv.spectator.maxsize = sizeof(g_psv.spectator_buf); + + g_psv.multicast.buffername = "Server Multicast Buffer"; + g_psv.multicast.data = g_psv.multicast_buf; + g_psv.multicast.maxsize = sizeof(g_psv.multicast_buf); + + g_psv.signon.buffername = "Server Signon Buffer"; + g_psv.signon.data = g_psv.signon_data; + g_psv.signon.maxsize = sizeof(g_psv.signon_data); + g_psv.signon.cursize = 0; + + g_psv.num_edicts = g_psvs.maxclients + 1; + + cl = g_psvs.clients; + for (i = 1; i < g_psvs.maxclients; i++, cl++) + cl->edict = &g_psv.edicts[i]; + + gGlobalVariables.maxClients = g_psvs.maxclients; + g_psv.time = 1.0f; + g_psv.state = ss_loading; + g_psv.paused = FALSE; + gGlobalVariables.time = 1.0f; + + R_ForceCVars((qboolean)(g_psvs.maxclients > 1)); + ContinueLoadingProgressBar("Server", 3, 0.0f); + + Q_snprintf(g_psv.modelname, sizeof(g_psv.modelname), "maps/%s.bsp", server); + g_psv.worldmodel = Mod_ForName(g_psv.modelname, FALSE, FALSE); + + if (!g_psv.worldmodel) + { + Con_Printf("Couldn't spawn server %s\n", g_psv.modelname); + g_psv.active = FALSE; + return 0; + } + + Sequence_OnLevelLoad(server); + ContinueLoadingProgressBar("Server", 4, 0.0); + if (gmodinfo.clientDllCRC) + { + char szDllName[64]; + Q_snprintf(szDllName, sizeof(szDllName), "cl_dlls//client.dll"); + COM_FixSlashes(szDllName); + if (!MD5_Hash_File(g_psv.clientdllmd5, szDllName, FALSE, FALSE, NULL)) + { + Con_Printf("Couldn't CRC client side dll: %s\n", szDllName); + g_psv.active = FALSE; + return 0; + } + } + ContinueLoadingProgressBar("Server", 6, 0.0); + + if (g_psvs.maxclients <= 1) + g_psv.worldmapCRC = 0; + else + { + CRC32_Init(&g_psv.worldmapCRC); + if (!CRC_MapFile(&g_psv.worldmapCRC, g_psv.modelname)) + { + Con_Printf("Couldn't CRC server map: %s\n", g_psv.modelname); + g_psv.active = FALSE; + return 0; + } + CM_CalcPAS(g_psv.worldmodel); + } + + g_psv.models[1] = g_psv.worldmodel; + SV_ClearWorld(); + g_psv.model_precache_flags[1] |= RES_FATALIFMISSING; + g_psv.model_precache[1] = g_psv.modelname; + + g_psv.sound_precache[0] = pr_strings; + g_psv.model_precache[0] = pr_strings; + g_psv.generic_precache[0] = pr_strings; + + for (i = 1; i < g_psv.worldmodel->numsubmodels; i++) + { + g_psv.model_precache[i + 1] = localmodels[i]; + g_psv.models[i + 1] = Mod_ForName(localmodels[i], FALSE, FALSE); + g_psv.model_precache_flags[i + 1] |= RES_FATALIFMISSING; + } + + Q_memset(&g_psv.edicts->v, 0, sizeof(entvars_t)); + + g_psv.edicts->free = FALSE; + g_psv.edicts->v.modelindex = 1; + g_psv.edicts->v.model = (size_t)g_psv.worldmodel - (size_t)pr_strings; + g_psv.edicts->v.solid = SOLID_BSP; + g_psv.edicts->v.movetype = MOVETYPE_PUSH; + + if (coop.value == 0.0f) + gGlobalVariables.deathmatch_ = deathmatch.value; + else + gGlobalVariables.coop_ = coop.value; + + gGlobalVariables.serverflags = g_psvs.serverflags; + gGlobalVariables.mapname = (size_t)g_psv.name - (size_t)pr_strings; + gGlobalVariables.startspot = (size_t)g_psv.startspot - (size_t)pr_strings; + allow_cheats = sv_cheats.value; + SV_SetMoveVars(); + + return 1; +} + +/* ../engine/sv_main.c:7586 */ +void SV_LoadEntities(void) +{ + ED_LoadFromFile(g_psv.worldmodel->entities); +} + +/* ../engine/sv_main.c:7592 */ +void SV_ClearEntities(void) +{ + int i; + edict_t *pEdict; + + for (i = 0; i < g_psv.num_edicts; i++) + { + pEdict = &g_psv.edicts[i]; + + if (!pEdict->free) + ReleaseEntityDLLFields(pEdict); + } +} +/* ../engine/sv_main.c:7620 */ +int RegUserMsg(const char *pszName, int iSize) +{ + if (giNextUserMsg > 255 || !pszName || Q_strlen(pszName) > 11 || iSize > 192) + return 0; + + UserMsg *pUserMsgs = sv_gpUserMsgs; + while (pUserMsgs) + { + if (!Q_strcmp(pszName, pUserMsgs->szName)) + return pUserMsgs->iMsg; + + pUserMsgs = pUserMsgs->next; + } + + UserMsg *pNewMsg = (UserMsg *)Mem_ZeroMalloc(sizeof(UserMsg)); + pNewMsg->iMsg = giNextUserMsg++; + pNewMsg->iSize = iSize; + Q_strcpy(pNewMsg->szName, pszName); + pNewMsg->next = sv_gpNewUserMsgs; + sv_gpNewUserMsgs = pNewMsg; + + return pNewMsg->iMsg; +} + +/* ../engine/sv_main.c:7717 */ +qboolean StringToFilter(const char *s, ipfilter_t *f) +{ + char num[128]; + unsigned char b[4] = { 0, 0, 0, 0 }; + unsigned char m[4] = { 0, 0, 0, 0 }; + + const char* cc = s; + int i = 0; + while (1) + { + if (*cc < '0' || *cc > '9') + break; + + int j = 0; +#ifdef REHLDS_FIXES + //check num for overflow + while (*cc >= '0' && *cc <= '9' && j < sizeof(num)) + num[j++] = *(cc++); + + if (j >= sizeof(num)) + break; +#else // REHLDS_FIXES + while (*cc >= '0' && *cc <= '9') + num[j++] = *(cc++); +#endif // REHLDS_FIXES + + num[j] = 0; + b[i] = Q_atoi(num); + if (b[i]) + m[i] = -1; + + if (*cc) + { + ++cc; + ++i; + if (i < 4) + continue; + } + f->mask = *(uint32_t *)m; + f->compare.u32 = *(uint32_t *)b; + return TRUE; + } + Con_Printf("Bad filter address: %s\n", cc); + return FALSE; +} + +/* ../engine/sv_main.c:7765 */ +USERID_t *SV_StringToUserID(const char *str) +{ + static USERID_t id; + Q_memset(&id, 0, sizeof(id)); + +#ifdef REHLDS_FIXES + if (!str || Q_strlen(str) < 7) //also check the length of identifier + return &id; +#else + if (!str || !*str) + return &id; +#endif + + char szTemp[128]; + const char *pszUserID = str + 6; + if (Q_strnicmp(str, "STEAM_", 6)) + { + Q_strncpy(szTemp, pszUserID, sizeof(szTemp) - 1); + id.idtype = 2; + } + else + { + Q_strncpy(szTemp, pszUserID, sizeof(szTemp) - 1); + id.idtype = 1; + } + szTemp[127] = 0; + id.m_SteamID = Steam_StringToSteamID(szTemp); + + return &id; +} + +/* ../engine/sv_main.c:7799 */ +void SV_BanId_f(void) +{ + char szreason[256]; + char idstring[64]; + + if (Cmd_Argc() < 3 || Cmd_Argc() > 8) + { + Con_Printf("Usage: banid { kick }\n"); + Con_Printf("Use 0 minutes for permanent\n"); + return; + } + + float banTime = Q_atof(Cmd_Argv(1)); + if (banTime < 0.01f) + banTime = 0.0f; + + Q_strncpy(idstring, Cmd_Argv(2), sizeof(idstring)); + idstring[63] = 0; + + qboolean bKick; + if (Cmd_Argc() > 3 && !Q_stricmp(Cmd_Argv(Cmd_Argc() - 1), "kick")) + bKick = TRUE; + else + bKick = FALSE; + + USERID_t *id = NULL; + if (idstring[0] == '#') + { + int search; + if (Q_strlen(idstring) == 1) + { + if (Cmd_Argc() < 3) + { + Con_Printf("Insufficient arguments to banid\n"); + return; + } + search = Q_atoi(Cmd_Argv(3)); + } + else + search = Q_atoi(&idstring[1]); + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + if ((!cl->active && !cl->connected && !cl->spawned) || cl->fakeclient) + continue; + + if (cl->userid == search) + { + id = &cl->network_userid; + break; + } + } + if (id == NULL) + { + Con_Printf(__FUNCTION__ ": Couldn't find #userid %u\n", search); + return; + } + } + else + { + if (!Q_strnicmp(idstring, "STEAM_", 6) || !Q_strnicmp(idstring, "VALVE_", 6)) + { + Q_snprintf(idstring, sizeof(idstring) - 1, "%s:%s:%s", Cmd_Argv(2), Cmd_Argv(4), Cmd_Argv(6)); + idstring[63] = 0; + } + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + if (!cl->active && !cl->connected && !cl->spawned || cl->fakeclient) + continue; + + if (!Q_stricmp(SV_GetClientIDString(cl), idstring)) + { + id = &cl->network_userid; + break; + } + } + if (id == NULL) + id = SV_StringToUserID(idstring); + + if (id == NULL) + { + Con_Printf(__FUNCTION__ ": Couldn't resolve uniqueid %s.\n", idstring); + Con_Printf("Usage: banid { kick }\n"); + Con_Printf("Use 0 minutes for permanent\n"); + return; + } + } + + int i = 0; + for (i = 0; i < numuserfilters; i++) + { + if (SV_CompareUserID(&userfilters[i].userid, id)) + break; + } + + if (i >= numuserfilters) + { + if (numuserfilters >= 32768) + { + Con_Printf(__FUNCTION__ ": User filter list is full\n"); + return; + } + numuserfilters++; + } + + userfilters[i].banTime = banTime; + userfilters[i].banEndTime = (banTime == 0.0f) ? 0.0f : banTime * 60.0f + realtime; + + memcpy(&userfilters[i].userid, id, sizeof(USERID_t)); + + // give 3-rd party plugins a chance to serialize ID + g_RehldsHookchains.m_SerializeSteamId.callChain(NULL, &userfilters[i].userid); + + if (banTime == 0.0f) + sprintf(szreason, "permanently"); + else + Q_snprintf(szreason, sizeof(szreason), "for %.2f minutes", banTime); + + const char *pszCmdGiver; + if (cmd_source == src_command) + { +#ifndef SWDS + pszCmdGiver = (g_pcls.state != ca_dedicated) ? cv_name.string : "Console"; +#else + pszCmdGiver = "Console"; +#endif // SWDS + } + else + pszCmdGiver = host_client->name; + + if (!bKick) + { + if (sv_logbans.value != 0.0f) + Log_Printf("Ban: \"<><%s><>\" was banned \"%s\" by \"%s\"\n", SV_GetIDString(id), szreason, pszCmdGiver); + + return; + } + + client_t *save = host_client; + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + if (!cl->active && !cl->connected && !cl->spawned || cl->fakeclient) + continue; + + if (SV_CompareUserID(&cl->network_userid, id)) + { + host_client = cl; + if (sv_logbans.value != 0.0f) + { + Log_Printf( + "Ban: \"%s<%i><%s><>\" was kicked and banned \"%s\" by \"%s\"\n", + host_client->name, host_client->userid, SV_GetClientIDString(host_client), szreason, pszCmdGiver + ); + } + SV_ClientPrintf("You have been kicked and banned %s by the server op.\n", szreason); + SV_DropClient(host_client, FALSE, "Kicked and banned"); + break; + } + } + host_client = save; +} + +/* ../engine/sv_main.c:8040 */ +void Host_Kick_f(void) +{ + const char *p; + char idstring[64]; + int argsStartNum; + + qboolean isSteam = FALSE; + qboolean found = FALSE; + + if (Cmd_Argc() <= 1) + { + Con_Printf("usage: kick < name > | < # userid >\n"); + return; + } + + if (cmd_source == src_command) + { + if (!g_psv.active) + { + Cmd_ForwardToServer(); + return; + } + } + else + { + if (host_client->netchan.remote_address.type != NA_LOOPBACK) + { + SV_ClientPrintf("You can't 'kick' because you are not a server operator\n"); + return; + } + } + + client_t *save = host_client; + p = Cmd_Argv(1); + if (p && *p == '#') + { + int searchid; + if (Cmd_Argc() <= 2 || p[1]) + { + p++; + argsStartNum = 2; + searchid = Q_atoi(p); + } + else + { + searchid = Q_atoi(Cmd_Argv(2)); + p = Cmd_Argv(2); + argsStartNum = 3; + } + + strncpy(idstring, p, 63); + idstring[63] = 0; + + if (!Q_strnicmp(idstring, "STEAM_", 6) || !Q_strnicmp(idstring, "VALVE_", 6)) + { + Q_snprintf(idstring, 63, "%s:%s:%s", p, Cmd_Argv(argsStartNum + 1), Cmd_Argv(argsStartNum + 3)); + + argsStartNum += 4; + idstring[63] = 0; + isSteam = 1; + } + + for (int i = 0; i < g_psvs.maxclients; i++) + { + host_client = &g_psvs.clients[i]; + if (!host_client->active && !host_client->connected) + continue; + + if (searchid && host_client->userid == searchid) + { + found = TRUE; + break; + } + + if (Q_stricmp(SV_GetClientIDString(host_client), idstring) == 0) + { + found = TRUE; + break; + } + } + } + else + { + for (int i = 0; i < g_psvs.maxclients; i++) + { + host_client = &g_psvs.clients[i]; + if (!host_client->active && !host_client->connected) + continue; + + if (!Q_stricmp(host_client->name, Cmd_Argv(1))) + { + found = TRUE; + break; + } + + } + argsStartNum = 2; + } + + if (found) + { + const char *who; + if (cmd_source == src_command) + { +#ifndef SWDS + who = (g_pcls.state != ca_dedicated) ? cv_name.string : "Console"; +#else + who = "Console"; +#endif // SWDS + } + else + { + who = save->name; + } + + if (host_client->netchan.remote_address.type == NA_LOOPBACK) + { + Con_Printf("The local player cannot be kicked!\n"); +#ifdef REHLDS_FIXES + host_client = save; +#endif // REHLDS_FIXES + return; + } + + if (Cmd_Argc() > argsStartNum) + { + unsigned int dataLen = 0; + for (int i = 1; i < argsStartNum; i++) + { + dataLen += strlen(Cmd_Argv(i)) + 1; + } + + if (isSteam) + dataLen -= 4; + + p = Cmd_Args(); + if (dataLen <= strlen(p)) + { + const char *message = dataLen + p; + if (message) + { + SV_ClientPrintf("Kicked by %s: %s\n", who, message); + Log_Printf( + "Kick: \"%s<%i><%s><>\" was kicked by \"%s\" (message \"%s\")\n", + host_client->name, host_client->userid, SV_GetClientIDString(host_client), who, message + ); + SV_DropClient(host_client, 0, va("Kicked :%s", message)); + host_client = save; + return; + } + } + } + + SV_ClientPrintf("Kicked by %s\n", who); + Log_Printf("Kick: \"%s<%i><%s><>\" was kicked by \"%s\"\n", host_client->name, host_client->userid, SV_GetClientIDString(host_client), who); + SV_DropClient(host_client, 0, "Kicked"); + } + host_client = save; +} + +/* ../engine/sv_main.c:8237 */ +void SV_RemoveId_f(void) +{ + char idstring[64]; + + if (Cmd_Argc() != 2 && Cmd_Argc() != 6) + { + Con_Printf("Usage: removeid \n"); + return; + } + + strncpy(idstring, Cmd_Argv(1), sizeof(idstring) - 1); + idstring[63] = 0; + if (!idstring[0]) + { + Con_Printf(__FUNCTION__ ": Id string is empty!\n"); + return; + } + + if (idstring[0] == '#') + { + int slot = Q_atoi(&idstring[1]); + if (slot <= 0 || slot > numuserfilters) + { + Con_Printf(__FUNCTION__ ": invalid slot #%i\n", slot); + return; + } + slot--; + + USERID_t id; + memcpy(&id, &userfilters[slot].userid, sizeof(id)); + + if (slot + 1 < numuserfilters) + memcpy(&userfilters[slot], &userfilters[slot + 1], (numuserfilters - (slot + 1)) * sizeof(userfilter_t)); + + numuserfilters--; + Con_Printf("UserID filter removed for %s, id %s\n", idstring, SV_GetIDString(&id)); + } + else + { + if (!Q_strnicmp(idstring, "STEAM_", 6) || !Q_strnicmp(idstring, "VALVE_", 6)) + { + _snprintf(idstring, 0x3Fu, "%s:%s:%s", Cmd_Argv(1), Cmd_Argv(3), Cmd_Argv(5)); + idstring[63] = 0; + } + + for (int i = 0; i < numuserfilters; i++) + { + if (!Q_stricmp(SV_GetIDString(&userfilters[i].userid), idstring)) + { + if (i + 1 < numuserfilters) + memcpy(&userfilters[i], &userfilters[i + 1], (numuserfilters - (i + 1)) * sizeof(userfilter_t)); + + numuserfilters--; + Con_Printf("UserID filter removed for %s\n", idstring); + return; + } + } + + Con_Printf("removeid: couldn't find %s\n", idstring); + } +} + +/* ../engine/sv_main.c:8320 */ +void SV_WriteId_f(void) +{ + char name[MAX_PATH]; + _snprintf(name, MAX_PATH, "%s", bannedcfgfile.string); + Con_Printf("Writing %s.\n", name); + + FILE *f = FS_Open(name, "wt"); + if (!f) + { + Con_Printf("Couldn't open %s\n", name); + return; + } + + for (int i = 0; i < numuserfilters; i++) + { + if (userfilters[i].banTime != 0.0f) + continue; + + FS_FPrintf(f, "banid 0.0 %s\n", SV_GetIDString(&userfilters[i].userid)); + } + + FS_Close(f); +} + +/* ../engine/sv_main.c:8358 */ +void SV_ListId_f(void) +{ + if (numuserfilters <= 0) + { + Con_Printf("UserID filter list: empty\n"); + return; + } + + Con_Printf("UserID filter list: %i entries\n", numuserfilters); + for (int i = 0; i < numuserfilters; i++) + { + if (userfilters[i].banTime == 0.0f) + { + Con_Printf("%i %s : permanent\n", i, SV_GetIDString(&userfilters[i].userid)); + } + else + { + Con_Printf("%i %s : %.3f min\n", i, SV_GetIDString(&userfilters[i].userid), userfilters[i].banTime); + } + } +} + +/* ../engine/sv_main.c:8388 */ +void SV_AddIP_f(void) +{ + if (Cmd_Argc() != 3) + { + Con_Printf("Usage: addip \nUse 0 minutes for permanent\n"); + return; + } + + float banTime = Q_atof(Cmd_Argv(1)); + ipfilter_t tempFilter; + if (!StringToFilter(Cmd_Argv(2), &tempFilter)) + { + Con_Printf("Invalid IP address!\nUsage: addip \nUse 0 minutes for permanent\n"); + return; + } + + int i = 0; + for (; i < numipfilters; i++) + { + if (ipfilters[i].mask == tempFilter.mask && ipfilters[i].compare.u32 == tempFilter.compare.u32) + { + ipfilters[i].banTime = banTime; + ipfilters[i].banEndTime = (banTime == 0.0f) ? 0.0f : banTime * 60.0f + realtime; + return; + } + } + + if (numipfilters >= 32768) + { + Con_Printf("IP filter list is full\n"); + return; + } + + ++numipfilters; + if (banTime < 0.0099999998f) + banTime = 0.0f; + + ipfilters[i].banTime = banTime; + ipfilters[i].compare = tempFilter.compare; + ipfilters[i].banEndTime = (banTime == 0.0f) ? 0.0f : banTime * 60.0f + realtime; + ipfilters[i].mask = tempFilter.mask; + + for (int i = 0; i < g_psvs.maxclients; i++) + { + host_client = &g_psvs.clients[i]; + if (!host_client->connected || !host_client->active || !host_client->spawned || host_client->fakeclient) + continue; + + memcpy(&net_from, &host_client->netchan.remote_address, sizeof(net_from)); + if (SV_FilterPacket()) + { + SV_ClientPrintf("The server operator has added you to banned list\n"); + SV_DropClient(host_client, 0, "Added to banned list");; + } + } +} + +/* ../engine/sv_main.c:8470 */ +void SV_RemoveIP_f(void) +{ + ipfilter_t f; + + if (!StringToFilter(Cmd_Argv(1), &f)) + return; + + for (int i = 0; i < numipfilters; i++) + { + if (ipfilters[i].mask == f.mask && ipfilters[i].compare.u32 == f.compare.u32) + { + if (i + 1 < numipfilters) + memcpy(&ipfilters[i], &ipfilters[i + 1], (numipfilters - (i + 1)) * sizeof(ipfilter_t)); + numipfilters--; + ipfilters[numipfilters].banTime = 0.0f; + ipfilters[numipfilters].banEndTime = 0.0f; + ipfilters[numipfilters].compare.u32 = 0; + ipfilters[numipfilters].mask = 0; + Con_Printf("IP filter removed.\n"); + + return; + } + } + Con_Printf("removeip: couldn't find %s.\n", Cmd_Argv(1)); +} + +/* ../engine/sv_main.c:8507 */ +void SV_ListIP_f(void) +{ + if (numipfilters <= 0) + { + Con_Printf("IP filter list: empty\n"); + return; + } + + Con_Printf("IP filter list:\n"); + for (int i = 0; i < numipfilters; i++) + { + uint8_t* b = ipfilters[i].compare.octets; + if (ipfilters[i].banTime == 0.0f) + Con_Printf("%3i.%3i.%3i.%3i : permanent\n", b[0], b[1], b[2], b[3]); + else + Con_Printf("%3i.%3i.%3i.%3i : %.3f min\n", b[0], b[1], b[2], b[3], ipfilters[i].banTime); + } +} + +/* ../engine/sv_main.c:8535 */ +void SV_WriteIP_f(void) +{ + char name[MAX_PATH]; + Q_snprintf(name, MAX_PATH, "listip.cfg"); + Con_Printf("Writing %s.\n", name); + + FILE *f = FS_Open(name, "wb"); + if (!f) + { + Con_Printf("Couldn't open %s\n", name); + return; + } + + for (int i = 0; i < numipfilters; i++) + { + if (ipfilters[i].banTime != 0.0f) + continue; + + uint8_t *b = ipfilters[i].compare.octets; + FS_FPrintf(f, "addip 0.0 %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]); + } + FS_Close(f); +} + +/* ../engine/sv_main.c:8569 */ +void SV_KickPlayer(int nPlayerSlot, int nReason) +{ + if (nPlayerSlot < 0 || nPlayerSlot >= g_psvs.maxclients) + return; + + client_t * client = &g_psvs.clients[nPlayerSlot]; + if (!client->connected || !g_psvs.isSecure) + return; + + USERID_t id; + memcpy(&id, &client->network_userid, sizeof(id)); + + Log_Printf("Secure: \"%s<%i><%s><>\" was detected cheating and dropped from the server.\n", client->name, client->userid, SV_GetIDString(&id), nReason); + + char rgchT[1024]; + rgchT[0] = svc_print; + sprintf( + &rgchT[1], + "\n********************************************\nYou have been automatically disconnected\nfrom this secure server because an illegal\ncheat was detected on your computer.\nRepeat violators may be permanently banned\nfrom all secure servers.\n\nFor help cleaning your system of cheats, visit:\nhttp://www.counter-strike.net/cheat.html\n********************************************\n\n" + ); + Netchan_Transmit(&g_psvs.clients[nPlayerSlot].netchan, strlen(rgchT) + 1, (byte *)rgchT); + + sprintf(rgchT, "%s was automatically disconnected\nfrom this secure server.\n", client->name); + for (int i = 0; i < g_psvs.maxclients; i++) + { + if (!g_psvs.clients[i].active && !g_psvs.clients[i].spawned || g_psvs.clients[i].fakeclient) + continue; + + MSG_WriteByte(&g_psvs.clients[i].netchan.message, svc_centerprint); + MSG_WriteString(&g_psvs.clients[i].netchan.message, rgchT); + } + + SV_DropClient(&g_psvs.clients[nPlayerSlot], FALSE, "Automatically dropped by cheat detector"); +} + +/* ../engine/sv_main.c:8639 */ +void SV_InactivateClients(void) +{ + int i; + client_t *cl; + for (i = 0, cl = g_psvs.clients; i < g_psvs.maxclients; i++, cl++) + { + if (!cl->active && !cl->connected && !cl->spawned) + continue; + + if (cl->fakeclient) + SV_DropClient(cl, FALSE, "Dropping fakeclient on level change"); + else + { + cl->active = FALSE; + cl->connected = TRUE; + cl->spawned = FALSE; + cl->fully_connected = FALSE; + + SZ_Clear(&cl->netchan.message); + SZ_Clear(&cl->datagram); + + COM_ClearCustomizationList(&cl->customdata, FALSE); + Q_memset(cl->physinfo, 0, MAX_PHYSINFO_STRING); + } + } +} + +/* ../engine/sv_main.c:8676 */ +void SV_FailDownload(const char *filename) +{ + if (filename && *filename) + { + MSG_WriteByte(&host_client->netchan.message, svc_filetxferfailed); + MSG_WriteString(&host_client->netchan.message, filename); + } +} + +/* ../engine/sv_main.c:8686 */ +//----------------------------------------------------------------------------- +// Finds a string in another string with a case insensitive test +//----------------------------------------------------------------------------- +const char *Q_stristr(const char *pStr, const char *pSearch) +{ + if (!pStr || !pSearch) + return NULL; + + char const *pLetter = pStr; + + // Check the entire string + while (*pLetter != 0) + { + // Skip over non-matches + if (tolower(*pLetter) == tolower(*pSearch)) + { + // Check for match + char const* pMatch = pLetter + 1; + char const* pTest = pSearch + 1; + while (*pTest != 0) + { + // We've run off the end; don't bother. + if (*pMatch == 0) + return NULL; + + if (tolower(*pMatch) != tolower(*pTest)) + break; + + ++pMatch; + ++pTest; + } + + // Found a match! + if (*pTest == 0) + return pLetter; + } + + ++pLetter; + } + + return NULL; +} + +/* ../engine/sv_main.c:8736 */ +qboolean IsSafeFileToDownload(const char *filename) +{ + char *first; + char *last; + char lwrfilename[MAX_PATH]; + + if (!filename) + { + return FALSE; + } + +#ifdef REHLDS_FIXES + // FIXED: Allow to download customizations + if (filename[0] == '!') + { + return TRUE; + } +#endif // REHLDS_FIXES + + // Convert to lower case + Q_strncpy(lwrfilename, filename, sizeof(lwrfilename)); + Q_strlwr(lwrfilename); + + first = Q_strchr(lwrfilename, '.'); + last = Q_strrchr(lwrfilename, '.'); + + if (lwrfilename[0] == '/' + || Q_strstr(lwrfilename, "\\") + || Q_strstr(lwrfilename, ":") + || Q_strstr(lwrfilename, "..") + || Q_strstr(lwrfilename, "~") + || first != last + || !first + || Q_strlen(first) != 4 + || Q_stristr(lwrfilename, ".cfg") + || Q_stristr(lwrfilename, ".lst") + || Q_stristr(lwrfilename, ".exe") + || Q_stristr(lwrfilename, ".vbs") + || Q_stristr(lwrfilename, ".com") + || Q_stristr(lwrfilename, ".bat") + || Q_stristr(lwrfilename, ".dll") + || Q_stristr(lwrfilename, ".ini") + || Q_stristr(lwrfilename, ".log") + || Q_stristr(lwrfilename, "halflife.wad") + || Q_stristr(lwrfilename, "pak0.pak") + || Q_stristr(lwrfilename, "xeno.wad") + || Q_stristr(lwrfilename, ".so") + || Q_stristr(lwrfilename, ".dylib") + || Q_stristr(lwrfilename, ".sys")) + { + return FALSE; + } + return TRUE; +} + +/* ../engine/sv_main.c:8835 */ +void SV_BeginFileDownload_f(void) +{ + const char *name; + char szModuleC[13] = "!ModuleC.dll"; + + if (Cmd_Argc() < 2 || cmd_source == src_command) + { + return; + } + + name = Cmd_Argv(1); + if (!name || !name[0] || (!Q_strncmp(name, szModuleC, 12) && g_psvs.isSecure)) + { + return; + } + + if (!IsSafeFileToDownload(name) || sv_allow_download.value == 0.0f) + { + SV_FailDownload(name); + return; + } + + // Regular downloads + if (name[0] != '!') + { + if (host_client->fully_connected || + sv_send_resources.value == 0.0f || + sv_downloadurl.string != NULL && sv_downloadurl.string[0] != 0 && Q_strlen(sv_downloadurl.string) <= 128 && sv_allow_dlfile.value == 0.0f || + Netchan_CreateFileFragments(TRUE, &host_client->netchan, name) == 0) + { + SV_FailDownload(name); + return; + } + Netchan_FragSend(&host_client->netchan); + return; + } + + // Customizations + if (Q_strlen(name) != 36 || Q_strnicmp(name, "!MD5", 4) != 0 || sv_send_logos.value == 0.0f) + { + SV_FailDownload(name); + return; + } + + unsigned char md5[16]; + resource_t custResource; + unsigned char *pbuf = NULL; + int size = 0; + + Q_memset(&custResource, 0, sizeof(custResource)); + COM_HexConvert(name + 4, 32, md5); + if (HPAK_ResourceForHash("custom.hpk", md5, &custResource)) + { + HPAK_GetDataPointer("custom.hpk", &custResource, &pbuf, &size); +#ifdef REHLDS_FIXES + if (pbuf && size) + { + Netchan_CreateFileFragmentsFromBuffer(1, &host_client->netchan, name, pbuf, size); + Netchan_FragSend(&host_client->netchan); + } + // Mem_Free pbuf even if size is zero + if (pbuf) + { + Mem_Free((void *)pbuf); + } +#else // REHLDS_FIXES + if (pbuf && size) + { + Netchan_CreateFileFragmentsFromBuffer(1, &host_client->netchan, name, pbuf, size); + Netchan_FragSend(&host_client->netchan); + Mem_Free((void *)pbuf); + } +#endif // REHLDS_FIXES + } + +#ifdef REHLDS_FIXES + // TODO: Shouldn't we SV_FailDownload if hpak do not contain resource? Ok, let's do it + if (pbuf == NULL || size == 0) + { + SV_FailDownload(name); + } +#endif // REHLDS_FIXES +} + +/* ../engine/sv_main.c:8942 */ +void SV_SetMaxclients(void) +{ + int i; + client_t *cl; + + for (i = 0, cl = g_psvs.clients; i < g_psvs.maxclientslimit; i++, cl++) + SV_ClearFrames(&cl->frames); + + g_psvs.maxclients = 1; + i = COM_CheckParm("-maxplayers"); + + if (i) + g_psvs.maxclients = Q_atoi(com_argv[i + 1]); + else + { + if (g_bIsDedicatedServer) + g_psvs.maxclients = 6; + } + + g_pcls.state = (cactive_t)(g_bIsDedicatedServer == FALSE); + + if (g_psvs.maxclients > 32) + g_psvs.maxclients = 32; + if (g_psvs.maxclients < 1) + g_psvs.maxclients = 6; + + if (g_bIsDedicatedServer) + g_psvs.maxclientslimit = 32; + else if(host_parms.memsize > 0x1000000) + g_psvs.maxclientslimit = 4; + + SV_UPDATE_BACKUP = 8; + SV_UPDATE_MASK = 7; + + if(g_psvs.maxclients != 1) + { + SV_UPDATE_BACKUP = 64; + SV_UPDATE_MASK = 63; + } + + g_psvs.clients = (client_t *)Hunk_AllocName(sizeof(client_t) * g_psvs.maxclientslimit, "clients"); + for (i = 0, cl = g_psvs.clients; i < g_psvs.maxclientslimit; i++, cl++) + { + Q_memset(cl, 0, sizeof(client_t)); + + cl->resourcesneeded.pPrev = &cl->resourcesneeded; + cl->resourcesneeded.pNext = &cl->resourcesneeded; + cl->resourcesonhand.pPrev = &cl->resourcesonhand; + cl->resourcesonhand.pNext = &cl->resourcesonhand; + } + if (g_psvs.maxclients >= 2) + Cvar_SetValue("deathmatch", 1.0); + else Cvar_SetValue("deathmatch", 0.0); + SV_AllocClientFrames(); + + if (g_psvs.maxclientslimit < g_psvs.maxclients) + g_psvs.maxclients = g_psvs.maxclientslimit; + + Rehlds_Interfaces_InitClients(); +} + +/* ../engine/sv_main.c:9033 */ +void SV_HandleRconPacket(void) +{ + MSG_BeginReading(); + MSG_ReadLong(); + char* s = MSG_ReadStringLine(); + Cmd_TokenizeString(s); + const char* c = Cmd_Argv(0); + if (!Q_strcmp(c, "getchallenge")) + { + SVC_GetChallenge(); + } + else if (!Q_stricmp(c, "challenge")) + { + SVC_ServiceChallenge(); + } + else if (!Q_strcmp(c, "rcon")) + { + SV_Rcon(&net_from); + } +} + +/* ../engine/sv_main.c:9065 */ +void SV_CheckCmdTimes(void) +{ + static double lastreset; + + if (Host_IsSinglePlayerGame()) + return; + + if (realtime - lastreset < 1.0) + return; + + lastreset = realtime; + for (int i = g_psvs.maxclients - 1; i >= 0; i--) + { + client_t* cl = &g_psvs.clients[i]; + if (!cl->connected || !cl->active) + continue; + + if (cl->connecttime == 0.0) + cl->connecttime = realtime; + + float dif = cl->connecttime + cl->cmdtime - realtime; + if (dif > clockwindow.value) + { + cl->ignorecmdtime = clockwindow.value + realtime; + cl->cmdtime = realtime - cl->connecttime; + } + + if (dif < -clockwindow.value) + cl->cmdtime = realtime - cl->connecttime; + } +} + +/* ../engine/sv_main.c:9122 */ +void SV_CheckForRcon(void) +{ + if (g_psv.active || g_pcls.state != ca_dedicated || giActive == DLL_CLOSE || !host_initialized) + return; + + while (NET_GetPacket(NS_SERVER)) + { + if (SV_FilterPacket()) + { + SV_SendBan(); + } + else + { + if (*(uint32_t *)net_message.data == 0xFFFFFFFF) + SV_HandleRconPacket(); + } + } +} + +/* ../engine/sv_main.c:9144 */ +qboolean SV_IsSimulating(void) +{ + if (g_psv.paused) + return FALSE; + + if (g_psvs.maxclients > 1) + return TRUE; + + if (!key_dest && (g_pcls.state == ca_active || g_pcls.state == ca_dedicated)) + return TRUE; + + return FALSE; +} + +/* ../engine/sv_main.c:9156 */ +void SV_CheckMapDifferences(void) +{ + static double lastcheck; + + if (realtime - lastcheck < 5.0) + return; + + lastcheck = realtime; + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + if (!cl->active || !cl->crcValue) + continue; + + if (cl->netchan.remote_address.type == NA_LOOPBACK) + continue; + + if (cl->crcValue != g_psv.worldmapCRC) + cl->netchan.message.flags |= SIZEBUF_OVERFLOWED; + } +} + +/* ../engine/sv_main.c:9191 */ +void SV_Frame(void) +{ + if (!g_psv.active) + return; + + gGlobalVariables.frametime = host_frametime; + g_psv.oldtime = g_psv.time; + SV_CheckCmdTimes(); + SV_ReadPackets(); + if (SV_IsSimulating()) + { + SV_Physics(); + g_psv.time += host_frametime; + } + SV_QueryMovevarsChanged(); + SV_RequestMissingResourcesFromClients(); + SV_CheckTimeouts(); + SV_SendClientMessages(); + SV_CheckMapDifferences(); + SV_GatherStatistics(); + Steam_RunFrame(); +} + +/* ../engine/sv_main.c:9252 */ +void SV_Drop_f(void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + } + else + { + SV_EndRedirect(); + SV_BroadcastPrintf("%s dropped\n", host_client->name); + SV_DropClient(host_client, FALSE, "Client sent 'drop'"); + } +} + +/* ../engine/sv_main.c:9265 */ +void SV_RegisterDelta(char *name, char *loadfile) +{ + delta_t *pdesc = NULL; + if (!DELTA_Load(name, &pdesc, loadfile)) + Sys_Error("Error parsing %s!!!\n", loadfile); + + delta_info_t *p = (delta_info_t *)Mem_ZeroMalloc(sizeof(delta_info_t)); + p->loadfile = Mem_Strdup(loadfile); + p->name = Mem_Strdup(name); + p->delta = pdesc; + p->next = g_sv_delta; + g_sv_delta = p; +} + +/* ../engine/sv_main.c:9284 */ +void SV_InitDeltas(void) +{ + Con_DPrintf("Initializing deltas\n"); + SV_RegisterDelta("clientdata_t", "delta.lst"); + SV_RegisterDelta("entity_state_t", "delta.lst"); + SV_RegisterDelta("entity_state_player_t", "delta.lst"); + SV_RegisterDelta("custom_entity_state_t", "delta.lst"); + SV_RegisterDelta("usercmd_t", "delta.lst"); + SV_RegisterDelta("weapon_data_t", "delta.lst"); + SV_RegisterDelta("event_t", "delta.lst"); + + g_pplayerdelta = SV_LookupDelta("entity_state_player_t"); + if (!g_pplayerdelta) + Sys_Error("No entity_state_player_t encoder on server!\n"); + + g_pentitydelta = SV_LookupDelta("entity_state_t"); + if (!g_pentitydelta) + Sys_Error("No entity_state_t encoder on server!\n"); + + g_pcustomentitydelta = SV_LookupDelta("custom_entity_state_t"); + if (!g_pcustomentitydelta) + Sys_Error("No custom_entity_state_t encoder on server!\n"); + + g_pclientdelta = SV_LookupDelta("clientdata_t"); + if (!g_pclientdelta) + Sys_Error("No clientdata_t encoder on server!\n"); + + g_pweapondelta = SV_LookupDelta("weapon_data_t"); + if (!g_pweapondelta) + Sys_Error("No weapon_data_t encoder on server!\n"); + + g_peventdelta = SV_LookupDelta("event_t"); + if (!g_peventdelta) + Sys_Error("No event_t encoder on server!\n"); +} + +/* ../engine/sv_main.c:9339 */ +void SV_InitEncoders(void) +{ + delta_t *pdesc; + delta_info_t *p; + for (p = g_sv_delta; p != NULL; p = p->next) + { + pdesc = p->delta; + if (Q_strlen(pdesc->conditionalencodename) > 0) + pdesc->conditionalencode = DELTA_LookupEncoder(pdesc->conditionalencodename); + } +} + +/* ../engine/sv_main.c:9362 */ +void SV_Init(void) +{ +#ifdef HOOK_ENGINE + + Cmd_AddCommand("banid", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_BanId_f", (void *)SV_BanId_f)); + Cmd_AddCommand("removeid", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_RemoveId_f", (void *)SV_RemoveId_f)); + Cmd_AddCommand("listid", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_ListId_f", (void *)SV_ListId_f)); + Cmd_AddCommand("writeid", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_WriteId_f", (void *)SV_WriteId_f)); + Cmd_AddCommand("resetrcon", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_ResetRcon_f", (void *)SV_ResetRcon_f)); + Cmd_AddCommand("logaddress", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_SetLogAddress_f", (void *)SV_SetLogAddress_f)); + Cmd_AddCommand("logaddress_add", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_AddLogAddress_f", (void *)SV_AddLogAddress_f)); + Cmd_AddCommand("logaddress_del", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_DelLogAddress_f", (void *)SV_DelLogAddress_f)); + Cmd_AddCommand("log", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_ServerLog_f", (void *)SV_ServerLog_f)); + Cmd_AddCommand("serverinfo", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_Serverinfo_f", (void *)SV_Serverinfo_f)); + Cmd_AddCommand("localinfo", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_Localinfo_f", (void *)SV_Localinfo_f)); + Cmd_AddCommand("showinfo", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_ShowServerinfo_f", (void *)SV_ShowServerinfo_f)); + Cmd_AddCommand("user", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_User_f", (void *)SV_User_f)); + Cmd_AddCommand("users", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_Users_f", (void *)SV_Users_f)); + Cmd_AddCommand("dlfile", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_BeginFileDownload_f", (void *)SV_BeginFileDownload_f)); + Cmd_AddCommand("addip", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_AddIP_f", (void *)SV_AddIP_f)); + Cmd_AddCommand("removeip", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_RemoveIP_f", (void *)SV_RemoveIP_f)); + Cmd_AddCommand("listip", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_ListIP_f", (void *)SV_ListIP_f)); + Cmd_AddCommand("writeip", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_WriteIP_f", (void *)SV_WriteIP_f)); + Cmd_AddCommand("dropclient", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_Drop_f", (void *)SV_Drop_f)); + Cmd_AddCommand("spawn", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_Spawn_f", (void *)SV_Spawn_f)); + Cmd_AddCommand("new", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_New_f", (void *)SV_New_f)); + Cmd_AddCommand("sendres", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_SendRes_f", (void *)SV_SendRes_f)); + Cmd_AddCommand("sendents", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_SendEnts_f", (void *)SV_SendEnts_f)); + Cmd_AddCommand("fullupdate", (xcommand_t)GetOriginalFuncAddrOrDefault("SV_FullUpdate_f", (void *)SV_FullUpdate_f)); + +#else // HOOK_ENGINE + + Cmd_AddCommand("banid", SV_BanId_f); + Cmd_AddCommand("removeid", SV_RemoveId_f); + Cmd_AddCommand("listid", SV_ListId_f); + Cmd_AddCommand("writeid", SV_WriteId_f); + Cmd_AddCommand("resetrcon", SV_ResetRcon_f); + Cmd_AddCommand("logaddress", SV_SetLogAddress_f); + Cmd_AddCommand("logaddress_add", SV_AddLogAddress_f); + Cmd_AddCommand("logaddress_del", SV_DelLogAddress_f); + Cmd_AddCommand("log", SV_ServerLog_f); + Cmd_AddCommand("serverinfo", SV_Serverinfo_f); + Cmd_AddCommand("localinfo", SV_Localinfo_f); + Cmd_AddCommand("showinfo", SV_ShowServerinfo_f); + Cmd_AddCommand("user", SV_User_f); + Cmd_AddCommand("users", SV_Users_f); + Cmd_AddCommand("dlfile", SV_BeginFileDownload_f); + Cmd_AddCommand("addip", SV_AddIP_f); + Cmd_AddCommand("removeip", SV_RemoveIP_f); + Cmd_AddCommand("listip", SV_ListIP_f); + Cmd_AddCommand("writeip", SV_WriteIP_f); + Cmd_AddCommand("dropclient", SV_Drop_f); + Cmd_AddCommand("spawn", SV_Spawn_f); + Cmd_AddCommand("new", SV_New_f); + Cmd_AddCommand("sendres", SV_SendRes_f); + Cmd_AddCommand("sendents", SV_SendEnts_f); + Cmd_AddCommand("fullupdate", SV_FullUpdate_f); + +#endif // HOOK_ENGINE + + Cvar_RegisterVariable(&sv_failuretime); + Cvar_RegisterVariable(&sv_voiceenable); + Cvar_RegisterVariable(&rcon_password); + Cvar_RegisterVariable(&sv_enableoldqueries); + Cvar_RegisterVariable(&mp_consistency); + Cvar_RegisterVariable(&sv_instancedbaseline); + Cvar_RegisterVariable(&sv_contact); + Cvar_RegisterVariable(&sv_unlag); + Cvar_RegisterVariable(&sv_maxunlag); + Cvar_RegisterVariable(&sv_unlagpush); + Cvar_RegisterVariable(&sv_unlagsamples); + Cvar_RegisterVariable(&sv_filterban); + Cvar_RegisterVariable(&sv_maxupdaterate); + Cvar_RegisterVariable(&sv_minupdaterate); + Cvar_RegisterVariable(&sv_logrelay); + Cvar_RegisterVariable(&sv_lan); + Cvar_DirectSet(&sv_lan, PF_IsDedicatedServer() ? "0" : "1"); + Cvar_RegisterVariable(&sv_lan_rate); + Cvar_RegisterVariable(&sv_proxies); + Cvar_RegisterVariable(&sv_outofdatetime); + Cvar_RegisterVariable(&sv_visiblemaxplayers); + Cvar_RegisterVariable(&sv_password); + Cvar_RegisterVariable(&sv_aim); + Cvar_RegisterVariable(&violence_hblood); + Cvar_RegisterVariable(&violence_ablood); + Cvar_RegisterVariable(&violence_hgibs); + Cvar_RegisterVariable(&violence_agibs); + Cvar_RegisterVariable(&sv_newunit); + Cvar_RegisterVariable(&sv_gravity); + Cvar_RegisterVariable(&sv_friction); + Cvar_RegisterVariable(&sv_edgefriction); + Cvar_RegisterVariable(&sv_stopspeed); + Cvar_RegisterVariable(&sv_maxspeed); + Cvar_RegisterVariable(&sv_footsteps); + Cvar_RegisterVariable(&sv_accelerate); + Cvar_RegisterVariable(&sv_stepsize); + Cvar_RegisterVariable(&sv_bounce); + Cvar_RegisterVariable(&sv_airaccelerate); + Cvar_RegisterVariable(&sv_wateraccelerate); + Cvar_RegisterVariable(&sv_waterfriction); + Cvar_RegisterVariable(&sv_skycolor_r); + Cvar_RegisterVariable(&sv_skycolor_g); + Cvar_RegisterVariable(&sv_skycolor_b); + Cvar_RegisterVariable(&sv_skyvec_x); + Cvar_RegisterVariable(&sv_skyvec_y); + Cvar_RegisterVariable(&sv_skyvec_z); + Cvar_RegisterVariable(&sv_timeout); + Cvar_RegisterVariable(&sv_clienttrace); + Cvar_RegisterVariable(&sv_zmax); + Cvar_RegisterVariable(&sv_wateramp); + Cvar_RegisterVariable(&sv_skyname); + Cvar_RegisterVariable(&sv_maxvelocity); + Cvar_RegisterVariable(&sv_cheats); + if (COM_CheckParm("-dev")) + Cvar_SetValue("sv_cheats", 1.0); + Cvar_RegisterVariable(&sv_spectatormaxspeed); + Cvar_RegisterVariable(&sv_allow_download); + Cvar_RegisterVariable(&sv_allow_upload); + Cvar_RegisterVariable(&sv_max_upload); + Cvar_RegisterVariable(&sv_send_logos); + Cvar_RegisterVariable(&sv_send_resources); + Cvar_RegisterVariable(&sv_logbans); + Cvar_RegisterVariable(&hpk_maxsize); + Cvar_RegisterVariable(&mapcyclefile); + Cvar_RegisterVariable(&motdfile); + Cvar_RegisterVariable(&servercfgfile); + Cvar_RegisterVariable(&mapchangecfgfile); + Cvar_RegisterVariable(&lservercfgfile); + Cvar_RegisterVariable(&logsdir); + Cvar_RegisterVariable(&bannedcfgfile); + Cvar_RegisterVariable(&sv_rcon_minfailures); + Cvar_RegisterVariable(&sv_rcon_maxfailures); + Cvar_RegisterVariable(&sv_rcon_minfailuretime); + Cvar_RegisterVariable(&sv_rcon_banpenalty); + Cvar_RegisterVariable(&sv_minrate); + Cvar_RegisterVariable(&sv_maxrate); + Cvar_RegisterVariable(&max_queries_sec); + Cvar_RegisterVariable(&max_queries_sec_global); + Cvar_RegisterVariable(&max_queries_window); + Cvar_RegisterVariable(&sv_logblocks); + Cvar_RegisterVariable(&sv_downloadurl); + Cvar_RegisterVariable(&sv_version); + Cvar_RegisterVariable(&sv_allow_dlfile); + + for (int i = 0; i < 512; i++) + { + Q_snprintf(localmodels[i], 5u, "*%i", i); + } + + g_psvs.isSecure = FALSE; + + for (int i = 0; i < g_psvs.maxclientslimit; i++) + { + client_t *cl = &g_psvs.clients[i]; + SV_ClearFrames(&cl->frames); + Q_memset(cl, 0, sizeof(client_t)); + cl->resourcesonhand.pPrev = &cl->resourcesonhand; + cl->resourcesonhand.pNext = &cl->resourcesonhand; + cl->resourcesneeded.pPrev = &cl->resourcesneeded; + cl->resourcesneeded.pNext = &cl->resourcesneeded; + } + + PM_Init(&g_svmove); + SV_AllocClientFrames(); + SV_InitDeltas(); +} + +/* ../engine/sv_main.c:9558 */ +void SV_Shutdown(void) +{ + delta_info_t *p = g_sv_delta; + while (p) + { + delta_info_t *n = p->next; + if (p->delta) + DELTA_FreeDescription(&p->delta); + + Mem_Free(p->name); + Mem_Free(p->loadfile); + Mem_Free(p); + p = n; + } + + g_sv_delta = NULL; +} + +qboolean SV_CompareUserID(USERID_t *id1, USERID_t *id2) +{ + return g_RehldsHookchains.m_SV_CompareUserID.callChain(SV_CompareUserID_internal, id1, id2); +} + +/* ../engine/sv_main.c:9585 */ +qboolean SV_CompareUserID_internal(USERID_t *id1, USERID_t *id2) +{ + if (id1 == NULL || id2 == NULL) + return FALSE; + + if (id1->idtype != id2->idtype) + return FALSE; + + if (id1->idtype != AUTH_IDTYPE_STEAM && id1->idtype != AUTH_IDTYPE_VALVE) + return FALSE; + + char szID1[64]; + char szID2[64]; + + strncpy(szID1, SV_GetIDString(id1), sizeof(szID1) - 1); + szID1[sizeof(szID1) - 1] = 0; + + strncpy(szID2, SV_GetIDString(id2), sizeof(szID2) - 1); + szID2[sizeof(szID2) - 1] = 0; + + return Q_stricmp(szID1, szID2) ? FALSE : TRUE; +} + +char *SV_GetIDString(USERID_t *id) +{ + return g_RehldsHookchains.m_SV_GetIDString.callChain(SV_GetIDString_internal, id); +} + +/* ../engine/sv_main.c:9625 */ +char *SV_GetIDString_internal(USERID_t *id) +{ + static char idstr[64]; + + idstr[0] = 0; + + if (!id) + { + return idstr; + } + + switch (id->idtype) + { + case AUTH_IDTYPE_STEAM: + if (sv_lan.value != 0.0f) + { + Q_strncpy(idstr, "STEAM_ID_LAN", ARRAYSIZE(idstr) - 1); + } + else if (!id->m_SteamID) + { + Q_strncpy(idstr, "STEAM_ID_PENDING", ARRAYSIZE(idstr) - 1); + } + else + { + TSteamGlobalUserID steam2ID = Steam_Steam3IDtoSteam2(id->m_SteamID); + Q_snprintf(idstr, ARRAYSIZE(idstr) - 1, "STEAM_%u:%u:%u", steam2ID.m_SteamInstanceID, steam2ID.m_SteamLocalUserID.Split.High32bits, steam2ID.m_SteamLocalUserID.Split.Low32bits); + } + break; + case AUTH_IDTYPE_VALVE: + if (sv_lan.value != 0.0f) + { + Q_strncpy(idstr, "VALVE_ID_LAN", ARRAYSIZE(idstr) - 1); + } + else if (!id->m_SteamID) + { + Q_strncpy(idstr, "VALVE_ID_PENDING", ARRAYSIZE(idstr) - 1); + } + else + { + TSteamGlobalUserID steam2ID = Steam_Steam3IDtoSteam2(id->m_SteamID); + Q_snprintf(idstr, ARRAYSIZE(idstr) - 1, "VALVE_%u:%u:%u", steam2ID.m_SteamInstanceID, steam2ID.m_SteamLocalUserID.Split.High32bits, steam2ID.m_SteamLocalUserID.Split.Low32bits); + } + break; + case AUTH_IDTYPE_LOCAL: + Q_strncpy(idstr, "HLTV", ARRAYSIZE(idstr) - 1); + break; + default: + Q_strncpy(idstr, "UNKNOWN", ARRAYSIZE(idstr) - 1); + break; + } + // Don't be paranoid + //idstr[ARRAYSIZE(idstr) - 1] = 0; + + return idstr; +} + +/* ../engine/sv_main.c:9697 */ +char *SV_GetClientIDString(client_t *client) +{ + static char idstr[64]; + + idstr[0] = 0; + + if (!client) + { + return idstr; + } + + if (client->netchan.remote_address.type == NA_LOOPBACK && client->network_userid.idtype == AUTH_IDTYPE_VALVE) + { + Q_snprintf(idstr, ARRAYSIZE(idstr) - 1, "VALVE_ID_LOOPBACK"); + } + else + { + USERID_t *id = &client->network_userid; + Q_snprintf(idstr, ARRAYSIZE(idstr) - 1, "%s", SV_GetIDString(id)); + idstr[ARRAYSIZE(idstr) - 1] = 0; + } + + return idstr; +} + +/* ../engine/sv_main.c:9719 */ +typedef struct GameToAppIDMapItem_s +{ + unsigned int iAppID; + const char *pGameDir; +} GameToAppIDMapItem_t; + +GameToAppIDMapItem_t g_GameToAppIDMap[11] = { + 0x0A, "cstrike", + 0x14, "tfc", + 0x1E, "dod", + 0x28, "dmc", + 0x32, "gearbox", + 0x3C, "ricochet", + 0x46, "valve", + 0x50, "czero", + 0x64, "czeror", + 0x82, "bshift", + 0x96, "cstrike_beta", +}; + +/* ../engine/sv_main.c:9748 */ +int GetGameAppID(void) +{ + char arg[260]; + char gd[260]; + + COM_ParseDirectoryFromCmd("-game", gd, "valve"); + COM_FileBase(gd, arg); + for (int i = 0; i < ARRAYSIZE(g_GameToAppIDMap); i++) + { + if (!Q_stricmp(g_GameToAppIDMap[i].pGameDir, arg)) + return g_GameToAppIDMap[i].iAppID; + } + + return 70; +} + +/* ../engine/sv_main.c:9772 */ +qboolean IsGameSubscribed(const char *gameName) +{ +#ifdef _WIN32 + for (int i = 0; i < ARRAYSIZE(g_GameToAppIDMap); i++) + { + if (!Q_stricmp(g_GameToAppIDMap[i].pGameDir, gameName)) + { + return ISteamApps_BIsSubscribedApp(g_GameToAppIDMap[i].iAppID); + } + } + + return ISteamApps_BIsSubscribedApp(70); +#else //_WIN32 + return 0; +#endif +} + +/* ../engine/sv_main.c:9796 */ +NOXREF qboolean BIsValveGame(void) +{ + for (int i = 0; i < ARRAYSIZE(g_GameToAppIDMap); i++) + { + if (!Q_stricmp(g_GameToAppIDMap[i].pGameDir, com_gamedir)) + return TRUE; + } + return FALSE; +} diff --git a/rehlds/engine/sv_move.cpp b/rehlds/engine/sv_move.cpp new file mode 100644 index 0000000..644bef8 --- /dev/null +++ b/rehlds/engine/sv_move.cpp @@ -0,0 +1,571 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#define DI_NODIR -1 + +/* +* Local initialization +*/ +#ifndef HOOK_ENGINE + +static int c_yes = 0; +static int c_no = 0; + +#else //HOOK_ENGINE + +int c_yes; +int c_no; + +#endif //HOOK_ENGINE + +/* ../engine/sv_move.c:27 */ +qboolean SV_CheckBottom(edict_t *ent) +{ + vec3_t mins; + vec3_t maxs; + vec3_t start; + vec3_t stop; // 29 + trace_t trace; // 30 + int x; // 31 + int y; // 31 + float mid; // 32 + float bottom; // 32 + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0; + + _VectorAdd(ent->v.origin, ent->v.mins, mins); + _VectorAdd(ent->v.origin, ent->v.maxs, maxs); + + start[2] = mins[2] - 1; + for (x = 0; x <= 1; x++) + { + for (y = 0; y <= 1; y++) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + + g_groupmask = ent->v.groupinfo; + + if (SV_PointContents(start) != CONTENTS_SOLID) + goto realcheck; + } + } + ++c_yes; + return 1; + +realcheck: + ++c_no; + start[2] = mins[2]; + + start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f; + start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f; + stop[2] = start[2] - 2 * sv_stepsize.value; + trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, ent, monsterClip); + + if (trace.fraction == 1.0f) + return 0; + + mid = bottom = trace.endpos[2]; + + for (x = 0; x <= 1; x++) + { + for (y = 0; y <= 1; y++) + { + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + trace = SV_Move(start, vec3_origin, vec3_origin, stop, 1, ent, monsterClip); + + if (trace.fraction != 1.0f && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0f || mid - trace.endpos[2] > sv_stepsize.value) + return 0; + } + } + + return 1; +} + +/* ../engine/sv_move.c:106 */ +qboolean SV_movetest(edict_t *ent, vec_t *move, qboolean relink) +{ + vec3_t oldorg; + vec3_t neworg; + vec3_t end; + trace_t trace; + + oldorg[0] = ent->v.origin[0]; + oldorg[1] = ent->v.origin[1]; + oldorg[2] = ent->v.origin[2]; + + neworg[0] = ent->v.origin[0] + move[0]; + neworg[1] = ent->v.origin[1] + move[1]; + neworg[2] = ent->v.origin[2] + move[2]; + end[0] = neworg[0]; + end[1] = neworg[1]; + + neworg[2] += sv_stepsize.value; + end[2] = neworg[2] - (2 * sv_stepsize.value); + trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent); + if (trace.allsolid) + return 0; + + if (trace.startsolid) + { + neworg[2] -= sv_stepsize.value; + trace = SV_MoveNoEnts(neworg, ent->v.mins, ent->v.maxs, end, 0, ent); + if (trace.allsolid || trace.startsolid) + return 0; + } + if (trace.fraction == 1.0f) + { + if (ent->v.flags & FL_PARTIALGROUND) + { + ent->v.origin[0] = *move + ent->v.origin[0]; + ent->v.origin[1] = ent->v.origin[1] + move[1]; + ent->v.origin[2] = ent->v.origin[2] + move[2]; + if (relink) + SV_LinkEdict(ent, 1); + + ent->v.flags &= ~FL_ONGROUND; + return 1; + } + return 0; + } + + ent->v.origin[0] = trace.endpos[0]; + ent->v.origin[1] = trace.endpos[1]; + ent->v.origin[2] = trace.endpos[2]; + if (SV_CheckBottom(ent) == 0) + { + if (!(ent->v.flags & FL_PARTIALGROUND)) + { + ent->v.origin[0] = oldorg[0]; + ent->v.origin[1] = oldorg[1]; + ent->v.origin[2] = oldorg[2]; + return 0; + } + } + else + { + if (ent->v.flags & FL_PARTIALGROUND) + { + ent->v.flags &= ~FL_PARTIALGROUND; + } + ent->v.groundentity = trace.ent; + } + + if (relink) + SV_LinkEdict(ent, 1); + + return 1; +} + +/* ../engine/sv_move.c:197 */ +qboolean SV_movestep(edict_t *ent, vec_t *move, qboolean relink) +{ + trace_t trace; + vec3_t end; + vec3_t oldorg; + float dz; + qboolean monsterClipBrush; + vec3_t start; + + oldorg[0] = ent->v.origin[0]; + oldorg[1] = ent->v.origin[1]; + oldorg[2] = ent->v.origin[2]; + + start[0] = ent->v.origin[0] + move[0]; + start[1] = ent->v.origin[1] + move[1]; + start[2] = ent->v.origin[2] + move[2]; + monsterClipBrush = (ent->v.flags & FL_MONSTERCLIP) != 0; + if (ent->v.flags & (FL_FLY | FL_SWIM)) + { + int i = 0; + while (i < 2) + { + start[0] = ent->v.origin[0] + move[0]; + start[1] = ent->v.origin[1] + move[1]; + start[2] = ent->v.origin[2] + move[2]; + edict_t* enemy = ent->v.enemy; + + + if (i == 0 && enemy) + { + dz = ent->v.origin[2] - enemy->v.origin[2]; + if (dz > 40.0) + start[2] = start[2] - 8.0; + if (dz < 30.0) + start[2] = start[2] + 8.0; + } + trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, start, 0, ent, monsterClipBrush); + if (trace.fraction == 1.0f) + break; + + if (!enemy) + return 0; + + if (i == 1) + return 0; + + i++; + } + + g_groupmask = ent->v.groupinfo; + if ((ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == -1) + return 0; + + ent->v.origin[0] = trace.endpos[0]; + ent->v.origin[1] = trace.endpos[1]; + ent->v.origin[2] = trace.endpos[2]; + if (relink) + SV_LinkEdict(ent, 1); + + return 1; + } + + start[2] += sv_stepsize.value; + end[0] = start[0]; + end[1] = start[1]; + end[2] = start[2] - (2 * sv_stepsize.value); + trace = SV_Move(start, ent->v.mins, ent->v.maxs, end, 0, ent, (ent->v.flags & FL_MONSTERCLIP) != 0); + if (trace.allsolid) + return 0; + + if (trace.startsolid) + { + start[2] = start[2] - sv_stepsize.value; + trace = SV_Move(start, ent->v.mins, ent->v.maxs, end, 0, ent, monsterClipBrush); + if (trace.allsolid || trace.startsolid) + return 0; + } + + if (trace.fraction != 1.0f) + { + ent->v.origin[0] = trace.endpos[0]; + ent->v.origin[1] = trace.endpos[1]; + ent->v.origin[2] = trace.endpos[2]; + if (SV_CheckBottom(ent) == 0) + { + if (!(ent->v.flags & FL_PARTIALGROUND)) + { + ent->v.origin[0] = oldorg[0]; + ent->v.origin[1] = oldorg[1]; + ent->v.origin[2] = oldorg[2]; + return 0; + } + } + else + { + if (ent->v.flags & FL_PARTIALGROUND) + ent->v.flags &= ~FL_PARTIALGROUND; + + ent->v.groundentity = trace.ent; + } + + if (relink) + SV_LinkEdict(ent, 1); + + return 1; + } + + if (!(ent->v.flags & FL_PARTIALGROUND)) + return 0; + + ent->v.origin[0] += move[0]; + ent->v.origin[1] += move[1]; + ent->v.origin[2] += move[2]; + if (relink) + SV_LinkEdict(ent, 1); + + ent->v.flags &= ~FL_ONGROUND; + return 1; +} + +/* ../engine/sv_move.c:333 */ +qboolean SV_StepDirection(edict_t *ent, float yaw, float dist) +{ + vec3_t move; + + move[0] = cos(yaw * (2 * M_PI) / 360.0) * dist; + move[1] = sin(yaw * (2 * M_PI) / 360.0) * dist; + move[2] = 0; + if (SV_movestep(ent, move, 0)) + { + SV_LinkEdict(ent, 1); + return 1; + } + else + { + SV_LinkEdict(ent, 1); + return 0; + } +} + +/* ../engine/sv_move.c:381 */ +qboolean SV_FlyDirection(edict_t *ent, vec_t *direction) +{ + if (SV_movestep(ent, direction, 0)) + { + SV_LinkEdict(ent, 1); + return 1; + } + else + { + SV_LinkEdict(ent, 1); + return 0; + } +} + +/* ../engine/sv_move.c:402 */ +void SV_FixCheckBottom(edict_t *ent) +{ + ent->v.flags |= FL_PARTIALGROUND; +} + +/* ../engine/sv_move.c:418 */ +NOXREF void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist) +{ + float deltax; + float deltay; + float d[3]; + float tdir; + float olddir; + float turnaround; + + olddir = anglemod(45.0 * (int)(actor->v.ideal_yaw / 45.0)); + turnaround = anglemod(olddir - 180.0); + + deltax = enemy->v.origin[0] - actor->v.origin[0]; + deltay = enemy->v.origin[1] - actor->v.origin[1]; + + if (deltax > 10.0) + d[1] = 0.0; + else if (deltax <- 10.0) + d[1]= 180.0; + else + d[1]= DI_NODIR; + if (deltay < -10.0) + d[2] = 270.0; + else if (deltay > 10.0) + d[2] = 90.0; + else + d[2]= DI_NODIR; + + if (d[1] != DI_NODIR && d[2] != DI_NODIR) + { + if (d[1] == 0.0) + tdir = d[2] == 90.0 ? 45.0 : 315.0; + else + tdir = d[2] == 90.0 ? 135.0 : 215.0; + + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + + if (RandomLong(0, 1) || abs(deltay) > abs(deltax)) + { + tdir = d[1]; + d[1] = d[2]; + d[2] = tdir; + } + + if (d[1] != DI_NODIR && d[1] != turnaround && SV_StepDirection(actor, d[1], dist)) + return; + + if (d[2] != DI_NODIR && d[2] != turnaround && SV_StepDirection(actor, d[2], dist)) + return; + + if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist)) + return; + + if (RandomLong(0, 1)) + { + for (tdir = 0.0; tdir <= 315.0; tdir += 45.0) + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + else + { + for (tdir = 315.0 ; tdir >= 0.0; tdir -= 45.0) + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + + if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist)) + return; + + actor->v.ideal_yaw = olddir; + + if (!SV_CheckBottom(actor)) + SV_FixCheckBottom(actor); +} + +/* ../engine/sv_move.c:507 */ +NOXREF qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist) +{ + int i; + for (i = 0; i < 3; i++) + { + if (goal->v.absmin[i] > ent->v.absmax[i] + dist) + return FALSE; + if (goal->v.absmax[i] < ent->v.absmin[i] - dist) + return FALSE; + } + return TRUE; +} + +/* ../engine/sv_move.c:528 */ +NOXREF qboolean SV_ReachedGoal(edict_t *ent, vec_t *vecGoal, float flDist) +{ + int i; + for (i = 0; i < 3; i++) + { + if (vecGoal[i] > ent->v.absmax[i] + flDist) + return FALSE; + if (vecGoal[i] < ent->v.absmin[i] - flDist) + return FALSE; + } + return TRUE; +} + +/* ../engine/sv_move.c:601 */ +void SV_NewChaseDir2(edict_t *actor, vec_t *vecGoal, float dist) +{ + float deltax; + float deltay; + float d_1, d_2; + float tdir; + float olddir; + float turnaround; + + olddir = anglemod(45 * (int)(actor->v.ideal_yaw / 45.0)); + turnaround = anglemod(olddir - 180.0); + deltax = vecGoal[0] - actor->v.origin[0]; + deltay = vecGoal[1] - actor->v.origin[1]; + + if (deltax > 10) + d_1 = 0; + else if (deltax < -10) + d_1 = 180; + else + d_1 = DI_NODIR; + + if (deltay < -10) + d_2 = 270; + else if (deltay > 10) + d_2 = 90; + else + d_2 = DI_NODIR; + + if (d_1 != DI_NODIR && d_2 != DI_NODIR) + { + if (d_1 == 0.0) + tdir = d_2 == 90 ? 45 : 315; + else + tdir = d_2 == 90 ? 135 : 215; + + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + + if (RandomLong(0, 1) || abs(deltay) > abs(deltax)) + { + tdir = d_1; + d_1 = d_2; + d_2 = tdir; + } + + if (d_1 != DI_NODIR && d_1 != turnaround + && SV_StepDirection(actor, d_1, dist)) + return; + + if (d_2 != DI_NODIR && d_2 != turnaround + && SV_StepDirection(actor, d_2, dist)) + return; + + if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist)) + return; + + if (RandomLong(0, 1)) + { + for (tdir = 0; tdir <= 315; tdir += 45) + { + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + } + else + { + for (tdir = 315; tdir >= 0; tdir -= 45) + { + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + } + + if (turnaround == DI_NODIR || !SV_StepDirection(actor, turnaround, dist)) + { + actor->v.ideal_yaw = olddir; + if (!SV_CheckBottom(actor)) + SV_FixCheckBottom(actor); + } +} + +/* ../engine/sv_move.c:690 */ +void SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iStrafe) +{ + vec3_t vecGoal; + vec3_t vecDir; + + vecGoal[0] = pflGoal[0]; + vecGoal[1] = pflGoal[1]; + vecGoal[2] = pflGoal[2]; + + if (ent->v.flags & (FL_ONGROUND | FL_SWIM | FL_FLY)) + { + if (iStrafe) + { + vecDir[0] = vecGoal[0] - ent->v.origin[0]; + vecDir[1] = vecGoal[1] - ent->v.origin[1]; + vecDir[2] = vecGoal[2] - ent->v.origin[2]; + if (!(ent->v.flags & (FL_SWIM | FL_FLY))) + vecDir[2] = 0; + + VectorNormalize(vecDir); + VectorScale(vecDir, dist, vecDir); + SV_FlyDirection(ent, vecDir); + } + else + { + if (!SV_StepDirection(ent, ent->v.ideal_yaw, dist)) + SV_NewChaseDir2(ent, vecGoal, dist); + } + } +} diff --git a/rehlds/engine/sv_move.h b/rehlds/engine/sv_move.h new file mode 100644 index 0000000..e0b8128 --- /dev/null +++ b/rehlds/engine/sv_move.h @@ -0,0 +1,60 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SV_MOVE_H +#define SV_MOVE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "server.h" + +#ifdef HOOK_ENGINE + +#define c_yes (*pc_yes) +#define c_no (*pc_no) + +#endif // HOOK_ENGINE + +extern int c_yes; +extern int c_no; + +qboolean SV_CheckBottom(edict_t *ent); +qboolean SV_movetest(edict_t *ent, vec_t *move, qboolean relink); +qboolean SV_movestep(edict_t *ent, vec_t *move, qboolean relink); +qboolean SV_StepDirection(edict_t *ent, float yaw, float dist); +qboolean SV_FlyDirection(edict_t *ent, vec_t *direction); +void SV_FixCheckBottom(edict_t *ent); +NOXREF void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist); +NOXREF qboolean SV_CloseEnough(edict_t *ent, edict_t *goal, float dist); +NOXREF qboolean SV_ReachedGoal(edict_t *ent, vec_t *vecGoal, float flDist); +void SV_NewChaseDir2(edict_t *actor, vec_t *vecGoal, float dist); +void SV_MoveToOrigin_I(edict_t *ent, const float *pflGoal, float dist, int iStrafe); + +#endif // SV_MOVE_H diff --git a/rehlds/engine/sv_phys.cpp b/rehlds/engine/sv_phys.cpp new file mode 100644 index 0000000..d7f44e7 --- /dev/null +++ b/rehlds/engine/sv_phys.cpp @@ -0,0 +1,1474 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +vec3_t* g_moved_from; +edict_t** g_moved_edict; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t sv_maxvelocity = { "sv_maxvelocity", "2000", 0, 0.0f, NULL }; +cvar_t sv_gravity = { "sv_gravity", "800", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_bounce = { "sv_bounce", "1", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_stepsize = { "sv_stepsize", "18", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_friction = { "sv_friction", "4", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_stopspeed = { "sv_stopspeed", "100", FCVAR_SERVER, 0.0f, NULL }; + +#else //HOOK_ENGINE + +cvar_t sv_maxvelocity; +cvar_t sv_gravity; +cvar_t sv_bounce; +cvar_t sv_stepsize; +cvar_t sv_friction; +cvar_t sv_stopspeed; + +#endif //HOOK_ENGINE + +/* ../engine/sv_phys.c:66 */ +NOXREF void SV_CheckAllEnts(void) +{ + int e; + edict_t *check; + + for (e = 1; e < g_psv.num_edicts; e++) + { + check = &g_psv.edicts[e]; + + if (check->free) + continue; + + int movetype = check->v.movetype; + if (check->v.movetype == MOVETYPE_NONE) + continue; + + if (movetype != MOVETYPE_PUSH + && movetype != MOVETYPE_NOCLIP + && movetype != MOVETYPE_FOLLOW) + { + if (SV_TestEntityPosition(check) != NULL) + Con_Printf("entity in invalid position\n"); + } + } +} + +/* ../engine/sv_phys.c:93 */ +void SV_CheckVelocity(edict_t *ent) +{ + for (int i = 0; i < 3; i++) + { + if (IS_NAN(ent->v.velocity[i])) + { + Con_Printf("Got a NaN velocity on %s\n", &pr_strings[ent->v.classname]); + ent->v.velocity[i] = 0; + } + if (IS_NAN(ent->v.origin[i])) + { + Con_Printf("Got a NaN origin on %s\n", &pr_strings[ent->v.classname]); + ent->v.origin[i] = 0; + } + + if (ent->v.velocity[i] > sv_maxvelocity.value) + { + Con_DPrintf("Got a velocity too high on %s\n", &pr_strings[ent->v.classname]); + ent->v.velocity[i] = sv_maxvelocity.value; + } + else if (ent->v.velocity[i] < -sv_maxvelocity.value) + { + Con_DPrintf("Got a velocity too low on %s\n", &pr_strings[ent->v.classname]); + ent->v.velocity[i] = -sv_maxvelocity.value; + } + } +} /* size: 3408238 */ + +/* +============= +SV_RunThink + +Runs thinking code if time. There is some play in the exact time the think +function will be called, because it is called before any movement is done +in a frame. Not used for pushmove objects, because they must be exact. +Returns false if the entity removed itself. +============= +*/ +/* ../engine/sv_phys.c:135 */ +qboolean SV_RunThink(edict_t *ent) +{ + float thinktime; + + if (!(ent->v.flags & FL_SPECTATOR)) + { + thinktime = ent->v.nextthink; + if (thinktime <= 0.0 || thinktime > g_psv.time + host_frametime) + { + return TRUE; + } + if (thinktime < g_psv.time) + { + thinktime = (float) g_psv.time; // don't let things stay in the past. + // it is possible to start that way + // by a trigger with a local time. + } + ent->v.nextthink = 0.0; + gGlobalVariables.time = thinktime; + gEntityInterface.pfnThink(ent); + } + + if (ent->v.flags & FL_SPECTATOR) + { + ED_Free(ent); + } + + return !ent->free; +} + +/* ../engine/sv_phys.c:170 */ +void SV_Impact(edict_t *e1, edict_t *e2, trace_t *ptrace) +{ + gGlobalVariables.time = (float) g_psv.time; + if ((e1->v.flags & FL_KILLME) || (e2->v.flags & FL_KILLME)) + return; + + if (e1->v.groupinfo && e2->v.groupinfo) + { + if (g_groupop) + { + if (g_groupop == GROUP_OP_NAND && (e1->v.groupinfo & e2->v.groupinfo)) + return; + } + else + { + if (!(e1->v.groupinfo & e2->v.groupinfo)) + return; + } + } + + if (e1->v.solid) + { + SV_SetGlobalTrace(ptrace); + gEntityInterface.pfnTouch(e1, e2); + } + if (e2->v.solid) + { + SV_SetGlobalTrace(ptrace); + gEntityInterface.pfnTouch(e2, e1); + } +} /* size: 168087284 */ + +/* ../engine/sv_phys.c:216 */ +int ClipVelocity(vec_t *in, vec_t *normal, vec_t *out, float overbounce) +{ + int blocked = 0; + if (normal[2] > 0.0) + blocked = 1; + if (normal[2] == 0.0) + blocked |= 2u; + + float backoff = (in[0] * normal[0] + in[1] * normal[1] + normal[2] * in[2]) * overbounce; + for (int i = 0; i < 3; i++) + { + float tmp = normal[i] * backoff; + float change = in[i] - tmp; + out[i] = (change > -0.1f && change < 0.1f) ? 0.0f : change; + } + + return blocked; +} /* size: 4 */ + +/* ../engine/sv_phys.c:264 */ +int SV_FlyMove(edict_t *ent, float time, trace_t *steptrace) +{ + vec_t planes[5][3]; + int numplanes = 0; + + vec3_t primal_velocity; + primal_velocity[0] = ent->v.velocity[0]; + primal_velocity[1] = ent->v.velocity[1]; + primal_velocity[2] = ent->v.velocity[2]; + + vec3_t original_velocity; + original_velocity[0] = ent->v.velocity[0]; + original_velocity[1] = ent->v.velocity[1]; + original_velocity[2] = ent->v.velocity[2]; + + vec3_t new_velocity; + + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0; + int blocked = 0; + for (int bumpcount = 0; bumpcount < 4; bumpcount++) + { + if (ent->v.velocity[0] == 0.0f && ent->v.velocity[1] == 0.0f && ent->v.velocity[2] == 0.0f) + break; + + vec3_t end; + for (int i = 0; i < 3; i++) + end[i] = time * ent->v.velocity[i] + ent->v.origin[i]; + + trace_t trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, 0, ent, monsterClip); + if (trace.allsolid) + { + ent->v.velocity[0] = vec3_origin[0]; + ent->v.velocity[1] = vec3_origin[1]; + ent->v.velocity[2] = vec3_origin[2]; + return 4; + } + + if (trace.fraction > 0.0f) + { + trace_t test = SV_Move(trace.endpos, ent->v.mins, ent->v.maxs, trace.endpos, 0, ent, monsterClip); + if (test.allsolid != 1) + { + ent->v.origin[0] = trace.endpos[0]; + ent->v.origin[1] = trace.endpos[1]; + ent->v.origin[2] = trace.endpos[2]; + primal_velocity[0] = ent->v.velocity[0]; + primal_velocity[1] = ent->v.velocity[1]; + primal_velocity[2] = ent->v.velocity[2]; + numplanes = 0; + } + } + + if (trace.fraction == 1.0f) + break; + + if (!trace.ent) + Sys_Error("SV_FlyMove: !trace.ent"); + + if (trace.plane.normal[2] > 0.7) + { + blocked |= 1u; + if (trace.ent->v.solid == SOLID_BSP + || trace.ent->v.movetype == MOVETYPE_PUSHSTEP + || trace.ent->v.solid == SOLID_SLIDEBOX + || ent->v.flags & FL_CLIENT) + { + ent->v.flags |= FL_ONGROUND; + ent->v.groundentity = trace.ent; + } + } + + if (trace.plane.normal[2] == 0.0) + { + blocked |= 2u; + if (steptrace) + memcpy(steptrace, &trace, 0x38u); + } + + SV_Impact(ent, trace.ent, &trace); + if (ent->free) + break; + + time = time - trace.fraction * time; + if (numplanes >= 5) + { + ent->v.velocity[0] = vec3_origin[0]; + ent->v.velocity[1] = vec3_origin[1]; + ent->v.velocity[2] = vec3_origin[2]; + return blocked; + } + + planes[numplanes][0] = trace.plane.normal[0]; + planes[numplanes][1] = trace.plane.normal[1]; + planes[numplanes][2] = trace.plane.normal[2]; + ++numplanes; + if (numplanes != 1 + || ent->v.movetype != MOVETYPE_WALK + || ((ent->v.flags & FL_ONGROUND) && ent->v.friction == 1.0f)) + { + int i = 0; + for (; i < numplanes; i++) + { + ClipVelocity(primal_velocity, planes[i], new_velocity, 1.0); + int j = 0; + for (; j < numplanes; j++) + { + if (j == i) + continue; + + if (new_velocity[2] * planes[j][2] + new_velocity[0] * planes[j][0] + new_velocity[1] * planes[j][1] < 0.0f) + break; + } + if (j == numplanes) + break; + } + if (i == numplanes) + { + if (numplanes != 2) + return blocked; + + vec3_t dir; + CrossProduct((const vec_t *)planes, planes[1], dir); + float vscale = dir[2] * ent->v.velocity[2] + dir[0] * ent->v.velocity[0] + dir[1] * ent->v.velocity[1]; + VectorScale(dir, vscale, ent->v.velocity); + } + else + { + ent->v.velocity[1] = new_velocity[1]; + ent->v.velocity[2] = new_velocity[2]; + ent->v.velocity[0] = new_velocity[0]; + } + + if (original_velocity[2] * ent->v.velocity[2] + + original_velocity[0] * ent->v.velocity[0] + + original_velocity[1] * ent->v.velocity[1] <= 0.0f) + { + ent->v.velocity[0] = vec3_origin[0]; + ent->v.velocity[1] = vec3_origin[1]; + ent->v.velocity[2] = vec3_origin[2]; + return blocked; + } + } + else + { + float d; + if (planes[0][2] <= 0.7) + { + d = (1.0f - ent->v.friction) * sv_bounce.value + 1.0f; + } + else + { + d = 1.0f; + } + ClipVelocity(primal_velocity, planes[0], new_velocity, d); + ent->v.velocity[0] = new_velocity[0]; + ent->v.velocity[1] = new_velocity[1]; + ent->v.velocity[2] = new_velocity[2]; + primal_velocity[0] = new_velocity[0]; + primal_velocity[1] = new_velocity[1]; + primal_velocity[2] = new_velocity[2]; + } + } + + return blocked; +} /* size: 4 */ + +/* ../engine/sv_phys.c:450 */ +void SV_AddGravity(edict_t *ent) +{ + float ent_gravity; // 452 + if (ent->v.gravity == 0.0) + ent_gravity = 1.0; + else + ent_gravity = ent->v.gravity; + ent_gravity = (float)(ent->v.velocity[2] - sv_gravity.value * ent_gravity * host_frametime); + ent->v.velocity[2] = (float)(ent_gravity + ent->v.basevelocity[2] * host_frametime); + ent->v.basevelocity[2] = 0; + SV_CheckVelocity(ent); +} /* size: 2 */ + +/* ../engine/sv_phys.c:467 */ +NOXREF void SV_AddCorrectGravity(edict_t *ent) +{ + float ent_gravity = 1.0f; + if (ent->v.gravity != 0.0f) + ent_gravity = ent->v.gravity; + + ent->v.velocity[2] -= (ent_gravity * sv_gravity.value * 0.5f * host_frametime); + ent->v.velocity[2] += ent->v.basevelocity[2] * host_frametime; + + pmove->basevelocity[2] = 0.0f; + SV_CheckVelocity(ent); +} + +/* ../engine/sv_phys.c:485 */ +NOXREF void SV_FixupGravityVelocity(edict_t *ent) +{ + float ent_gravity = 1.0f; + if (ent->v.gravity != 0.0f) + ent_gravity = ent->v.gravity; + + ent->v.velocity[2] -= (ent_gravity * sv_gravity.value * 0.5f * host_frametime); + SV_CheckVelocity(ent); +} + +/* ../engine/sv_phys.c:515 */ +trace_t SV_PushEntity(edict_t *ent, vec_t *push) +{ + trace_t trace; // 517 + vec3_t end; // 518 + int moveType; + + end[0] = ent->v.origin[0] + push[0]; + end[1] = push[1] + ent->v.origin[1]; + end[2] = push[2] + ent->v.origin[2]; + + if (ent->v.movetype == MOVETYPE_FLYMISSILE) + moveType = 2; + else + moveType = (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) ? 1 : 0; + + qboolean monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0; + trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, moveType, ent, monsterClip); + if (trace.fraction != 0.0) + { + ent->v.origin[0] = trace.endpos[0]; + ent->v.origin[1] = trace.endpos[1]; + ent->v.origin[2] = trace.endpos[2]; + } + + SV_LinkEdict(ent, 1); + if (trace.ent) + SV_Impact(ent, trace.ent, &trace); + + return trace; +} /* size: 56 */ + +/* ../engine/sv_phys.c:558 */ +void SV_PushMove(edict_t *pusher, float movetime) +{ + vec3_t mins; // 562 + vec3_t maxs; // 562 + vec3_t move; // 562 + vec3_t pushorig; // 563 + + if (pusher->v.velocity[0] == 0.0f && pusher->v.velocity[1] == 0.0f && pusher->v.velocity[2] == 0.0f) + { + pusher->v.ltime = movetime + pusher->v.ltime; + return; + } + + pushorig[0] = pusher->v.origin[0]; + pushorig[1] = pusher->v.origin[1]; + pushorig[2] = pusher->v.origin[2]; + + for (int i = 0; i < 3; i++) + { + float movedist = movetime * pusher->v.velocity[i]; + move[i] = movedist; + mins[i] = movedist + pusher->v.absmin[i]; + maxs[i] = movedist + pusher->v.absmax[i]; + pusher->v.origin[i] = movedist + pusher->v.origin[i]; + } + + pusher->v.ltime = movetime + pusher->v.ltime; + SV_LinkEdict(pusher, 0); + + if (pusher->v.solid == SOLID_NOT) + return; + + int num_moved = 0; + for (int i = 1; i < g_psv.num_edicts; i++) + { + edict_t* check = &g_psv.edicts[i]; + + if (check->free) + continue; + + if (check->v.movetype == MOVETYPE_PUSH) + continue; + + if (check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_FOLLOW || check->v.movetype == MOVETYPE_NOCLIP) + continue; + + if (((check->v.flags & FL_ONGROUND) && check->v.groundentity == pusher) + || (check->v.absmin[0] < maxs[0] + && check->v.absmin[1] < maxs[1] + && check->v.absmin[2] < maxs[2] + && check->v.absmax[0] > mins[0] + && check->v.absmax[1] > mins[1] + && check->v.absmax[2] > mins[2] + && SV_TestEntityPosition(check))) + { + if (check->v.movetype != MOVETYPE_WALK) + check->v.flags &= ~FL_ONGROUND; + + vec3_t entorigin; + entorigin[0] = check->v.origin[0]; + entorigin[1] = check->v.origin[1]; + entorigin[2] = check->v.origin[2]; + + pusher->v.solid = SOLID_NOT; + g_moved_from[num_moved][0] = check->v.origin[0]; + g_moved_from[num_moved][1] = check->v.origin[1]; + g_moved_from[num_moved][2] = check->v.origin[2]; + g_moved_edict[num_moved] = check; + ++num_moved; + + SV_PushEntity(check, move); + + pusher->v.solid = SOLID_BSP; + if (!SV_TestEntityPosition(check)) + continue; + + if (check->v.mins[0] == check->v.maxs[0]) + continue; + + if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) + { + check->v.mins[1] = 0; + check->v.mins[0] = 0; + check->v.maxs[0] = 0; + check->v.maxs[1] = 0; + check->v.maxs[2] = check->v.mins[2]; + continue; + } + + check->v.origin[0] = entorigin[0]; + check->v.origin[1] = entorigin[1]; + check->v.origin[2] = entorigin[2]; + SV_LinkEdict(check, 1); + + pusher->v.origin[0] = pushorig[0]; + pusher->v.origin[1] = pushorig[1]; + pusher->v.origin[2] = pushorig[2]; + SV_LinkEdict(pusher, 0); + + pusher->v.ltime = pusher->v.ltime - movetime; + gEntityInterface.pfnBlocked(pusher, check); + + for (int e = 0; e < num_moved; e++) + { + g_moved_edict[e]->v.origin[0] = g_moved_from[e][0]; + g_moved_edict[e]->v.origin[1] = g_moved_from[e][1]; + g_moved_edict[e]->v.origin[2] = g_moved_from[e][2]; + + SV_LinkEdict(g_moved_edict[e], 0); + } + return; + } + } + +} /* size: 168100728 */ + +/* ../engine/sv_phys.c:689 */ +int SV_PushRotate(edict_t *pusher, float movetime) +{ + vec3_t amove; // 693 + vec3_t pushorig; // 694 + vec3_t forward; // 698 + vec3_t right; // 698 + vec3_t up; // 698 + vec3_t forwardNow; // 699 + vec3_t rightNow; // 699 + vec3_t upNow; // 699 + + if (pusher->v.avelocity[0] == 0.0 && pusher->v.avelocity[1] == 0.0 && pusher->v.avelocity[2] == 0.0) + { + pusher->v.ltime = movetime + pusher->v.ltime; + return 1; + } + + for (int i = 0; i < 3; i++) + amove[i] = movetime * pusher->v.avelocity[i]; + + AngleVectors(pusher->v.angles, forward, right, up); + + pushorig[0] = pusher->v.angles[0]; + pushorig[1] = pusher->v.angles[1]; + pushorig[2] = pusher->v.angles[2]; + + pusher->v.angles[0] = amove[0] + pusher->v.angles[0]; + pusher->v.angles[1] = amove[1] + pusher->v.angles[1]; + pusher->v.angles[2] = amove[2] + pusher->v.angles[2]; + + AngleVectorsTranspose(pusher->v.angles, forwardNow, rightNow, upNow); + pusher->v.ltime = movetime + pusher->v.ltime; + + SV_LinkEdict(pusher, 0); + if (pusher->v.solid == SOLID_NOT) + return 1; + + int num_moved = 0; + for (int i = 1; i < g_psv.num_edicts; i++) + { + edict_t* check = &g_psv.edicts[i]; + if (check->free) + continue; + + if (check->v.movetype == MOVETYPE_PUSH) + continue; + + if (check->v.movetype == MOVETYPE_NONE || check->v.movetype == MOVETYPE_FOLLOW || check->v.movetype == MOVETYPE_NOCLIP) + continue; + + if (((check->v.flags & FL_ONGROUND) && check->v.groundentity == pusher) + || (check->v.absmin[0] < pusher->v.absmax[0] + && check->v.absmin[1] < pusher->v.absmax[1] + && check->v.absmin[2] < pusher->v.absmax[2] + && check->v.absmax[0] > pusher->v.absmin[0] + && check->v.absmax[1] > pusher->v.absmin[1] + && check->v.absmax[2] > pusher->v.absmin[2] + && SV_TestEntityPosition(check))) + { + if (check->v.movetype != MOVETYPE_WALK) + check->v.flags &= ~FL_ONGROUND; + + vec3_t entorig; + entorig[0] = check->v.origin[0]; + entorig[1] = check->v.origin[1]; + entorig[2] = check->v.origin[2]; + + g_moved_from[num_moved][0] = check->v.origin[0]; + g_moved_from[num_moved][1] = check->v.origin[1]; + g_moved_from[num_moved][2] = check->v.origin[2]; + g_moved_edict[num_moved] = check; + ++num_moved; + + if (num_moved >= g_psv.max_edicts) + Sys_Error("Out of edicts in simulator!\n"); + + vec3_t start, end, push, move; + float start_off2; + if (check->v.movetype == MOVETYPE_PUSHSTEP) + { + vec3_t org; + org[0] = (check->v.absmax[0] + check->v.absmin[0]) * 0.5f; + org[1] = (check->v.absmax[1] + check->v.absmin[1]) * 0.5f; + org[2] = (check->v.absmax[2] + check->v.absmin[2]) * 0.5f; + start[0] = org[0] - pusher->v.origin[0]; + start[1] = org[1] - pusher->v.origin[1]; + start_off2 = org[2]; + } + else + { + start[0] = check->v.origin[0] - pusher->v.origin[0]; + start[1] = check->v.origin[1] - pusher->v.origin[1]; + start_off2 = check->v.origin[2]; + } + + start[2] = start_off2 - pusher->v.origin[2]; + pusher->v.solid = SOLID_NOT; + + move[0] = forward[2] * start[2] + forward[1] * start[1] + forward[0] * start[0]; + move[1] = -(right[2] * start[2] + right[1] * start[1] + right[0] * start[0]); + move[2] = up[2] * start[2] + up[1] * start[1] + up[0] * start[0]; + end[0] = forwardNow[2] * move[2] + forwardNow[1] * move[1] + forwardNow[0] * move[0]; + end[1] = rightNow[2] * move[2] + rightNow[1] * move[1] + rightNow[0] * move[0]; + end[2] = upNow[2] * move[2] + upNow[1] * move[1] + upNow[0] * move[0]; + push[0] = end[0] - start[0]; + push[1] = end[1] - start[1]; + push[2] = end[2] - start[2]; + SV_PushEntity(check, push); + + pusher->v.solid = SOLID_BSP; + if (check->v.movetype != MOVETYPE_PUSHSTEP) + { + if (check->v.flags & FL_CLIENT) + { + check->v.fixangle = 2; + check->v.avelocity[1] = amove[1] + check->v.avelocity[1]; + } + else + { + //check->v.angles[0] = check->v.angles[0] + 0.0f; //TODO: The 'check->v.angles[0]' variable is assigned to itself. + check->v.angles[1] = amove[1] + check->v.angles[1]; + //check->v.angles[2] = check->v.angles[2] + 0.0f; //TODO: The 'check->v.angles[2]' variable is assigned to itself. + } + } + + if (!SV_TestEntityPosition(check) || check->v.mins[0] == check->v.maxs[0]) + continue; + + if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) + { + check->v.mins[1] = 0.0f; + check->v.mins[0] = 0.0f; + check->v.maxs[0] = 0.0f; + check->v.maxs[1] = 0.0f; + check->v.maxs[2] = check->v.mins[2]; + continue; + } + + check->v.origin[0] = entorig[0]; + check->v.origin[1] = entorig[1]; + check->v.origin[2] = entorig[2]; + SV_LinkEdict(check, 1); + + pusher->v.angles[0] = pushorig[0]; + pusher->v.angles[1] = pushorig[1]; + pusher->v.angles[2] = pushorig[2]; + SV_LinkEdict(pusher, 0); + + pusher->v.ltime = pusher->v.ltime - movetime; + gEntityInterface.pfnBlocked(pusher, check); + for (int e = 0; e < num_moved; e++) + { + edict_t* movedEnt = g_moved_edict[e]; + movedEnt->v.origin[0] = g_moved_from[e][0]; + movedEnt->v.origin[1] = g_moved_from[e][1]; + movedEnt->v.origin[2] = g_moved_from[e][2]; + if (movedEnt->v.flags & FL_CLIENT) + { + movedEnt->v.avelocity[1] = 0.0f; + } + else + { + if (movedEnt->v.movetype != MOVETYPE_PUSHSTEP) + { + //movedEnt->v.angles[0] = movedEnt->v.angles[0]; //TODO: V570 The 'movedEnt->v.angles[0]' variable is assigned to itself. + movedEnt->v.angles[1] = movedEnt->v.angles[1] - amove[1]; + //movedEnt->v.angles[2] = movedEnt->v.angles[2]; //TODO: V570 The 'movedEnt->v.angles[2]' variable is assigned to itself. + } + } + SV_LinkEdict(movedEnt, 0); + } + + return 0; + } + } + + return 1; +} /* size: 4 */ + +/* ../engine/sv_phys.c:865 */ +void SV_Physics_Pusher(edict_t *ent) +{ + float thinktime = ent->v.nextthink; + float oldltime = ent->v.ltime; + float movetime; + + if (oldltime + host_frametime <= thinktime) + { + movetime = (float) host_frametime; + } + else + { + movetime = thinktime - ent->v.ltime; + if (movetime < 0.0) + movetime = 0; + } + if (movetime != 0.0) + { + if (ent->v.avelocity[0] != 0.0 || ent->v.avelocity[1] != 0.0 || ent->v.avelocity[2] != 0.0) + { + if (ent->v.velocity[0] != 0.0 || ent->v.velocity[1] != 0.0 || ent->v.velocity[2] != 0.0) + { + if (SV_PushRotate(ent, movetime)) + { + float savetime = ent->v.ltime; + ent->v.ltime = oldltime; + SV_PushMove(ent, movetime); + if (ent->v.ltime < savetime) + ent->v.ltime = savetime; + } + } + else + { + SV_PushRotate(ent, movetime); + } + } + else + { + SV_PushMove(ent, movetime); + } + } + + for (int i = 0; i < 3; i++) { + if (ent->v.angles[i] < -3600.0f || ent->v.angles[i] > 3600.0f) + ent->v.angles[i] = fmod(ent->v.angles[i], 3600.0f); + } + + if (thinktime > oldltime && ((ent->v.flags & FL_ALWAYSTHINK) || thinktime <= ent->v.ltime)) + { + ent->v.nextthink = 0; + gGlobalVariables.time = (float) g_psv.time; + gEntityInterface.pfnThink(ent); + } +} /* size: 983224 */ + +/* ../engine/sv_phys.c:935 */ +qboolean SV_CheckWater(edict_t *ent) +{ + vec3_t point; + + ent->v.waterlevel = 0; + ent->v.watertype = -1; + g_groupmask = ent->v.groupinfo; + point[0] = (ent->v.absmax[0] + ent->v.absmin[0]) * 0.5f; + point[1] = (ent->v.absmax[1] + ent->v.absmin[1]) * 0.5f; + point[2] = ent->v.absmin[2] + 1.0f; + int cont = SV_PointContents(point); + if (cont > CONTENTS_WATER || cont <= CONTENTS_TRANSLUCENT) + return 0; + + ent->v.watertype = cont; + ent->v.waterlevel = 1; + if (ent->v.absmin[2] == ent->v.absmax[2]) + { + ent->v.waterlevel = 3; + } + else + { + + g_groupmask = ent->v.groupinfo; + point[2] = (ent->v.absmax[2] + ent->v.absmin[2]) * 0.5f; + int truecont = SV_PointContents(point); + if (truecont <= CONTENTS_WATER && truecont > CONTENTS_TRANSLUCENT) + { + ent->v.waterlevel = 2; + g_groupmask = ent->v.groupinfo; + point[0] = point[0] + ent->v.view_ofs[0]; + point[1] = point[1] + ent->v.view_ofs[1]; + point[2] = point[2] + ent->v.view_ofs[2]; + truecont = SV_PointContents(point); + if (truecont <= CONTENTS_WATER && truecont > CONTENTS_TRANSLUCENT) + ent->v.waterlevel = 3; + } + } + + if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) + { + static vec_t current_table[6][3] = + { + { 1.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f }, + { -1.0f, 0.0f, 0.0f }, + { 0.0f, -1.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, -1.0f } + }; + + VectorMA(ent->v.basevelocity, ent->v.waterlevel * 50.0f, current_table[-(cont - CONTENTS_CURRENT_0)], ent->v.basevelocity); + } + + return (ent->v.waterlevel > 1) ? 1 : 0; + +} + +/* ../engine/sv_phys.c:1002 */ +float SV_RecursiveWaterLevel(vec_t *center, float out, float in, int count) +{ + float offset = (float)((out - in) * 0.5 + in); + if (count + 1 < 6) + { + vec3_t test; + test[0] = center[0]; + test[1] = center[1]; + test[2] = offset + center[2]; + if (SV_PointContents(test) == CONTENTS_WATER) + return SV_RecursiveWaterLevel(center, out, offset, count + 1); + else + return SV_RecursiveWaterLevel(center, offset, in, count + 1); + } + else + { + return offset; + } +} /* size: 0 */ + +/* ../engine/sv_phys.c:1024 */ +float SV_Submerged(edict_t *ent) +{ +// float start; // 1026 + float end; // 1026 +// float bottom; // 1026 + vec3_t center; // 1027 +// { +// vec3_t point; // 1044 +// } +// SV_RecursiveWaterLevel(vec_t *center, +// float out, +// float in, +// int count); // 1059 + + center[0] = (ent->v.absmax[0] + ent->v.absmin[0]) * 0.5f; + center[1] = (ent->v.absmax[1] + ent->v.absmin[1]) * 0.5f; + center[2] = (ent->v.absmin[2] + ent->v.absmax[2]) * 0.5f; + float start = ent->v.absmin[2] - center[2]; + if (ent->v.waterlevel == 1) + { + return SV_RecursiveWaterLevel(center, 0.0, start, 0) - start; + } + + if (ent->v.waterlevel == 2) + { + end = ent->v.absmax[2] - center[2]; + return SV_RecursiveWaterLevel(center, end, 0.0, 0) - start; + } + + if (ent->v.waterlevel == 3) + { + vec3_t point; + point[0] = center[0]; + point[1] = center[1]; + point[2] = ent->v.absmax[2]; + g_groupmask = ent->v.groupinfo; + if (SV_PointContents(point) == -3) + return ent->v.maxs[2] - ent->v.mins[2]; + + end = ent->v.absmax[2] - center[2]; + return SV_RecursiveWaterLevel(center, end, 0.0, 0) - start; + } + + return 0; +} /* size: 4 */ + +/* +============= +SV_Physics_None + +Non moving objects can only think. +============= +*/ +/* ../engine/sv_phys.c:1389 */ +void SV_Physics_None(edict_t *ent) +{ + SV_RunThink(ent); +} + +/* ../engine/sv_phys.c:1402 */ +void SV_Physics_Follow(edict_t *ent) +{ + if (SV_RunThink(ent)) + { + if (ent->v.aiment) + { + ent->v.angles[0] = ent->v.aiment->v.angles[0]; + ent->v.angles[1] = ent->v.aiment->v.angles[1]; + ent->v.angles[2] = ent->v.aiment->v.angles[2]; + ent->v.origin[0] = ent->v.aiment->v.origin[0] + ent->v.v_angle[0]; + ent->v.origin[1] = ent->v.aiment->v.origin[1] + ent->v.v_angle[1]; + ent->v.origin[2] = ent->v.aiment->v.origin[2] + ent->v.v_angle[2]; + SV_LinkEdict(ent, 1); + } + else + { + Con_DPrintf("%s movetype FOLLOW with NULL aiment\n", &pr_strings[ent->v.classname]); + ent->v.movetype = 0; + } + } +} /* size: 0 */ + +/* ../engine/sv_phys.c:1430 */ +void SV_Physics_Noclip(edict_t *ent) +{ + if (SV_RunThink(ent)) + { + VectorMA(ent->v.angles, (float)host_frametime, ent->v.avelocity, ent->v.angles); + VectorMA(ent->v.origin, (float)host_frametime, ent->v.velocity, ent->v.origin); + SV_LinkEdict(ent, 0); + } +} /* size: 0 */ + +/* ../engine/sv_phys.c:1456 */ +void SV_CheckWaterTransition(edict_t *ent) +{ +// int cont; // 1458 + vec3_t point; // 1460 + + g_groupmask = ent->v.groupinfo; + point[0] = (ent->v.absmax[0] + ent->v.absmin[0]) * 0.5f; + point[1] = (ent->v.absmax[1] + ent->v.absmin[1]) * 0.5f; + point[2] = ent->v.absmin[2] + 1.0f; + int cont = SV_PointContents(point); + + if (ent->v.watertype == 0) + { + ent->v.watertype = cont; + ent->v.waterlevel = 1; + return; + } + + if (cont > CONTENTS_WATER || cont <= CONTENTS_TRANSLUCENT) + { + if (ent->v.watertype != -1) + SV_StartSound(0, ent, 0, "player/pl_wade2.wav", 255, 1.0, 0, 100); + ent->v.watertype = -1; + ent->v.waterlevel = 0; + return; + } + + if (ent->v.watertype == -1) + { + SV_StartSound(0, ent, 0, "player/pl_wade1.wav", 255, 1.0, 0, 100); + ent->v.velocity[2] = ent->v.velocity[2] * 0.5f; + } + + ent->v.watertype = cont; + ent->v.waterlevel = 1; + if (ent->v.absmin[2] == ent->v.absmax[2]) + { + ent->v.waterlevel = 3; + return; + } + + g_groupmask = ent->v.groupinfo; + point[2] = (ent->v.absmin[2] + ent->v.absmax[2]) * 0.5f; + cont = SV_PointContents(point); + if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT) + { + ent->v.waterlevel = 2; + g_groupmask = ent->v.groupinfo; + point[0] = point[0] + ent->v.view_ofs[0]; + point[1] = point[1] + ent->v.view_ofs[1]; + point[2] = point[2] + ent->v.view_ofs[2]; + cont = SV_PointContents(point); + if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT) + { + ent->v.waterlevel = 3; + } + } + +} + +/* ../engine/sv_phys.c:1531 */ +void SV_Physics_Toss(edict_t *ent) +{ + SV_CheckWater(ent); + if (!SV_RunThink(ent)) + return; + + if (ent->v.velocity[2] > 0.0 || ent->v.groundentity == NULL || ent->v.groundentity->v.flags & (FL_MONSTER | FL_CLIENT)) + ent->v.flags &= ~FL_ONGROUND; + + if ((ent->v.flags & FL_ONGROUND) && VectorCompare(ent->v.velocity, vec_origin)) { + ent->v.avelocity[0] = vec3_origin[0]; + ent->v.avelocity[1] = vec3_origin[1]; + ent->v.avelocity[2] = vec3_origin[2]; + if (VectorCompare(ent->v.basevelocity, vec_origin)) + return; + } + + SV_CheckVelocity(ent); + if (ent->v.movetype != MOVETYPE_FLY && ent->v.movetype != MOVETYPE_BOUNCEMISSILE && ent->v.movetype != MOVETYPE_FLYMISSILE) + SV_AddGravity(ent); + + VectorMA(ent->v.angles, (float)host_frametime, ent->v.avelocity, ent->v.angles); + ent->v.velocity[0] = ent->v.basevelocity[0] + ent->v.velocity[0]; + ent->v.velocity[1] = ent->v.basevelocity[1] + ent->v.velocity[1]; + ent->v.velocity[2] = ent->v.basevelocity[2] + ent->v.velocity[2]; + SV_CheckVelocity(ent); + + vec3_t move; + VectorScale(ent->v.velocity, (float)host_frametime, move); + ent->v.velocity[0] = ent->v.velocity[0] - ent->v.basevelocity[0]; + ent->v.velocity[1] = ent->v.velocity[1] - ent->v.basevelocity[1]; + ent->v.velocity[2] = ent->v.velocity[2] - ent->v.basevelocity[2]; + + trace_t trace = SV_PushEntity(ent, move); + SV_CheckVelocity(ent); + + if (trace.allsolid) + { + ent->v.velocity[0] = vec3_origin[0]; + ent->v.velocity[1] = vec3_origin[1]; + ent->v.velocity[2] = vec3_origin[2]; + ent->v.avelocity[0] = vec3_origin[0]; + ent->v.avelocity[1] = vec3_origin[1]; + ent->v.avelocity[2] = vec3_origin[2]; + return; + } + + if (trace.fraction == 1.0f) + { + SV_CheckWaterTransition(ent); + return; + } + + if (ent->free) + return; + + float backoff; + if (ent->v.movetype == MOVETYPE_BOUNCE) + { + backoff = 2.0f - ent->v.friction; + } + else + { + backoff = 2.0f; + if (ent->v.movetype != MOVETYPE_BOUNCEMISSILE) + backoff = 1.0f; + } + ClipVelocity(ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); + + if (trace.plane.normal[2] <= 0.7f) + return; + + move[0] = ent->v.basevelocity[0] + ent->v.velocity[0]; + move[1] = ent->v.basevelocity[1] + ent->v.velocity[1]; + move[2] = ent->v.basevelocity[2] + ent->v.velocity[2]; + if (sv_gravity.value * host_frametime > move[2]) + { + ent->v.flags |= FL_ONGROUND; + ent->v.velocity[2]= 0; + ent->v.groundentity = trace.ent; + } + + if (move[2] * move[2] + move[1] * move[1] + move[0] * move[0] >= 900.0f) + { + if (ent->v.movetype == MOVETYPE_BOUNCE || ent->v.movetype == MOVETYPE_BOUNCEMISSILE) + { + VectorScale(ent->v.velocity, (float)((1.0 - trace.fraction) * host_frametime * 0.9f), move); + VectorMA(move, (float)((1.0 - trace.fraction) * host_frametime * 0.9f), ent->v.basevelocity, move); + SV_PushEntity(ent, move); + SV_CheckWaterTransition(ent); + return; + } + } + + ent->v.flags |= FL_ONGROUND; + ent->v.groundentity = trace.ent; + ent->v.velocity[0] = vec3_origin[0]; + ent->v.velocity[1] = vec3_origin[1]; + ent->v.velocity[2] = vec3_origin[2]; + ent->v.avelocity[0] = vec3_origin[0]; + ent->v.avelocity[1] = vec3_origin[1]; + ent->v.avelocity[2] = vec3_origin[2]; +} /* size: 3408000 */ + +/* ../engine/sv_phys.c:1668 */ + + +void PF_WaterMove(edict_t *pSelf) +{ + int flags; + int waterlevel; + int watertype; + float drownlevel; + + if (pSelf->v.movetype == MOVETYPE_NOCLIP) + { + pSelf->v.air_finished = (float)(g_psv.time + 12.0f); + return; + } + + if (pSelf->v.health < 0.0) + return; + + drownlevel = (pSelf->v.deadflag) ? 1.0f : 3.0f; + flags = pSelf->v.flags; + waterlevel = pSelf->v.waterlevel; + watertype = pSelf->v.watertype; + if (!(flags & (FL_IMMUNE_WATER | FL_GODMODE))) + { + if (flags & FL_SWIM && (waterlevel < drownlevel) + || (waterlevel >= drownlevel)) + { + if (pSelf->v.air_finished < g_psv.time && pSelf->v.pain_finished < g_psv.time) + { + pSelf->v.dmg += 2.0; + if (pSelf->v.dmg > 15.0) + pSelf->v.dmg = 10.0f; + pSelf->v.pain_finished = (float)(g_psv.time + 1.0f); + } + } + else + { + pSelf->v.dmg = 2.0f; + pSelf->v.air_finished = (float)(g_psv.time + 12.0); + } + } + if (!waterlevel) + { + if (flags & FL_INWATER) + { + switch (RandomLong(0, 3)) + { + case 0: + SV_StartSound(0, pSelf, 4, "player/pl_wade1.wav", 255, 0.8f, 0, 100); + break; + case 1: + SV_StartSound(0, pSelf, 4, "player/pl_wade2.wav", 255, 0.8f, 0, 100); + break; + case 2: + SV_StartSound(0, pSelf, 4, "player/pl_wade3.wav", 255, 0.8f, 0, 100); + break; + case 3: + SV_StartSound(0, pSelf, 4, "player/pl_wade4.wav", 255, 0.8f, 0, 100); + break; + default: + break; + } + pSelf->v.flags &= ~FL_INWATER; + } + pSelf->v.air_finished = (float)(g_psv.time + 12.0); + return; + } + + if (watertype == -5) + { + if (!(flags & (FL_IMMUNE_LAVA | FL_GODMODE)) && pSelf->v.dmgtime < g_psv.time) + { + if (g_psv.time <= pSelf->v.radsuit_finished) + pSelf->v.dmgtime = (float)(g_psv.time + 1.0); + else + pSelf->v.dmgtime = (float)(g_psv.time + 0.2); + } + } + else + { + if (watertype == -4 + && !(flags & (FL_IMMUNE_SLIME | FL_GODMODE)) + && pSelf->v.dmgtime < g_psv.time + && pSelf->v.radsuit_finished < g_psv.time) + { + pSelf->v.dmgtime = (float)(g_psv.time + 1.0); + } + } + + if (!(flags & FL_INWATER)) + { + if (watertype == -3) + { + switch (RandomLong(0, 3)) + { + case 0: + SV_StartSound(0, pSelf, 4, "player/pl_wade1.wav", 255, 0.8f, 0, 100); + break; + case 1: + SV_StartSound(0, pSelf, 4, "player/pl_wade2.wav", 255, 0.8f, 0, 100); + break; + case 2: + SV_StartSound(0, pSelf, 4, "player/pl_wade3.wav", 255, 0.8f, 0, 100); + break; + case 3: + SV_StartSound(0, pSelf, 4, "player/pl_wade4.wav", 255, 0.8f, 0, 100); + break; + default: + break; + } + } + pSelf->v.dmgtime = 0; + pSelf->v.flags = flags | FL_INWATER; + } + + if (!(flags & FL_WATERJUMP)) + { + VectorMA(pSelf->v.velocity, (float)(pSelf->v.waterlevel * host_frametime * -0.8), pSelf->v.velocity, pSelf->v.velocity); + } +} + + +/* ../engine/sv_phys.c:1812 */ +void SV_Physics_Step(edict_t *ent) +{ + vec3_t maxs; + vec3_t mins; + vec3_t point; + + PF_WaterMove(ent); + SV_CheckVelocity(ent); + qboolean wasonground = (ent->v.flags & FL_ONGROUND) ? 1 : 0; + qboolean inwater = SV_CheckWater(ent); + if ((ent->v.flags & FL_FLOAT) && ent->v.waterlevel > 0)// FL_FLOAT + { + float waterLevel = (float)(SV_Submerged(ent) * ent->v.skin * host_frametime); + SV_AddGravity(ent); + ent->v.velocity[2] += waterLevel; + } + if (!wasonground) + { + if (!(ent->v.flags & FL_FLY)) + { + if (!(ent->v.flags & FL_SWIM) || ent->v.waterlevel <= 0) + { + if (!inwater) + SV_AddGravity(ent); + } + } + } + if (VectorCompare(ent->v.velocity, vec_origin) && VectorCompare(ent->v.basevelocity, vec_origin)) + { + if (gGlobalVariables.force_retouch != 0.0) + { + trace_t trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent, (ent->v.flags & FL_MONSTERCLIP) ? 1 : 0); + if (trace.fraction < 1.0 || trace.startsolid) + { + if (trace.ent) + SV_Impact(ent, trace.ent, &trace); + } + } + } + else + { + ent->v.flags &= ~FL_ONGROUND; + if (wasonground && (ent->v.health > 0.0 || SV_CheckBottom(ent))) + { + float speed = (float)sqrt((long double)(ent->v.velocity[0] * ent->v.velocity[0] + ent->v.velocity[1] * ent->v.velocity[1])); + if (speed != 0.0) + { + float friction = sv_friction.value * ent->v.friction; + ent->v.friction = 1.0f; + float control = (speed >= sv_stopspeed.value) ? speed : sv_stopspeed.value; + + float newspeed = (float)(speed - control * friction * host_frametime); + if (newspeed < 0.0) + newspeed = 0.0; + newspeed = newspeed / speed; + + ent->v.velocity[0] *= newspeed; + ent->v.velocity[1] *= newspeed; + } + } + ent->v.velocity[0] += ent->v.basevelocity[0]; + ent->v.velocity[1] += ent->v.basevelocity[1]; + ent->v.velocity[2] += ent->v.basevelocity[2]; + SV_CheckVelocity(ent); + SV_FlyMove(ent, (float)host_frametime, 0); + SV_CheckVelocity(ent); + ent->v.velocity[0] -= ent->v.basevelocity[0]; + ent->v.velocity[1] -= ent->v.basevelocity[1]; + ent->v.velocity[2] -= ent->v.basevelocity[2]; + SV_CheckVelocity(ent); + mins[0] = ent->v.mins[0] + ent->v.origin[0]; + mins[1] = ent->v.mins[1] + ent->v.origin[1]; + mins[2] = ent->v.mins[2] + ent->v.origin[2]; + maxs[0] = ent->v.maxs[0] + ent->v.origin[0]; + maxs[1] = ent->v.maxs[1] + ent->v.origin[1]; + point[2] = mins[2] - 1.0f; + + for (int x = 0; x <= 1; x++) + { + for (int y = 0; y <= 1; y++) + { + point[0] = x ? (maxs[0]) : (mins[0]); + point[1] = y ? (maxs[1]) : (mins[1]); + g_groupmask = ent->v.groupinfo; + if (SV_PointContents(point) == -2) + { + ent->v.flags |= FL_ONGROUND; + break; + } + } + }; + SV_LinkEdict(ent, 1); + } + SV_RunThink(ent); + SV_CheckWaterTransition(ent); +} /* size: 168162184 */ + +/* ../engine/sv_phys.c:1976 */ +void SV_Physics(void) +{ + gGlobalVariables.time = (float)g_psv.time; + gEntityInterface.pfnStartFrame(); + for (int i = 0; i < g_psv.num_edicts; i++) + { + edict_t* ent = &g_psv.edicts[i]; + if (ent->free) + continue; + + if (gGlobalVariables.force_retouch != 0.0) + SV_LinkEdict(ent, 1); + + if (i > 0 && i <= g_psvs.maxclients) + continue; + + if (ent->v.flags & FL_ONGROUND) + { + edict_t* groundentity = ent->v.groundentity; + if (groundentity) + { + if (groundentity->v.flags & FL_CONVEYOR) + { + if (ent->v.flags & FL_BASEVELOCITY) + VectorMA(ent->v.basevelocity, groundentity->v.speed, groundentity->v.movedir, ent->v.basevelocity); + else + VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); + ent->v.flags |= FL_BASEVELOCITY; + } + } + } + if (!(ent->v.flags & FL_BASEVELOCITY)) + { + VectorMA(ent->v.velocity, (float)(host_frametime * 0.5 + 1.0), ent->v.basevelocity, ent->v.velocity); + ent->v.basevelocity[0] = vec3_origin[0]; + ent->v.basevelocity[1] = vec3_origin[1]; + ent->v.basevelocity[2] = vec3_origin[2]; + } + ent->v.flags &= ~FL_BASEVELOCITY; + + switch (ent->v.movetype) + { + case MOVETYPE_NONE: + SV_Physics_None(ent); + break; + + case MOVETYPE_PUSH: + SV_Physics_Pusher(ent); + break; + + case MOVETYPE_FOLLOW: + SV_Physics_Follow(ent); + break; + + case MOVETYPE_NOCLIP: + SV_Physics_Noclip(ent); + break; + + case MOVETYPE_STEP: + case MOVETYPE_PUSHSTEP: + SV_Physics_Step(ent); + break; + + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_BOUNCEMISSILE: + case MOVETYPE_FLY: + case MOVETYPE_FLYMISSILE: + SV_Physics_Toss(ent); + break; + + default: + Sys_Error("SV_Physics: %s bad movetype %d", &pr_strings[ent->v.classname], ent->v.movetype); + } + + if (ent->v.flags & FL_KILLME) + ED_Free(ent); + } + + if (gGlobalVariables.force_retouch != 0.0f) + gGlobalVariables.force_retouch = gGlobalVariables.force_retouch - 1.0f; +} /* size: 0 */ + +/* ../engine/sv_phys.c:2068 */ +trace_t SV_Trace_Toss(edict_t *ent, edict_t *ignore) +{ + edict_t tempent; + trace_t trace; + vec3_t move; + vec3_t end; + double save_frametime; + + save_frametime = host_frametime; + host_frametime = 5.0; + Q_memcpy(&tempent, ent, sizeof(tempent)); + do + { + do + { + SV_CheckVelocity(&tempent); + SV_AddGravity(&tempent); + VectorMA(tempent.v.angles, (float)host_frametime, tempent.v.avelocity, tempent.v.angles); + VectorScale(tempent.v.velocity, (float)host_frametime, move); + end[0] = tempent.v.origin[0] + move[0]; + end[1] = tempent.v.origin[1] + move[1]; + end[2] = tempent.v.origin[2] + move[2]; + trace = SV_Move(tempent.v.origin, tempent.v.mins, tempent.v.maxs, end, 0, &tempent, 0); + tempent.v.origin[1] = trace.endpos[1]; + tempent.v.origin[0] = trace.endpos[0]; + tempent.v.origin[2] = trace.endpos[2]; + } while (!trace.ent); + } while (trace.ent == ignore); + host_frametime = save_frametime; + return trace; +} /* size: 56 */ diff --git a/rehlds/engine/sv_phys.h b/rehlds/engine/sv_phys.h new file mode 100644 index 0000000..ee7f203 --- /dev/null +++ b/rehlds/engine/sv_phys.h @@ -0,0 +1,88 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SV_PHYS_H +#define SV_PHYS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "model.h" +#include "cvar.h" + + +#ifdef HOOK_ENGINE +#define sv_maxvelocity (*psv_maxvelocity) +#define sv_gravity (*psv_gravity) +#define sv_bounce (*psv_bounce) +#define sv_stepsize (*psv_stepsize) +#define sv_friction (*psv_friction) +#define sv_stopspeed (*psv_stopspeed) +#define g_moved_from (*pg_moved_from) +#define g_moved_edict (*pg_moved_edict) +#endif + +extern cvar_t sv_maxvelocity; +extern cvar_t sv_gravity; +extern cvar_t sv_bounce; +extern cvar_t sv_stepsize; +extern cvar_t sv_friction; +extern cvar_t sv_stopspeed; + +extern vec3_t *g_moved_from; +extern edict_t **g_moved_edict; + + +NOXREF void SV_CheckAllEnts(void); +void SV_CheckVelocity(edict_t *ent); +qboolean SV_RunThink(edict_t *ent); +void SV_Impact(edict_t *e1, edict_t *e2, trace_t *ptrace); +int ClipVelocity(vec_t *in, vec_t *normal, vec_t *out, float overbounce); +int SV_FlyMove(edict_t *ent, float time, trace_t *steptrace); +void SV_AddGravity(edict_t *ent); +NOXREF void SV_AddCorrectGravity(edict_t *ent); +NOXREF void SV_FixupGravityVelocity(edict_t *ent); +trace_t SV_PushEntity(edict_t *ent, vec_t *push); +void SV_PushMove(edict_t *pusher, float movetime); +int SV_PushRotate(edict_t *pusher, float movetime); +void SV_Physics_Pusher(edict_t *ent); +qboolean SV_CheckWater(edict_t *ent); +float SV_RecursiveWaterLevel(vec_t *center, float out, float in, int count); +float SV_Submerged(edict_t *ent); +void SV_Physics_None(edict_t *ent); +void SV_Physics_Follow(edict_t *ent); +void SV_Physics_Noclip(edict_t *ent); +void SV_CheckWaterTransition(edict_t *ent); +void SV_Physics_Toss(edict_t *ent); +void PF_WaterMove(edict_t *pSelf); +void SV_Physics_Step(edict_t *ent); +void SV_Physics(void); +trace_t SV_Trace_Toss(edict_t *ent, edict_t *ignore); + +#endif // SV_PHYS_H diff --git a/rehlds/engine/sv_pmove.cpp b/rehlds/engine/sv_pmove.cpp new file mode 100644 index 0000000..c58bea3 --- /dev/null +++ b/rehlds/engine/sv_pmove.cpp @@ -0,0 +1,59 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +/* ../engine/sv_pmove.c:12 */ +void PM_SV_PlaybackEventFull(int flags, int clientindex, short unsigned int eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2) +{ + EV_SV_Playback(flags | FEV_NOTHOST, clientindex, eventindex, delay, origin, angles, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2); +} + +/* ../engine/sv_pmove.c:25 */ +void PM_SV_PlaySound(int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch) +{ + SV_StartSound(1, host_client->edict, channel, sample, (int)(volume * 255.0), attenuation, fFlags, pitch); +} + +/* ../engine/sv_pmove.c:38 */ +const char *PM_SV_TraceTexture(int ground, vec_t *vstart, vec_t *vend) +{ + if (ground < 0 || ground >= pmove->numphysent) + return NULL; + + physent_t *pe = &pmove->physents[ground]; + if (!pe->model || pe->info < 0 || pe->info >= g_psv.max_edicts) + return NULL; + + edict_t *pent = &g_psv.edicts[pe->info]; + if (!pent) + return NULL; + + return TraceTexture(pent, vstart, vend); +} diff --git a/rehlds/engine/sv_pmove.h b/rehlds/engine/sv_pmove.h new file mode 100644 index 0000000..18cc17d --- /dev/null +++ b/rehlds/engine/sv_pmove.h @@ -0,0 +1,42 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SV_PMOVE_H +#define SV_PMOVE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + + +void PM_SV_PlaybackEventFull(int flags, int clientindex, short unsigned int eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2); +void PM_SV_PlaySound(int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch); +const char *PM_SV_TraceTexture(int ground, vec_t *vstart, vec_t *vend); + +#endif // SV_PMOVE_H diff --git a/rehlds/engine/sv_remoteaccess.cpp b/rehlds/engine/sv_remoteaccess.cpp new file mode 100644 index 0000000..2ed98c4 --- /dev/null +++ b/rehlds/engine/sv_remoteaccess.cpp @@ -0,0 +1,306 @@ +#include "precompiled.h" + +class CServerRemoteAccess g_ServerRemoteAccess; + +void CServerRemoteAccess::WriteDataRequest(const void *buffer, int bufferSize) +{ + WriteDataRequest_noVirt(buffer, bufferSize); +} + +int CServerRemoteAccess::ReadDataResponse(void *data, int len) +{ + return ReadDataResponse_noVirt(data, len); +} + +void CServerRemoteAccess::WriteDataRequest_noVirt(const void *buffer, int bufferSize) +{ + int requestID; + int requestType; + char value[256]; + char command[256]; + char variable[256]; + + CUtlBuffer cmd(buffer, bufferSize, false); + + this->m_iBytesReceived += bufferSize; + requestID = cmd.GetInt(); + requestType = cmd.GetInt(); + + switch (requestType) + { + case 0: + cmd.GetString(variable); + RequestValue(requestID, variable); + break; + + case 1: + cmd.GetString(variable); + cmd.GetString(value); + SetValue(variable, value); + break; + + case 2: + cmd.GetString(command); + ExecCommand(command); + } +} + +int CServerRemoteAccess::ReadDataResponse_noVirt(void *data, int len) +{ + int i = m_ResponsePackets.Head(); + if (!m_ResponsePackets.IsValidIndex(i)) + return 0; + + CUtlBuffer &response = m_ResponsePackets.Element(i).packet; + int bytesToCopy = response.TellPut(); + if (bytesToCopy > len) + bytesToCopy = 0; + + if (bytesToCopy) + memcpy(data, response.Base(), bytesToCopy); + + m_iBytesSent += bytesToCopy; + + m_ResponsePackets.Remove(i); + + return bytesToCopy; +} + +void CServerRemoteAccess::SendMessageToAdminUI(const char *message) +{ + DataResponse_t &resp = m_ResponsePackets.Element(m_ResponsePackets.AddToTail()); + resp.packet.PutInt(0); + resp.packet.PutInt(1); + resp.packet.PutString(message); +} + +const char* CServerRemoteAccess::LookupStringValue(const char *variable) +{ + static char s_ReturnBuf[32]; + + cvar_t *var = Cvar_FindVar(variable); + if (var) + return var->string; + + if (!Q_stricmp(variable, "map")) + return g_psv.name; + + if (!Q_stricmp(variable, "playercount")) + { + int count = 0; + for (int i = 0; i < g_psvs.maxclients; i++) + { + if (g_psvs.clients[i].active || g_psvs.clients[i].spawned || g_psvs.clients[i].connected) + count++; + } + + _snprintf(s_ReturnBuf, sizeof(s_ReturnBuf) - 1, "%d", count); + return s_ReturnBuf; + } + + if (!Q_stricmp(variable, "maxplayers")) + { + _snprintf(s_ReturnBuf, sizeof(s_ReturnBuf) - 1, "%d", g_psvs.maxclients); + return s_ReturnBuf; + } + + if (!Q_stricmp(variable, "gamedescription")) + return gEntityInterface.pfnGetGameDescription(); + + return NULL; +} + +void CServerRemoteAccess::GetUserBanList(CUtlBuffer &value) +{ + for (int i = 0; i < numuserfilters; i++) + { + value.Printf("%i %s : %.3f min\n", i + 1, SV_GetIDString(&userfilters[i].userid), userfilters[i].banTime); + } + + for (int i = 0; i < numuserfilters; i++) + { + ipfilter_t* f = &ipfilters[i]; + value.Printf("%i %i.%i.%i.%i : %.3f min\n", numuserfilters + i + 1, f->compare.octets[0], f->compare.octets[1], f->compare.octets[2], f->compare.octets[3], f->banTime); + } + + value.PutChar(0); +} + +void CServerRemoteAccess::GetPlayerList(CUtlBuffer &value) +{ + for (int i = 0; i < g_psvs.maxclients; ++i) + { + client_t* cli = &g_psvs.clients[i]; + if (!cli->active || Q_strlen(cli->name) < 1) + continue; + + value.Printf("\"%s\" %s %s %d %d %d %d\n", cli->name, SV_GetIDString(&cli->network_userid), NET_AdrToString(cli->netchan.remote_address), + int(cli->latency * 1000.0), (int)cli->packet_loss, (int)cli->edict->v.frags, int(realtime - cli->netchan.connect_time)); + + } + + value.PutChar(0); +} + +void CServerRemoteAccess::GetMapList(CUtlBuffer &value) +{ + const char *findfn; + char *extension; + char curDir[MAX_PATH]; + char mapName[MAX_PATH]; + char mapwild[64]; + + strcpy(mapwild, "maps/*.bsp"); + for (findfn = Sys_FindFirst(mapwild, 0); findfn; findfn = Sys_FindNext(0)) + { + _snprintf(curDir, MAX_PATH, "maps/%s", findfn); + FS_GetLocalPath(curDir, curDir, MAX_PATH); + if (Q_strstr(curDir, com_gamedir)) + { + Q_strcpy(mapName, findfn); + extension = Q_strstr(mapName, ".bsp"); + if (extension) + *extension = 0; + + value.PutString(mapName); + value.PutString("\n"); + } + } + Sys_FindClose(); + + value.PutChar(0); +} + +bool CServerRemoteAccess::LookupValue(const char *variable, CUtlBuffer &value) +{ + const char* strval = LookupStringValue(variable); + if (strval) + { + value.PutString(strval); + value.PutChar(0); + return true; + } + + if (!Q_stricmp(variable, "stats")) + { + char stats[512]; + GetStatsString(stats, sizeof(stats)); + value.PutString(stats); + value.PutChar(0); + return true; + } + + if (!Q_stricmp(variable, "banlist")) + { + GetUserBanList(value); + return true; + } + + if (!Q_stricmp(variable, "playerlist")) + { + GetPlayerList(value); + return true; + } + + if (!Q_stricmp(variable, "maplist")) + { + GetMapList(value); + return true; + } + + if (!Q_stricmp(variable, "uptime")) + { + value.PutInt(int(Sys_FloatTime() - Host_GetStartTime())); + value.PutChar(0); + return true; + } + + if (!Q_stricmp(variable, "ipaddress")) + { + value.PutString(NET_AdrToString(net_local_adr)); + value.PutChar(0); + return true; + } + + if (!Q_stricmp(variable, "mapcycle")) + { + int len; + void* mapcyclelist = COM_LoadFileForMe(mapcyclefile.string, &len); + if (mapcyclelist && len) + { + value.PutString((char*)mapcyclelist); + value.PutChar(0); + COM_FreeFile(mapcyclelist); + } + return true; + } + + value.PutChar(0); + return false; +} + +void CServerRemoteAccess::RequestValue(int requestID, const char *variable) +{ + CUtlBuffer value(0, 0x100, true); + LookupValue(variable, value); + + int i = m_ResponsePackets.AddToTail(); + DataResponse_t& resp = m_ResponsePackets.Element(i); + + resp.packet.PutInt(requestID); + resp.packet.PutInt(0); + resp.packet.PutString(variable); + resp.packet.PutInt(value.TellPut()); + + if (value.TellPut()) + resp.packet.Put(value.Base(), value.TellPut()); + +} + +void CServerRemoteAccess::SetValue(const char *variable, const char *value) +{ + FileHandle_t f; + struct cvar_s *var; + + if (!Q_stricmp(variable, "map")) + { + Cbuf_AddText("changelevel "); + Cbuf_AddText((char*)value); + Cbuf_AddText("\n"); + Cbuf_Execute(); + } + else if (!Q_stricmp(variable, "mapcycle")) + { + f = FS_Open(mapcyclefile.string, "wt"); + if (!f) + { + Con_Printf("Couldn't write to read-only file %s, using file _dev_mapcycle.txt instead.\n", mapcyclefile.string); + Cvar_DirectSet(&mapcyclefile, "_temp_mapcycle.txt"); + f = FS_Open(mapcyclefile.string, "wt"); + } + + if (f) + { + FS_Write(value, Q_strlen(value) + 1, 1, f); + FS_Close(f); + } + } + else + { + var = Cvar_FindVar(variable); + if (var) + Cvar_DirectSet(var, value); + } +} + +void CServerRemoteAccess::ExecCommand(const char *cmdString) +{ + Cbuf_AddText((char*)cmdString); + Cbuf_AddText("\n"); + Cbuf_Execute(); +} + +void NotifyDedicatedServerUI(const char *message) +{ + g_ServerRemoteAccess.SendMessageToAdminUI(message); +} diff --git a/rehlds/engine/sv_remoteaccess.h b/rehlds/engine/sv_remoteaccess.h new file mode 100644 index 0000000..a1c2d68 --- /dev/null +++ b/rehlds/engine/sv_remoteaccess.h @@ -0,0 +1,84 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + + +#include "maintypes.h" +#include "IGameServerData.h" +#include "utlbuffer.h" +#include "utllinkedlist.h" + + +class CServerRemoteAccess : public IGameServerData { +public: + struct DataResponse_t { + CUtlBuffer packet; + }; + +private: + CUtlLinkedList m_ResponsePackets; + int m_iBytesSent; + int m_iBytesReceived; + +public: + + virtual ~CServerRemoteAccess() { } + + virtual void WriteDataRequest(const void *buffer, int bufferSize); + virtual int ReadDataResponse(void *data, int len); + + void WriteDataRequest_noVirt(const void *buffer, int bufferSize); + int ReadDataResponse_noVirt(void *data, int len); + + void SendMessageToAdminUI(const char *message); + + void RequestValue(int requestID, const char *variable); + + void SetValue(const char *variable, const char *value); + + void ExecCommand(const char *cmdString); + + bool LookupValue(const char *variable, CUtlBuffer &value); + + const char* LookupStringValue(const char *variable); + + void GetUserBanList(CUtlBuffer &value); + + void GetPlayerList(CUtlBuffer &value); + + void GetMapList(CUtlBuffer &value); +}; + + +#ifdef HOOK_ENGINE +#define g_ServerRemoteAccess (*pg_ServerRemoteAccess) +#endif + +extern class CServerRemoteAccess g_ServerRemoteAccess; + +extern void NotifyDedicatedServerUI(const char *message); diff --git a/rehlds/engine/sv_steam3.cpp b/rehlds/engine/sv_steam3.cpp new file mode 100644 index 0000000..795307c --- /dev/null +++ b/rehlds/engine/sv_steam3.cpp @@ -0,0 +1,949 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +bool (CSteam3Server::*pNotifyClientConnect)(client_t *client, const void *pvSteam2Key, uint32_t ucbSteam2Key) = &CSteam3Server::NotifyClientConnect; + + +/* ../engine/sv_steam3.cpp:81 */ +void CSteam3Server::OnGSPolicyResponse(GSPolicyResponse_t *pPolicyResponse) +{ + if (CRehldsPlatformHolder::get()->SteamGameServer()->BSecure()) + Con_Printf(" VAC secure mode is activated.\n"); + else + Con_Printf(" VAC secure mode disabled.\n"); +} + +/* ../engine/sv_steam3.cpp:97 */ +void CSteam3Server::OnLogonSuccess(SteamServersConnected_t *pLogonSuccess) +{ + if (m_bLogOnResult) + { + if (!m_bLanOnly) + Con_Printf("Reconnected to Steam servers.\n"); + } + else + { + m_bLogOnResult = 1; + if (!m_bLanOnly) + Con_Printf("Connection to Steam servers successful.\n"); + } + + m_SteamIDGS = CRehldsPlatformHolder::get()->SteamGameServer()->GetSteamID(); + CSteam3Server::SendUpdatedServerDetails(); +} + +/* ../engine/sv_steam3.cpp:128 */ +uint64_t CSteam3Server::GetSteamID() +{ + if (m_bLanOnly) + return CSteamID(0, k_EUniversePublic, k_EAccountTypeInvalid).ConvertToUint64(); + else + return m_SteamIDGS.ConvertToUint64(); +} + +/* ../engine/sv_steam3.cpp:145 */ +void CSteam3Server::OnLogonFailure(SteamServerConnectFailure_t *pLogonFailure) +{ + if (!m_bLogOnResult) + { + if (pLogonFailure->m_eResult == k_EResultServiceUnavailable) + { + if (!m_bLanOnly) + { + Con_Printf("Connection to Steam servers successful (SU).\n"); + if (m_bWantToBeSecure) + { + Con_Printf(" VAC secure mode not available.\n"); + m_bLogOnResult = true; + return; + } + } + } + else + { + if (!m_bLanOnly) + Con_Printf("Could not establish connection to Steam servers.\n"); + } + } + + m_bLogOnResult = true; +} + +/* ../engine/sv_steam3.cpp:181 */ +void CSteam3Server::OnGSClientDeny(GSClientDeny_t *pGSClientDeny) +{ + client_t* cl = CSteam3Server::ClientFindFromSteamID(pGSClientDeny->m_SteamID); + if (cl) + OnGSClientDenyHelper(cl, pGSClientDeny->m_eDenyReason, pGSClientDeny->m_rgchOptionalText); +} + +/* ../engine/sv_steam3.cpp:190 */ +void CSteam3Server::OnGSClientDenyHelper(client_t *cl, EDenyReason eDenyReason, const char *pchOptionalText) +{ + switch (eDenyReason) + { + case k_EDenyInvalidVersion: + SV_DropClient(cl, 0, "Client version incompatible with server. \nPlease exit and restart"); + break; + + case k_EDenyNotLoggedOn: + if (!this->m_bLanOnly) + SV_DropClient(cl, 0, "No Steam logon\n"); + break; + + case k_EDenyLoggedInElseWhere: + if (!this->m_bLanOnly) + SV_DropClient(cl, 0, "This Steam account is being used in another location\n"); + break; + + case k_EDenyNoLicense: + SV_DropClient(cl, 0, "This Steam account does not own this game. \nPlease login to the correct Steam account."); + break; + + case k_EDenyCheater: + SV_DropClient(cl, 0, "VAC banned from secure server\n"); + break; + + case k_EDenyUnknownText: + if (pchOptionalText && *pchOptionalText) + SV_DropClient(cl, 0, pchOptionalText); + else + SV_DropClient(cl, 0, "Client dropped by server"); + break; + + case k_EDenyIncompatibleAnticheat: + SV_DropClient(cl, 0, "You are running an external tool that is incompatible with Secure servers."); + break; + + case k_EDenyMemoryCorruption: + SV_DropClient(cl, 0, "Memory corruption detected."); + break; + + case k_EDenyIncompatibleSoftware: + SV_DropClient(cl, 0, "You are running software that is not compatible with Secure servers."); + break; + + case k_EDenySteamConnectionLost: + if (!this->m_bLanOnly) + SV_DropClient(cl, 0, "Steam connection lost\n"); + break; + + case k_EDenySteamConnectionError: + if (!this->m_bLanOnly) + SV_DropClient(cl, 0, "Unable to connect to Steam\n"); + break; + + case k_EDenySteamResponseTimedOut: + SV_DropClient(cl, 0, "Client timed out while answering challenge.\n---> Please make sure that you have opened the appropriate ports on any firewall you are connected behind.\n---> See http://support.steampowered.com for help with firewall configuration."); + break; + + case k_EDenySteamValidationStalled: + if (this->m_bLanOnly) + cl->network_userid.m_SteamID = 1; + break; + + default: + SV_DropClient(cl, 0, "Client dropped by server"); + break; + } +} + +/* ../engine/sv_steam3.cpp:290 */ +void CSteam3Server::OnGSClientApprove(GSClientApprove_t *pGSClientSteam2Accept) +{ + client_t* cl = ClientFindFromSteamID(pGSClientSteam2Accept->m_SteamID); + if (!cl) + return; + + char msg[256]; + if (SV_FilterUser(&cl->network_userid)) + { + sprintf(msg, "You have been banned from this server\n"); + SV_RejectConnection(&cl->netchan.remote_address, msg); + SV_DropClient(cl, 0, "STEAM UserID %s is in server ban list\n", SV_GetClientIDString(cl)); + } + else if (SV_CheckForDuplicateSteamID(cl) != -1) + { + sprintf(msg, "Your UserID is already in use on this server.\n"); + SV_RejectConnection(&cl->netchan.remote_address, msg); + SV_DropClient(cl, 0, "STEAM UserID %s is already\nin use on this server\n", SV_GetClientIDString(cl)); + } + else + { + _snprintf(msg, 0x200u, "\"%s<%i><%s><>\" STEAM USERID validated\n", cl->name, cl->userid, SV_GetClientIDString(cl)); + Con_DPrintf("%s", msg); + Log_Printf("%s", msg); + } +} + +/* ../engine/sv_steam3.cpp:268 */ +void CSteam3Server::OnGSClientKick(GSClientKick_t *pGSClientKick) /* linkage=_ZN13CSteam3Server14OnGSClientKickEP14GSClientKick_t */ +{ + client_t* cl = CSteam3Server::ClientFindFromSteamID(pGSClientKick->m_SteamID); + if (cl) + CSteam3Server::OnGSClientDenyHelper(cl, pGSClientKick->m_eDenyReason, 0); +} + +/* ../engine/sv_steam3.cpp:333 */ +client_t *CSteam3Server::ClientFindFromSteamID(CSteamID &steamIDFind) +{ + for (int i = 0; i < g_psvs.maxclients; i++) + { + auto cl = &g_psvs.clients[i]; + if (!cl->connected && !cl->active && !cl->spawned) + continue; + + if (cl->network_userid.idtype != AUTH_IDTYPE_STEAM) + continue; + + if (steamIDFind == cl->network_userid.m_SteamID) + return cl; + } + + return NULL; +} + +/* ../engine/sv_steam3.cpp:356 */ +CSteam3Server::CSteam3Server(void) : + m_CallbackGSClientApprove(this, &CSteam3Server::OnGSClientApprove), + m_CallbackGSClientDeny(this, &CSteam3Server::OnGSClientDeny), + m_CallbackGSClientKick(this, &CSteam3Server::OnGSClientKick), + m_CallbackGSPolicyResponse(this, &CSteam3Server::OnGSPolicyResponse), + m_CallbackLogonSuccess(this, &CSteam3Server::OnLogonSuccess), + m_CallbackLogonFailure(this, &CSteam3Server::OnLogonFailure), + m_SteamIDGS(1, 0, k_EUniverseInvalid, k_EAccountTypeInvalid) +{ +} + +/* ../engine/sv_steam3.cpp:375 */ +void CSteam3Server::Activate() +{ + bool bLanOnly; + int argSteamPort; + EServerMode eSMode; + int gamePort; + char gamedir[MAX_PATH]; + int usSteamPort; + uint32_t unIP; + + if (m_bLoggedOn) + { + bLanOnly = sv_lan.value != 0.0; + if (this->m_bLanOnly != bLanOnly) + { + m_bLanOnly = bLanOnly; + m_bWantToBeSecure = !COM_CheckParm("-insecure") && !bLanOnly; + } + } + else + { + m_bLoggedOn = 1; + unIP = 0; + usSteamPort = 26900; + argSteamPort = COM_CheckParm("-sport"); + if (argSteamPort > 0) + usSteamPort = atoi(com_argv[argSteamPort + 1]); + eSMode = eServerModeAuthenticationAndSecure; + if (net_local_adr.type == NA_IP) + unIP = ntohl(*(u_long *)&net_local_adr.ip[0]); + + m_bLanOnly = sv_lan.value > 0.0; + m_bWantToBeSecure = !COM_CheckParm("-insecure") && !m_bLanOnly; + COM_FileBase(com_gamedir, gamedir); + + if (!m_bWantToBeSecure) + eSMode = eServerModeAuthentication; + + if (m_bLanOnly) + eSMode = eServerModeNoAuthentication; + + gamePort = (int)iphostport.value; + if (gamePort == 0) + gamePort = (int)hostport.value; + + int nAppId = GetGameAppID(); + if (nAppId > 0 && g_pcls.state == ca_dedicated) + { + FILE* f = fopen("steam_appid.txt", "w+"); + if (f) + { + fprintf(f, "%d\n", nAppId); + fclose(f); + } + } + + if (!CRehldsPlatformHolder::get()->SteamGameServer_Init(unIP, usSteamPort, gamePort, 0xFFFFu, eSMode, gpszVersionString)) + Sys_Error("Unable to initialize Steam."); + + CRehldsPlatformHolder::get()->SteamGameServer()->SetProduct(gpszProductString); + CRehldsPlatformHolder::get()->SteamGameServer()->SetModDir(gamedir); + CRehldsPlatformHolder::get()->SteamGameServer()->SetDedicatedServer(g_pcls.state == ca_dedicated); + CRehldsPlatformHolder::get()->SteamGameServer()->SetGameDescription(gEntityInterface.pfnGetGameDescription()); + CRehldsPlatformHolder::get()->SteamGameServer()->LogOnAnonymous(); + m_bLogOnResult = false; + + if (COM_CheckParm("-nomaster")) + { + Con_Printf("Master server communication disabled.\n"); + gfNoMasterServer = TRUE; + } + else + { + if (!gfNoMasterServer && g_psvs.maxclients > 1) + { + CRehldsPlatformHolder::get()->SteamGameServer()->EnableHeartbeats(true); + double fMasterHeartbeatTimeout = 200.0; + if (!Q_strcmp(gamedir, "dmc")) + fMasterHeartbeatTimeout = 150.0; + if (!Q_strcmp(gamedir, "tfc")) + fMasterHeartbeatTimeout = 400.0; + if (!Q_strcmp(gamedir, "cstrike")) + fMasterHeartbeatTimeout = 400.0; + + CRehldsPlatformHolder::get()->SteamGameServer()->SetHeartbeatInterval((int)fMasterHeartbeatTimeout); + CSteam3Server::NotifyOfLevelChange(true); + } + } + } +} + +/* ../engine/sv_steam3.cpp:506 */ +void CSteam3Server::Shutdown(void) /* linkage=_ZN13CSteam3Server8ShutdownEv */ +{ + if (this->m_bLoggedOn) + { + SteamGameServer()->EnableHeartbeats(0); + SteamGameServer()->LogOff(); + + SteamGameServer_Shutdown(); + this->m_bLoggedOn = false; + } +} + +/* ../engine/sv_steam3.cpp:537 */ +bool CSteam3Server::NotifyClientConnect(client_t *client, const void *pvSteam2Key, uint32_t ucbSteam2Key) /* linkage=_ZN13CSteam3Server19NotifyClientConnectEP8client_sPKvj */ +{ + class CSteamID steamIDClient; + bool bRet = false; + + if (client == NULL || !m_bLoggedOn) + return false; + + client->network_userid.idtype = AUTH_IDTYPE_STEAM; + + bRet = CRehldsPlatformHolder::get()->SteamGameServer()->SendUserConnectAndAuthenticate(htonl(client->network_userid.clientip), pvSteam2Key, ucbSteam2Key, &steamIDClient); + client->network_userid.m_SteamID = steamIDClient.ConvertToUint64(); + + return bRet; +} + +/* ../engine/sv_steam3.cpp:578 */ +bool CSteam3Server::NotifyBotConnect(client_t *client) +{ + if (client == NULL || !m_bLoggedOn) + return false; + + client->network_userid.idtype = AUTH_IDTYPE_LOCAL; + CSteamID steamId = CRehldsPlatformHolder::get()->SteamGameServer()->CreateUnauthenticatedUserConnection(); + client->network_userid.m_SteamID = steamId.ConvertToUint64(); + return true; +} + +/* ../engine/sv_steam3.cpp:596 */ +void CSteam3Server::NotifyClientDisconnect(client_t *cl) +{ + if (!cl || !m_bLoggedOn) + return; + + if (cl->network_userid.idtype == AUTH_IDTYPE_STEAM || cl->network_userid.idtype == AUTH_IDTYPE_LOCAL) + { + CRehldsPlatformHolder::get()->SteamGameServer()->SendUserDisconnect(cl->network_userid.m_SteamID); + } +} + +/* ../engine/sv_steam3.cpp:616 */ +void CSteam3Server::NotifyOfLevelChange(bool bForce) +{ + SendUpdatedServerDetails(); + bool iHasPW = (sv_password.string[0] && Q_stricmp(sv_password.string, "none")); + CRehldsPlatformHolder::get()->SteamGameServer()->SetPasswordProtected(iHasPW); + CRehldsPlatformHolder::get()->SteamGameServer()->ClearAllKeyValues(); + + for (cvar_t *var = cvar_vars; var; var = var->next) + { + if (!(var->flags & FCVAR_SERVER)) + continue; + + const char *szVal; + if (var->flags & FCVAR_PROTECTED) + { + if (Q_strlen(var->string) > 0 && Q_stricmp(var->string, "none")) + szVal = "1"; + else + szVal = "0"; + } + else + { + szVal = var->string; + } + CRehldsPlatformHolder::get()->SteamGameServer()->SetKeyValue(var->name, szVal); + } +} + +/* ../engine/sv_steam3.cpp:664 */ +void CSteam3Server::RunFrame() +{ + bool bHasPlayers; + char szOutBuf[4096]; + double fCurTime; + + static double s_fLastRunFragsUpdate; + static double s_fLastRunCallback; + static double s_fLastRunSendPackets; + + if (g_psvs.maxclients <= 1) + return; + + fCurTime = Sys_FloatTime(); + if (fCurTime - s_fLastRunFragsUpdate > 1.0) + { + s_fLastRunFragsUpdate = fCurTime; + bHasPlayers = false; + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t* cl = &g_psvs.clients[i]; + if (cl->active || cl->spawned || cl->connected) + { + bHasPlayers = true; + break; + } + } + + m_bHasActivePlayers = bHasPlayers; + SendUpdatedServerDetails(); + bool iHasPW = (sv_password.string[0] && Q_stricmp(sv_password.string, "none")); + CRehldsPlatformHolder::get()->SteamGameServer()->SetPasswordProtected(iHasPW); + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t* cl = &g_psvs.clients[i]; + if (!cl->active) + continue; + + CRehldsPlatformHolder::get()->SteamGameServer()->BUpdateUserData(CSteamID(cl->network_userid.m_SteamID), cl->name, cl->edict->v.frags); + } + + if (CRehldsPlatformHolder::get()->SteamGameServer()->WasRestartRequested()) + { + Con_Printf("%cMasterRequestRestart\n", 3); + if (COM_CheckParm("-steam")) + { + Con_Printf("Your server needs to be restarted in order to receive the latest update.\n"); + Log_Printf("Your server needs to be restarted in order to receive the latest update.\n"); + } + else + { + Con_Printf("Your server is out of date. Please update and restart.\n"); + } + } + } + + if (fCurTime - s_fLastRunCallback > 0.1) + { + CRehldsPlatformHolder::get()->SteamGameServer_RunCallbacks(); + s_fLastRunCallback = fCurTime; + } + + if (fCurTime - s_fLastRunSendPackets > 0.01) + { + s_fLastRunSendPackets = fCurTime; + + uint16_t port; + uint32_t ip; + int iLen = CRehldsPlatformHolder::get()->SteamGameServer()->GetNextOutgoingPacket(szOutBuf, sizeof(szOutBuf), &ip, &port); + while (iLen > 0) + { + netadr_t netAdr; + *((uint32_t*)&netAdr.ip[0]) = htonl(ip); + netAdr.port = htons(port); + netAdr.type = NA_IP; + + NET_SendPacket(NS_SERVER, iLen, szOutBuf, netAdr); + + iLen = CRehldsPlatformHolder::get()->SteamGameServer()->GetNextOutgoingPacket(szOutBuf, sizeof(szOutBuf), &ip, &port); + } + } +} + +/* ../engine/sv_steam3.cpp:777 */ +void CSteam3Server::SendUpdatedServerDetails() +{ + int botCount = 0; + if (g_psvs.maxclients > 0) + { + + for (int i = 0; i < g_psvs.maxclients; i++) + { + auto cl = &g_psvs.clients[i]; + if ((cl->active || cl->spawned || cl->connected) && cl->fakeclient) + ++botCount; + } + } + + int maxPlayers = sv_visiblemaxplayers.value; + if (maxPlayers < 0) + maxPlayers = g_psvs.maxclients; + + CRehldsPlatformHolder::get()->SteamGameServer()->SetMaxPlayerCount(maxPlayers); + CRehldsPlatformHolder::get()->SteamGameServer()->SetBotPlayerCount(botCount); + CRehldsPlatformHolder::get()->SteamGameServer()->SetServerName(Cvar_VariableString("hostname")); + CRehldsPlatformHolder::get()->SteamGameServer()->SetMapName(g_psv.name); +} + + +/* ../engine/sv_steam3.cpp:523 */ +void CSteam3Client::Shutdown(void) /* linkage=_ZN13CSteam3Client8ShutdownEv */ +{ + if (this->m_bLoggedOn) + { + SteamAPI_Shutdown(); + this->m_bLoggedOn = false; + } +} + +/* ../engine/sv_steam3.cpp:816 */ +int CSteam3Client::InitiateGameConnection(void *pData, int cbMaxData, uint64_t steamID, uint32_t unIPServer, uint16_t usPortServer, bool bSecure) +{ + return SteamUser()->InitiateGameConnection(pData, cbMaxData, CSteamID(steamID), ntohl(unIPServer), ntohs(usPortServer), bSecure); +} + +/* ../engine/sv_steam3.cpp:822 */ +void CSteam3Client::TerminateConnection(uint32_t unIPServer, uint16_t usPortServer) +{ + SteamUser()->TerminateGameConnection(ntohl(unIPServer), ntohs(usPortServer)); +} + +/* ../engine/sv_steam3.cpp:827 */ +void CSteam3Client::InitClient() +{ + if (m_bLoggedOn) + return; + + m_bLoggedOn = true; + _unlink("steam_appid.txt"); + if (!getenv("SteamAppId")) + { + int nAppID = GetGameAppID(); + if (nAppID > 0) + { + FILE* f = fopen("steam_appid.txt", "w+"); + if (f) + { + fprintf(f, "%d\n", nAppID); + fclose(f); + } + } + } + + if (!SteamAPI_Init()) + Sys_Error("Failed to initalize authentication interface. Exiting...\n"); + + m_bLogOnResult = false; +} + +/* ../engine/sv_steam3.cpp:864 */ +void CSteam3Client::OnClientGameServerDeny(ClientGameServerDeny_t *pClientGameServerDeny) /* linkage=_ZN13CSteam3Client22OnClientGameServerDenyEP22ClientGameServerDeny_t */ +{ + COM_ExplainDisconnection(TRUE, "Invalid server version, unable to connect."); + CL_Disconnect(); +} + +/* ../engine/sv_steam3.cpp:874 */ +void CSteam3Client::OnGameServerChangeRequested(GameServerChangeRequested_t *pGameServerChangeRequested) /* linkage=_ZN13CSteam3Client27OnGameServerChangeRequestedEP27GameServerChangeRequested_t */ +{ +#ifndef SWDS + char *cmd; + + Cvar_DirectSet(&password, pGameServerChangeRequested->m_rgchPassword); + Con_Printf("Connecting to %s\n", pGameServerChangeRequested->m_rgchServer); + cmd = va("connect %s\n", pGameServerChangeRequested->m_rgchServer); + Cbuf_AddText(cmd); +#endif +} + +/* ../engine/sv_steam3.cpp:887 */ +void CSteam3Client::OnGameOverlayActivated(GameOverlayActivated_t *pGameOverlayActivated) /* linkage=_ZN13CSteam3Client22OnGameOverlayActivatedEP22GameOverlayActivated_t */ +{ +#ifndef SWDS + if (Host_IsSinglePlayerGame()) + { + if (pGameOverlayActivated->m_bActive) + { + Cbuf_AddText("setpause;"); + } + else + { + if (!(unsigned __int8)(*(int(**)(void))(*(_DWORD *)g_pGameUI007 + 44))()) + { + Cbuf_AddText("unpause;"); + } + } + } +#endif +} + +/* ../engine/sv_steam3.cpp:905 */ +void CSteam3Client::RunFrame(void) /* linkage=_ZN13CSteam3Client8RunFrameEv */ +{ + CRehldsPlatformHolder::get()->SteamAPI_RunCallbacks(); +} + + +/* ../engine/sv_steam3.cpp:552 */ +uint64_t ISteamGameServer_CreateUnauthenticatedUserConnection(void) +{ + if (!CRehldsPlatformHolder::get()->SteamGameServer()) + { + return 0L; + } + + return CRehldsPlatformHolder::get()->SteamGameServer()->CreateUnauthenticatedUserConnection().ConvertToUint64(); +} + +/* ../engine/sv_steam3.cpp:559 */ +bool ISteamGameServer_BUpdateUserData(uint64_t steamid, const char *netname, uint32_t score) +{ + if (!CRehldsPlatformHolder::get()->SteamGameServer()) + { + return false; + } + + return CRehldsPlatformHolder::get()->SteamGameServer()->BUpdateUserData(steamid, netname, score); +} + +/* ../engine/sv_steam3.cpp:566 */ +bool ISteamApps_BIsSubscribedApp(uint32_t appid) +{ + if (CRehldsPlatformHolder::get()->SteamApps()) + { + ISteamApps* apps = CRehldsPlatformHolder::get()->SteamApps(); + return apps->BIsSubscribedApp(appid); + } + + return false; +} + +/* ../engine/sv_steam3.cpp:805 */ +const char *Steam_GetCommunityName() +{ + if (SteamFriends()) + return SteamFriends()->GetPersonaName(); + + return NULL; +} + +qboolean Steam_NotifyClientConnect_api(IGameClient *cl, const void *pvSteam2Key, unsigned int ucbSteam2Key) +{ + return Steam_NotifyClientConnect_internal(cl->GetClient(), pvSteam2Key, ucbSteam2Key); +} + +qboolean Steam_NotifyClientConnect(client_t *cl, const void *pvSteam2Key, unsigned int ucbSteam2Key) +{ + return g_RehldsHookchains.m_Steam_NotifyClientConnect + .callChain(Steam_NotifyClientConnect_api, GetRehldsApiClient(cl), pvSteam2Key, ucbSteam2Key); +} + + +/* ../engine/sv_steam3.cpp:914 */ +qboolean Steam_NotifyClientConnect_internal(client_t *cl, const void *pvSteam2Key, unsigned int ucbSteam2Key) +{ + if (Steam3Server()) + { + return Steam3Server()->NotifyClientConnect(cl, pvSteam2Key, ucbSteam2Key); + } + return NULL; +} + +qboolean Steam_NotifyBotConnect_api(IGameClient* cl) +{ + return Steam_NotifyBotConnect_internal(cl->GetClient()); +} + +qboolean Steam_NotifyBotConnect(client_t *cl) +{ + return g_RehldsHookchains.m_Steam_NotifyBotConnect.callChain(Steam_NotifyBotConnect_api, GetRehldsApiClient(cl)); +} + +/* ../engine/sv_steam3.cpp:924 */ +qboolean Steam_NotifyBotConnect_internal(client_t *cl) +{ + if (Steam3Server()) + { + return Steam3Server()->NotifyBotConnect(cl); + } + return NULL; +} + +void Steam_NotifyClientDisconnect_api(IGameClient* cl) +{ + Steam_NotifyClientDisconnect_internal(cl->GetClient()); +} + +void Steam_NotifyClientDisconnect(client_t *cl) +{ + g_RehldsHookchains.m_Steam_NotifyClientDisconnect.callChain(Steam_NotifyClientDisconnect_api, GetRehldsApiClient(cl)); +} + +/* ../engine/sv_steam3.cpp:934 */ +void Steam_NotifyClientDisconnect_internal(client_t *cl) +{ + if (Steam3Server()) + { + Steam3Server()->NotifyClientDisconnect(cl); + } +} + +/* ../engine/sv_steam3.cpp:944 */ +void Steam_NotifyOfLevelChange(void) +{ + if (Steam3Server()) + { + Steam3Server()->NotifyOfLevelChange(false); + } +} + +/* ../engine/sv_steam3.cpp:955 */ +void Steam_Shutdown(void) +{ + if (Steam3Server()) + { + Steam3Server()->Shutdown(); + delete s_Steam3Server; + s_Steam3Server = NULL; + } +} + +/* ../engine/sv_steam3.cpp:965 */ +void Steam_Activate(void) +{ + if (!Steam3Server()) + { + s_Steam3Server = new CSteam3Server(); + if (s_Steam3Server == NULL) + return; + } + + Steam3Server()->Activate(); +} + +/* ../engine/sv_steam3.cpp:975 */ +void Steam_RunFrame(void) +{ + if (Steam3Server()) + { + Steam3Server()->RunFrame(); + } +} + +/* ../engine/sv_steam3.cpp:986 */ +void Steam_SetCVar(const char *pchKey, const char *pchValue) +{ + if (Steam3Server()) + { + CRehldsPlatformHolder::get()->SteamGameServer()->SetKeyValue(pchKey, pchValue); + } +} + +/* ../engine/sv_steam3.cpp:996 */ +void Steam_ClientRunFrame() +{ + Steam3Client()->RunFrame(); +} + +/* ../engine/sv_steam3.cpp:1002 */ +void Steam_InitClient(void) +{ + Steam3Client()->InitClient(); +} + +/* ../engine/sv_steam3.cpp:1007 */ +int Steam_GSInitiateGameConnection(void *pData, int cbMaxData, uint64_t steamID, uint32_t unIPServer, uint16_t usPortServer, qboolean bSecure) +{ + return Steam3Client()->InitiateGameConnection(pData, cbMaxData, steamID, unIPServer, usPortServer, bSecure != 0); +} + +/* ../engine/sv_steam3.cpp:1013 */ +void Steam_GSTerminateGameConnection(uint32_t unIPServer, uint16_t usPortServer) +{ + Steam3Client()->TerminateConnection(unIPServer, usPortServer); +} + +/* ../engine/sv_steam3.cpp:1019 */ +void Steam_ShutdownClient(void) +{ + Steam3Client()->Shutdown(); +} + +/* ../engine/sv_steam3.cpp:1026 */ +uint64_t Steam_GSGetSteamID() +{ + return Steam3Server()->GetSteamID(); +} + +/* ../engine/sv_steam3.cpp:1031 */ +qboolean Steam_GSBSecure(void) +{ + Steam3Server(); + return CRehldsPlatformHolder::get()->SteamGameServer()->BSecure(); +} + +/* ../engine/sv_steam3.cpp:1036 */ +qboolean Steam_GSBLoggedOn(void) +{ + return Steam3Server()->BLoggedOn() && CRehldsPlatformHolder::get()->SteamGameServer()->BLoggedOn(); +} + +/* ../engine/sv_steam3.cpp:1041 */ +qboolean Steam_GSBSecurePreference(void) +{ + return Steam3Server()->BWantsSecure(); +} + +/* ../engine/sv_steam3.cpp:1046 */ +TSteamGlobalUserID Steam_Steam3IDtoSteam2(uint64_t unSteamID) +{ + class CSteamID steamID = unSteamID; + TSteamGlobalUserID steam2ID; + steamID.ConvertToSteam2(&steam2ID); + return steam2ID; +} + +/* ../engine/sv_steam3.cpp:1054 */ +uint64_t Steam_StringToSteamID(const char *pStr) +{ + CSteamID steamID; + if (Steam3Server()) + { + CSteamID serverSteamId(Steam3Server()->GetSteamID()); + steamID.SetFromSteam2String(pStr, serverSteamId.GetEUniverse()); + } + else + { + steamID.SetFromSteam2String(pStr, k_EUniversePublic); + } + + return steamID.ConvertToUint64(); +} + +/* ../engine/sv_steam3.cpp:1065 */ +const char *Steam_GetGSUniverse(void) +{ + CSteamID steamID(Steam3Server()->GetSteamID()); + switch (steamID.GetEUniverse()) + { + case k_EUniversePublic: + return ""; + + case k_EUniverseBeta: + return "(beta)"; + + case k_EUniverseInternal: + return "(internal)"; + + default: + return "(u)"; + } +} + + +CSteam3Server *s_Steam3Server; // static + +/* ../engine/sv_steam3.cpp:1085 */ +CSteam3Server *Steam3Server(void) +{ + return s_Steam3Server; +} + +CSteam3Client s_Steam3Client; // static + +/* ../engine/sv_steam3.cpp:1096 */ +CSteam3Client *Steam3Client(void) +{ + return &s_Steam3Client; +} + +/* ../engine/sv_steam3.cpp:1102 */ +void Master_SetMaster_f(void) +{ + int i; + const char * pszCmd; + + i = Cmd_Argc(); + if (!Steam3Server()) + { + Con_Printf("Usage:\nSetmaster unavailable, start a server first.\n"); + return; + } + + if (i < 2 || i > 5) + { + Con_Printf("Usage:\nSetmaster \n"); + return; + } + + + pszCmd = Cmd_Argv(1); + if (!pszCmd || !pszCmd[0]) + return; + + if (Q_stricmp(pszCmd, "disable") || gfNoMasterServer) + { + if (!Q_stricmp(pszCmd, "enable")) + { + if (gfNoMasterServer) + { + gfNoMasterServer = 0; + CRehldsPlatformHolder::get()->SteamGameServer()->EnableHeartbeats(gfNoMasterServer != 0); + } + } + } + else + { + gfNoMasterServer = 1; + CRehldsPlatformHolder::get()->SteamGameServer()->EnableHeartbeats(gfNoMasterServer != 0); + } +} + +/* ../engine/sv_steam3.cpp:1143 */ +void Steam_HandleIncomingPacket(byte *data, int len, int fromip, uint16_t port) +{ + CRehldsPlatformHolder::get()->SteamGameServer()->HandleIncomingPacket(data, len, fromip, port); +} diff --git a/rehlds/engine/sv_steam3.h b/rehlds/engine/sv_steam3.h new file mode 100644 index 0000000..78bf746 --- /dev/null +++ b/rehlds/engine/sv_steam3.h @@ -0,0 +1,233 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SV_STEAM3_H +#define SV_STEAM3_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "common.h" +#include "common/SteamCommon.h" +#include "public/steam/steam_api.h" +#include "public/steam/steam_gameserver.h" +#include "public/steam/steamclientpublic.h" +#include "server.h" + + +/* ../engine/sv_steam3.h:21 */ +class CSteam3 +{ +public: // TODO: Make protected after all (it is set public for testing purpouses) + + bool m_bLoggedOn; + bool m_bLogOnResult; + HSteamPipe m_hSteamPipe; + +protected: + /* ../engine/sv_steam3.h:24 */ + CSteam3(void) { + m_bLoggedOn = false; + m_bLogOnResult = false; + m_hSteamPipe = 0; + } + + /* ../engine/sv_steam3.h:32 */ + virtual ~CSteam3(void) { } + + /* ../engine/sv_steam3.h:38 */ + virtual void Shutdown(void) = 0; /* linkage=_ZN7CSteam38ShutdownEv */ + + /* ../engine/sv_steam3.h:40 */ + void GSSendUserStatusResponse(class CSteamID &, int, int); /* linkage=_ZN7CSteam324GSSendUserStatusResponseER8CSteamIDii */ + + /* ../engine/sv_steam3.h:43 */ + bool InitModule(void); /* linkage=_ZN7CSteam310InitModuleEv */ +}; + +/* ../engine/sv_steam3.h:52 */ +class CSteam3Server : public CSteam3 +{ +public: + + STEAM_GAMESERVER_CALLBACK(CSteam3Server, OnGSClientApprove, GSClientApprove_t, m_CallbackGSClientApprove); + STEAM_GAMESERVER_CALLBACK(CSteam3Server, OnGSClientDeny, GSClientDeny_t, m_CallbackGSClientDeny); + STEAM_GAMESERVER_CALLBACK(CSteam3Server, OnGSClientKick, GSClientKick_t, m_CallbackGSClientKick); + STEAM_GAMESERVER_CALLBACK(CSteam3Server, OnGSPolicyResponse, GSPolicyResponse_t, m_CallbackGSPolicyResponse); + STEAM_GAMESERVER_CALLBACK(CSteam3Server, OnLogonSuccess, SteamServersConnected_t, m_CallbackLogonSuccess); + STEAM_GAMESERVER_CALLBACK(CSteam3Server, OnLogonFailure, SteamServerConnectFailure_t, m_CallbackLogonFailure); + +public: // TODO: Make protected after all (it is set public for testing purpouses) + bool m_bHasActivePlayers; + bool m_bWantToBeSecure; + bool m_bLanOnly; + CSteamID m_SteamIDGS; + +public: + + /* ../engine/sv_steam3.h:58 */ + NOBODY void SetServerType(void); /* linkage=_ZN13CSteam3Server13SetServerTypeEv */ + + /* ../engine/sv_steam3.h:68 */ + NOBODY void SetSpawnCount(int count); /* linkage=_ZN13CSteam3Server13SetSpawnCountEi */ + + /* ../engine/sv_steam3.h:72 */ + NOBODY bool BSecure(void); /* linkage=_ZNK13CSteam3Server7BSecureEv */ + + /* ../engine/sv_steam3.h:73 */ + NOBODY bool BLanOnly(void); /* linkage=_ZNK13CSteam3Server8BLanOnlyEv */ + + /* ../engine/sv_steam3.h:74 */ + bool BWantsSecure(void) + { + return m_bWantToBeSecure; + } + + /* ../engine/sv_steam3.h:75 */ + bool BLoggedOn(void) + { + return m_bLoggedOn; + } + + /* ../engine/sv_steam3.cpp:128 */ + uint64_t GetSteamID(void); /* linkage=_ZN13CSteam3Server10GetSteamIDEv */ + + /* ../engine/sv_steam3.cpp:190 */ + void OnGSClientDenyHelper(client_t *cl, EDenyReason eDenyReason, const char *pchOptionalText); /* linkage=_ZN13CSteam3Server20OnGSClientDenyHelperEP8client_s11EDenyReasonPKc */ + + /* ../engine/sv_steam3.cpp:333 */ + client_t *ClientFindFromSteamID(class CSteamID &steamIDFind); /* linkage=_ZN13CSteam3Server21ClientFindFromSteamIDER8CSteamID */ + + /* ../engine/sv_steam3.cpp:356 */ + CSteam3Server(void); + + /* ../engine/sv_steam3.cpp:375 */ + void Activate(void); /* linkage=_ZN13CSteam3Server8ActivateEv */ + + /* ../engine/sv_steam3.cpp:506 */ + virtual void Shutdown(void); /* linkage=_ZN13CSteam3Server8ShutdownEv */ + + /* ../engine/sv_steam3.cpp:537 */ + bool NotifyClientConnect(client_t *client, const void *pvSteam2Key, uint32_t ucbSteam2Key); /* linkage=_ZN13CSteam3Server19NotifyClientConnectEP8client_sPKvj */ + + /* ../engine/sv_steam3.cpp:578 */ + bool NotifyBotConnect(client_t *client); /* linkage=_ZN13CSteam3Server16NotifyBotConnectEP8client_s */ + + /* ../engine/sv_steam3.cpp:596 */ + void NotifyClientDisconnect(client_t *cl); /* linkage=_ZN13CSteam3Server22NotifyClientDisconnectEP8client_s */ + + /* ../engine/sv_steam3.cpp:616 */ + void NotifyOfLevelChange(bool bForce); /* linkage=_ZN13CSteam3Server19NotifyOfLevelChangeEb */ + + /* ../engine/sv_steam3.cpp:664 */ + void RunFrame(void); /* linkage=_ZN13CSteam3Server8RunFrameEv */ + + /* ../engine/sv_steam3.cpp:777 */ + void SendUpdatedServerDetails(void); /* linkage=_ZN13CSteam3Server24SendUpdatedServerDetailsEv */ +}; + +/* ../engine/sv_steam3.h:101 */ +class CSteam3Client : public CSteam3 +{ +public: + STEAM_CALLBACK(CSteam3Client, OnClientGameServerDeny, ClientGameServerDeny_t, m_CallbackClientGameServerDeny); + STEAM_CALLBACK(CSteam3Client, OnGameServerChangeRequested, GameServerChangeRequested_t, m_CallbackGameServerChangeRequested); + STEAM_CALLBACK(CSteam3Client, OnGameOverlayActivated, GameOverlayActivated_t, m_CallbackGameOverlayActivated); + + /* ../engine/sv_steam3.h:104 */ + CSteam3Client(void) : + m_CallbackClientGameServerDeny(this, &CSteam3Client::OnClientGameServerDeny), + m_CallbackGameServerChangeRequested(this, &CSteam3Client::OnGameServerChangeRequested), + m_CallbackGameOverlayActivated(this, &CSteam3Client::OnGameOverlayActivated) + { } + + /* ../engine/sv_steam3.cpp:523 */ + virtual void Shutdown(void); /* linkage=_ZN13CSteam3Client8ShutdownEv */ + + /* ../engine/sv_steam3.cpp:816 */ + int InitiateGameConnection(void *pData, int cbMaxData, uint64 steamID, uint32 unIPServer, uint16 usPortServer, bool bSecure); /* linkage=_ZN13CSteam3Client22InitiateGameConnectionEPviyjtb */ + + /* ../engine/sv_steam3.cpp:822 */ + void TerminateConnection(uint32, uint16); /* linkage=_ZN13CSteam3Client19TerminateConnectionEjt */ + + /* ../engine/sv_steam3.cpp:827 */ + void InitClient(void); /* linkage=_ZN13CSteam3Client10InitClientEv */ + + /* ../engine/sv_steam3.cpp:905 */ + void RunFrame(void); /* linkage=_ZN13CSteam3Client8RunFrameEv */ +}; + + +#ifdef HOOK_ENGINE +#define s_Steam3Server (*ps_Steam3Server) +#define s_Steam3Client (*ps_Steam3Client) +#endif // HOOK_ENGINE + + +extern CSteam3Server *s_Steam3Server; +extern CSteam3Client s_Steam3Client; + + +extern bool (CSteam3Server::*pNotifyClientConnect)(client_t *client, const void *pvSteam2Key, uint32_t ucbSteam2Key); + + +uint64_t ISteamGameServer_CreateUnauthenticatedUserConnection(void); +bool ISteamGameServer_BUpdateUserData(uint64_t steamid, const char *netname, uint32_t score); +bool ISteamApps_BIsSubscribedApp(uint32_t appid); +const char *Steam_GetCommunityName(void); +qboolean Steam_NotifyClientConnect(client_t *cl, const void *pvSteam2Key, unsigned int ucbSteam2Key); +qboolean Steam_NotifyClientConnect_internal(client_t *cl, const void *pvSteam2Key, unsigned int ucbSteam2Key); +qboolean Steam_NotifyBotConnect(client_t *cl); +qboolean Steam_NotifyBotConnect_internal(client_t *cl); +qboolean Steam_NotifyBotConnect_api(IGameClient* cl); +void Steam_NotifyClientDisconnect(client_t *cl); +void Steam_NotifyClientDisconnect_internal(client_t *cl); +void Steam_NotifyOfLevelChange(void); +void Steam_Shutdown(void); +void Steam_Activate(void); +void Steam_RunFrame(void); +void Steam_SetCVar(const char *pchKey, const char *pchValue); +void Steam_ClientRunFrame(void); +void Steam_InitClient(void); +int Steam_GSInitiateGameConnection(void *pData, int cbMaxData, uint64_t steamID, uint32_t unIPServer, uint16_t usPortServer, qboolean bSecure); +void Steam_GSTerminateGameConnection(uint32_t unIPServer, uint16_t usPortServer); +void Steam_ShutdownClient(void); +uint64_t Steam_GSGetSteamID(void); +qboolean Steam_GSBSecure(void); +qboolean Steam_GSBLoggedOn(void); +qboolean Steam_GSBSecurePreference(void); +TSteamGlobalUserID Steam_Steam3IDtoSteam2(uint64_t unSteamID); +uint64_t Steam_StringToSteamID(const char *pStr); +const char *Steam_GetGSUniverse(void); +CSteam3Server *Steam3Server(void); +CSteam3Client *Steam3Client(void); +void Master_SetMaster_f(void); +void Steam_HandleIncomingPacket(byte *data, int len, int fromip, uint16_t port); + +#endif // SV_STEAM3_H diff --git a/rehlds/engine/sv_upld.cpp b/rehlds/engine/sv_upld.cpp new file mode 100644 index 0000000..ff9c5ad --- /dev/null +++ b/rehlds/engine/sv_upld.cpp @@ -0,0 +1,508 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +/* ../engine/sv_upld.c:51 */ +// Checks MD5 of the resource against local cache and returns TRUE if resource was found or if downloads are disabled. Otherwise, if resource was requested from the player, it returns FALSE. +qboolean SV_CheckFile(sizebuf_t *msg, char *filename) +{ + resource_t p; + + Q_memset(&p, 0, sizeof(p)); + +#ifdef REHLDS_FIXES + + // FIXED: First, check for allowed downloads, then try to lookup, this is faster if downloads aren't enabled + if (sv_allow_upload.value == 0.0f) + { + // Downloads are not allowed, continue with the state we have + return TRUE; + } + + if (Q_strlen(filename) == 36 && Q_strnicmp(filename, "!MD5", 4) == 0) + { + // MD5 signature is correct, lets try to find this resource locally + COM_HexConvert(filename + 4, 32, p.rgucMD5_hash); + if (HPAK_GetDataPointer("custom.hpk", &p, 0, 0)) + { + return TRUE; + } + } + +#else // REHLDS_FIXES + + if (Q_strlen(filename) == 36 && Q_strnicmp(filename, "!MD5", 4) == 0) + { + // MD5 signature is correct, lets try to find this resource locally + COM_HexConvert(filename + 4, 32, p.rgucMD5_hash); + if (HPAK_GetDataPointer("custom.hpk", &p, 0, 0)) + { + return TRUE; + } + } + + if (sv_allow_upload.value == 0.0f) + { + // Downloads are not allowed, continue with the state we have + return TRUE; + } + +#endif // REHLDS_FIXES + + MSG_WriteByte(msg, svc_stufftext); + MSG_WriteString(msg, va("upload \"!MD5%s\"\n", MD5_Print(p.rgucMD5_hash))); + + return FALSE; +} + +/* ../engine/sv_upld.c:93 */ +void SV_ClearResourceLists(client_t *cl) +{ + if (!cl) + { + Sys_Error("SV_ClearResourceLists with NULL client!"); + } + + SV_ClearResourceList(&cl->resourcesneeded); + SV_ClearResourceList(&cl->resourcesonhand); +} + +/* ../engine/sv_upld.c:108 */ +// Reinitializes customizations list. Tries to create customization for each resource in on-hands list. +void SV_CreateCustomizationList(client_t *pHost) +{ + resource_t *pResource; + + // Clear customizations list +#ifdef REHLDS_FIXES + // FIXED: Do it right, free mem, even if this is not actually needed (should be freed already on disconnect) + COM_ClearCustomizationList(&pHost->customdata, FALSE); +#else // REHLDS_FIXES + pHost->customdata.pNext = NULL; +#endif // REHLDS_FIXES + + pResource = pHost->resourcesonhand.pNext; + while (pResource != &pHost->resourcesonhand) + { + // TODO: Check if we need to filter resources here based on type (t_decal) and flags (RES_CUSTOM) + + // Search if this resource already in customizations list + qboolean bFound = FALSE; + customization_t *pList = pHost->customdata.pNext; + while (pList && Q_memcmp(pList->resource.rgucMD5_hash, pResource->rgucMD5_hash, 16)) + { + pList = pList->pNext; + } + if (pList != NULL) + { + Con_DPrintf("SV_CreateCustomization list, ignoring dup. resource for player %s\n", pHost->name); + bFound = TRUE; + } + + if (!bFound) + { + // Try to create customization and add it to the list + customization_t *pCust; + qboolean bNoError; + int nLumps = 0; + bNoError = COM_CreateCustomization(&pHost->customdata, pResource, -1, FCUST_WIPEDATA | FCUST_FROMHPAK, &pCust, &nLumps); + if (bNoError) + { + pCust->nUserData2 = nLumps; + gEntityInterface.pfnPlayerCustomization(pHost->edict, pCust); + } + else + { + if (sv_allow_upload.value == 0.0f) + Con_Printf("Ignoring custom decal from %s\n", pHost->name); + else + Con_Printf("Ignoring invalid custom decal from %s\n", pHost->name); + } + } + + pResource = pResource->pNext; + } +} + +/* ../engine/sv_upld.c:185 */ +// Sends resource to all other players, optionally skipping originating player. +void SV_Customization(client_t *pPlayer, resource_t *pResource, qboolean bSkipPlayer) +{ + int i; + int nPlayerNumber; + client_t *pHost; + + // Get originating player id + for (i = 0, pHost = g_psvs.clients; i < g_psvs.maxclients; i++, pHost++) + { + if (pHost == pPlayer) + break; + } + if (i == g_psvs.maxclients) + { + Sys_Error("Couldn't find player index for customization."); + } + + nPlayerNumber = i; + + // Send resource to all other active players + for (i = 0, pHost = g_psvs.clients; i < g_psvs.maxclients; i++, pHost++) + { + if (!pHost->active && !pHost->spawned || pHost->fakeclient) + continue; + + if (pHost == pPlayer && bSkipPlayer) + continue; + + MSG_WriteByte(&pHost->netchan.message, svc_customization); + MSG_WriteByte(&pHost->netchan.message, nPlayerNumber); + MSG_WriteByte(&pHost->netchan.message, pResource->type); + MSG_WriteString(&pHost->netchan.message, pResource->szFileName); + MSG_WriteShort(&pHost->netchan.message, pResource->nIndex); + MSG_WriteLong(&pHost->netchan.message, pResource->nDownloadSize); + MSG_WriteByte(&pHost->netchan.message, pResource->ucFlags); + if (pResource->ucFlags & RES_CUSTOM) + { + SZ_Write(&pHost->netchan.message, pResource->rgucMD5_hash, 16); + } + } +} + +/* ../engine/sv_upld.c:241 */ +// Creates customizations list for the current player and sends resources to other players. +void SV_RegisterResources(void) +{ + resource_t *pResource; + client_t *pHost = host_client; + + pHost->uploading = FALSE; +#ifdef REHLDS_FIXES + SV_CreateCustomizationList(pHost); // FIXED: Call this function only once. It was crazy to call it for each resource available. + for (pResource = pHost->resourcesonhand.pNext; pResource != &pHost->resourcesonhand; pResource = pResource->pNext) + { + SV_Customization(pHost, pResource, TRUE); + } +#else // REHLDS_FIXES + for (pResource = pHost->resourcesonhand.pNext; pResource != &pHost->resourcesonhand; pResource = pResource->pNext) + { + SV_CreateCustomizationList(pHost); + SV_Customization(pHost, pResource, TRUE); + } +#endif // REHLDS_FIXES +} + +/* ../engine/sv_upld.c:276 */ +void SV_MoveToOnHandList(resource_t *pResource) +{ + if (!pResource) + { + Con_DPrintf("Null resource passed to SV_MoveToOnHandList\n"); + return; + } + + SV_RemoveFromResourceList(pResource); + SV_AddToResourceList(pResource, &host_client->resourcesonhand); +} + +/* ../engine/sv_upld.c:296 */ +void SV_AddToResourceList(resource_t *pResource, resource_t *pList) +{ + if (pResource->pPrev || pResource->pNext) + { + Con_Printf("Resource already linked\n"); + return; + } + + pResource->pPrev = pList->pPrev; + pResource->pNext = pList; + pList->pPrev->pNext = pResource; + pList->pPrev = pResource; +} + +/* ../engine/sv_upld.c:316 */ +void SV_ClearResourceList(resource_t *pList) +{ + resource_t *p, *n; + + p = pList->pNext; + while (p != NULL) + { + if (p == pList) + break; + + n = p->pNext; + SV_RemoveFromResourceList(p); + Mem_Free(p); + + p = n; + } + + pList->pPrev = pList; + pList->pNext = pList; +} + +/* ../engine/sv_upld.c:339 */ +void SV_RemoveFromResourceList(resource_t *pResource) +{ + pResource->pPrev->pNext = pResource->pNext; + pResource->pNext->pPrev = pResource->pPrev; + pResource->pPrev = NULL; + pResource->pNext = NULL; +} + +/* ../engine/sv_upld.c:355 */ +// For each t_decal and RES_CUSTOM resource the player had shown to us, tries to find it locally or count size required to be downloaded. +int SV_EstimateNeededResources(void) +{ + resource_t *p; + int missing; + int size = 0; + + for (p = host_client->resourcesneeded.pNext; p != &host_client->resourcesneeded; p = p->pNext) + { +#ifdef REHLDS_FIXES + if (p->type == t_decal && (p->ucFlags & RES_CUSTOM) && p->nDownloadSize > 0) // FIXED: We don't need to lookup if we can't or will not download anyway +#else // REHLDS_FIXES + if (p->type == t_decal) +#endif // REHLDS_FIXES + { + missing = !HPAK_ResourceForHash("custom.hpk", p->rgucMD5_hash, NULL); + if (missing) + { +#ifdef REHLDS_FIXES + // FIXED: Moved into outer scope +#else // REHLDS_FIXES + if (p->nDownloadSize) +#endif // REHLDS_FIXES + { + size += p->nDownloadSize; + p->ucFlags |= RES_WASMISSING; + } + } + } + } + + return size; +} + +/* ../engine/sv_upld.c:391 */ +// This is called each frame to do checks on players if they uploaded all files that where requested from them. +void SV_RequestMissingResourcesFromClients(void) +{ + host_client = g_psvs.clients; + for (int i = 0; i < g_psvs.maxclients; i++, host_client++) + { + if (!host_client->active && !host_client->spawned) + { + continue; + } + while (SV_RequestMissingResources()) + ; // Woot??! + } +} + +/* ../engine/sv_upld.c:406 */ +// Creates customizations list for a player (the current player actually, see the caller) and sends them out to other players when all needed resources are on-hands. Also sends other players customizations to the current player. +qboolean SV_UploadComplete(client_t *cl) +{ + if (cl->resourcesneeded.pNext == &cl->resourcesneeded) + { + // All resources are available locally, now we can do customizations propagation + SV_RegisterResources(); + SV_PropagateCustomizations(); + if (sv_allow_upload.value != 0.0f) + { + Con_DPrintf("Custom resource propagation complete.\n"); + } + cl->uploaddoneregistering = TRUE; + return TRUE; + } + return FALSE; +} + +/* ../engine/sv_upld.c:423 */ +// For each resource the player had shown to us, moves it to on-hands list. For t_decal and RES_CUSTOM it tries to find it locally or request resource from the player. +void SV_BatchUploadRequest(client_t *cl) +{ + resource_t *p, *n; + char filename[MAX_PATH]; + + p = cl->resourcesneeded.pNext; + while (p != &cl->resourcesneeded) + { + n = p->pNext; + + if ((p->ucFlags & RES_WASMISSING) == 0) + { + SV_MoveToOnHandList(p); + } + else if (p->type == t_decal) + { + if (p->ucFlags & RES_CUSTOM) + { + Q_snprintf(filename, sizeof(filename), "!MD5%s", MD5_Print(p->rgucMD5_hash)); + if (SV_CheckFile(&cl->netchan.message, filename)) + { + SV_MoveToOnHandList(p); + } + } + else + { + Con_Printf("Non customization in upload queue!\n"); + SV_MoveToOnHandList(p); + } + } + + p = n; + } +} + +/* ../engine/sv_upld.c:467 */ +// This is used to do recurring checks on the current player that he uploaded all resources that where needed. +qboolean SV_RequestMissingResources(void) +{ + if (host_client->uploading && !host_client->uploaddoneregistering) + { + SV_UploadComplete(host_client); + } + return FALSE; +} + +/* ../engine/sv_upld.c:491 */ +void SV_ParseResourceList(client_t *pSenderClient) +{ + int i, total; + int totalsize; + resource_t *resource; + resourceinfo_t ri; + + total = MSG_ReadShort(); + + SV_ClearResourceList(&host_client->resourcesneeded); + SV_ClearResourceList(&host_client->resourcesonhand); + + for (i = 0; i < total; i++) + { + resource = (resource_t *)Mem_ZeroMalloc(sizeof(resource_t)); + Q_strncpy(resource->szFileName, MSG_ReadString(), sizeof(resource->szFileName) - 1); + resource->szFileName[sizeof(resource->szFileName) - 1] = 0; + resource->type = (resourcetype_t)MSG_ReadByte(); + resource->nIndex = MSG_ReadShort(); + resource->nDownloadSize = MSG_ReadLong(); + resource->ucFlags = MSG_ReadByte() & (~RES_WASMISSING); + if (resource->ucFlags & RES_CUSTOM) + MSG_ReadBuf(16, resource->rgucMD5_hash); + resource->pNext = NULL; + resource->pPrev = NULL; + +#ifdef REHLDS_FIXES + SV_AddToResourceList(resource, &host_client->resourcesneeded); // FIXED: Mem leak. Add to list to free current resource in SV_ClearResourceList if something goes wrong. +#endif // REHLDS_FIXES + + if (msg_badread || resource->type > t_world || +#ifdef REHLDS_FIXES + resource->nDownloadSize <= 0 || // FIXED: Check that download size is valid +#endif // REHLDS_FIXES + resource->nDownloadSize > 1024 * 1024 * 1024) // FIXME: Are they gone crazy??! + { + SV_ClearResourceList(&host_client->resourcesneeded); + SV_ClearResourceList(&host_client->resourcesonhand); + return; + } + +#ifndef REHLDS_FIXES + SV_AddToResourceList(resource, &host_client->resourcesneeded); +#endif // REHLDS_FIXES + } + + if (sv_allow_upload.value != 0.0f) + { + Con_DPrintf("Verifying and uploading resources...\n"); + totalsize = COM_SizeofResourceList(&host_client->resourcesneeded, &ri); +#ifdef REHLDS_FIXES + if (totalsize > 0) +#else // REHLDS_FIXES + if (totalsize != 0) +#endif // REHLDS_FIXES + { + Con_DPrintf("Custom resources total %.2fK\n", total / 1024.0f); + if (ri.info[t_model].size) + { + total = ri.info[t_model].size; + Con_DPrintf(" Models: %.2fK\n", total / 1024.0f); + } + if (ri.info[t_sound].size) + { + total = ri.info[t_sound].size; + Con_DPrintf(" Sounds: %.2fK\n", total / 1024.0f); + } + if (ri.info[t_decal].size) + { + total = ri.info[t_decal].size; + Con_DPrintf(" Decals: %.2fK\n", total / 1024.0f); + } + if (ri.info[t_skin].size) + { + total = ri.info[t_skin].size; + Con_DPrintf(" Skins : %.2fK\n", total / 1024.0f); + } + if (ri.info[t_generic].size) + { + total = ri.info[t_generic].size; + Con_DPrintf(" Generic : %.2fK\n", total / 1024.0f); + } + if (ri.info[t_eventscript].size) + { + total = ri.info[t_eventscript].size; + Con_DPrintf(" Events : %.2fK\n", total / 1024.0f); + } + Con_DPrintf("----------------------\n"); + + int bytestodownload = SV_EstimateNeededResources(); + + if (bytestodownload > sv_max_upload.value * 1024 * 1024) + { + SV_ClearResourceList(&host_client->resourcesneeded); + SV_ClearResourceList(&host_client->resourcesonhand); + return; + } + + if (bytestodownload > 1024) + Con_DPrintf("Resources to request: %.2fK\n", bytestodownload / 1024.0f); + else + Con_DPrintf("Resources to request: %i bytes\n", bytestodownload); + } + } + + host_client->uploading = TRUE; + host_client->uploaddoneregistering = FALSE; + + SV_BatchUploadRequest(host_client); +} diff --git a/rehlds/engine/sv_upld.h b/rehlds/engine/sv_upld.h new file mode 100644 index 0000000..7436449 --- /dev/null +++ b/rehlds/engine/sv_upld.h @@ -0,0 +1,54 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SV_UPLD__H +#define SV_UPLD__H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + + +qboolean SV_CheckFile(sizebuf_t *msg, char *filename); +void SV_ClearResourceLists(client_t *cl); +void SV_CreateCustomizationList(client_t *pHost); +void SV_Customization(client_t *pPlayer, resource_t *pResource, qboolean bSkipPlayer); +void SV_RegisterResources(void); +void SV_MoveToOnHandList(resource_t *pResource); +void SV_AddToResourceList(resource_t *pResource, resource_t *pList); +void SV_ClearResourceList(resource_t *pList); +void SV_RemoveFromResourceList(resource_t *pResource); +int SV_EstimateNeededResources(void); +void SV_RequestMissingResourcesFromClients(void); +qboolean SV_UploadComplete(client_t *cl); +void SV_BatchUploadRequest(client_t *cl); +qboolean SV_RequestMissingResources(void); + void SV_ParseResourceList(client_t *pSenderClient); + +#endif // SV_UPLD__H diff --git a/rehlds/engine/sv_user.cpp b/rehlds/engine/sv_user.cpp new file mode 100644 index 0000000..be09f32 --- /dev/null +++ b/rehlds/engine/sv_user.cpp @@ -0,0 +1,1791 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +/* ../engine/sv_user.c:21 */ +typedef struct command_s +{ + char *command; +} command_t; + +sv_adjusted_positions_t truepositions[MAX_CLIENTS]; +qboolean g_balreadymoved; + +float s_LastFullUpdate[33]; + +//cvar_t sv_voicecodec; + +//cvar_t sv_voicequality; + +edict_t *sv_player; + +//int giSkip; +qboolean nofind; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +command_t clcommands[23] = { "status", "god", "notarget", "fly", "name", "noclip", "kill", "pause", "spawn", "new", "sendres", "dropclient", "kick", "ping", "dlfile", "nextdl", "setinfo", "showinfo", "sendents", "fullupdate", "setpause", "unpause", NULL }; + +cvar_t sv_edgefriction = { "edgefriction", "2", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_maxspeed = { "sv_maxspeed", "320", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_accelerate = { "sv_accelerate", "10", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_footsteps = { "mp_footsteps", "1", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_rollspeed = { "sv_rollspeed", "200", 0, 0.0f, NULL }; +cvar_t sv_rollangle = { "sv_rollangle", "2.0", 0, 0.0f, NULL }; +cvar_t sv_unlag = { "sv_unlag", "1", 0, 0.0f, NULL }; +cvar_t sv_maxunlag = { "sv_maxunlag", "0.5", 0, 0.0f, NULL }; +cvar_t sv_unlagpush = { "sv_unlagpush", "0.0", 0, 0.0f, NULL }; +cvar_t sv_unlagsamples = { "sv_unlagsamples", "1", 0, 0.0f, NULL }; +cvar_t mp_consistency = { "mp_consistency", "1", FCVAR_SERVER, 0.0f, NULL }; +cvar_t sv_voiceenable = { "sv_voiceenable", "1", FCVAR_SERVER | FCVAR_ARCHIVE, 0.0f, NULL }; + +clc_func_t sv_clcfuncs[] = { + { clc_bad, "clc_bad", NULL }, + { clc_nop, "clc_nop", NULL }, + { clc_move, "clc_move", &SV_ParseMove }, + { clc_stringcmd, "clc_stringcmd", &SV_ParseStringCommand }, + { clc_delta, "clc_delta", &SV_ParseDelta }, + { clc_resourcelist, "clc_resourcelist", &SV_ParseResourceList }, + { clc_tmove, "clc_tmove", NULL }, + { clc_fileconsistency, "clc_fileconsistency", &SV_ParseConsistencyResponse }, + { clc_voicedata, "clc_voicedata", &SV_ParseVoiceData }, + { clc_hltv, "clc_hltv", &SV_IgnoreHLTV }, + { clc_cvarvalue, "clc_cvarvalue", &SV_ParseCvarValue }, + { clc_cvarvalue2, "clc_cvarvalue2", &SV_ParseCvarValue2 }, + + { clc_endoflist, "End of List", NULL }, +}; + +#else //HOOK_ENGINE + +command_t clcommands[23]; + +cvar_t sv_edgefriction; +cvar_t sv_maxspeed; +cvar_t sv_accelerate; +cvar_t sv_footsteps; +cvar_t sv_rollspeed; +cvar_t sv_rollangle; +cvar_t sv_unlag; +cvar_t sv_maxunlag; +cvar_t sv_unlagpush; +cvar_t sv_unlagsamples; +cvar_t mp_consistency; +cvar_t sv_voiceenable; + +clc_func_t sv_clcfuncs[12]; + +#endif //HOOK_ENGINE + +/* ../engine/sv_user.c:94 */ +void SV_ParseConsistencyResponse(client_t *pSenderClient) +{ + vec3_t mins; + vec3_t maxs; + vec3_t cmins; + vec3_t cmaxs; + unsigned char nullbuffer[32]; + unsigned char resbuffer[32]; + + int length = 0; + int c = 0; + Q_memset(nullbuffer, 0, sizeof(nullbuffer)); + int value = MSG_ReadShort(); + COM_UnMunge(&net_message.data[msg_readcount], value, g_psvs.spawncount); + MSG_StartBitReading(&net_message); + + while (MSG_ReadBits(1)) + { + int idx = MSG_ReadBits(12); + if (idx < 0 || idx >= g_psv.num_resources) + { + c = -1; + break; + } + + resource_t *r = &g_psv.resourcelist[idx]; + if (!(g_psv.resourcelist[idx].ucFlags & RES_CHECKFILE)) + { + c = -1; + break; + } + + Q_memcpy(resbuffer, r->rguc_reserved, sizeof(resbuffer)); + if (!Q_memcmp(resbuffer, nullbuffer, sizeof(resbuffer))) + { + if (MSG_ReadBits(32) != *(uint32_t *)&r->rgucMD5_hash[0]) + c = idx + 1; + } + else + { + MSG_ReadBitData(cmins, 12); + MSG_ReadBitData(cmaxs, 12); + Q_memcpy(resbuffer, r->rguc_reserved, sizeof(resbuffer)); + COM_UnMunge(resbuffer, sizeof(resbuffer), g_psvs.spawncount); + FORCE_TYPE ft = (FORCE_TYPE)resbuffer[0]; + if (ft == force_model_samebounds) + { + Q_memcpy(mins, &resbuffer[1], 12); + Q_memcpy(maxs, &resbuffer[13], 12); + if (!VectorCompare(cmins, mins) || !VectorCompare(cmaxs, maxs)) + c = idx + 1; + } + else if (ft == force_model_specifybounds) + { + Q_memcpy(mins, &resbuffer[1], 12); + Q_memcpy(maxs, &resbuffer[13], 12); + for (int i = 0; i < 3; i++) + { + if (cmins[i] < mins[i] || cmaxs[i] > maxs[i]) + { + c = idx + 1; + break; + } + } + } + else if (ft == force_model_specifybounds_if_avail) + { + Q_memcpy(mins, &resbuffer[1], 12); + Q_memcpy(maxs, &resbuffer[13], 12); + if (cmins[0] != -1.0 || cmins[1] != -1.0 || cmins[2] != -1.0 || cmaxs[0] != -1.0 || cmaxs[1] != -1.0 || cmaxs[2] != -1.0) + { + for (int i = 0; i < 3; i++) + { + if (cmins[i] < mins[i] || cmaxs[i] > maxs[i]) + { + c = idx + 1; + break; + } + } + } + } + else + { + msg_badread = 1; + c = idx + 1; + break; + } + + } + + if (msg_badread) + break; + + ++length; + } + + MSG_EndBitReading(&net_message); + if (c < 0 || length != g_psv.num_consistency) + { + msg_badread = 1; + Con_Printf("SV_ParseConsistencyResponse: %s:%s sent bad file data\n", host_client->name, NET_AdrToString(host_client->netchan.remote_address)); + SV_DropClient(host_client, 0, "Bad file data"); + return; + } + + if (c > 0) + { + char dropmessage[256]; + if (gEntityInterface.pfnInconsistentFile(host_client->edict, g_psv.resourcelist[c - 1].szFileName, dropmessage)) + { + if (Q_strlen(dropmessage) > 0) + SV_ClientPrintf("%s", dropmessage); + SV_DropClient(host_client, 0, "Bad file %s", dropmessage); + } + return; + } + + host_client->has_force_unmodified = 0; +} + +/* ../engine/sv_user.c:267 */ +qboolean SV_FileInConsistencyList(const char *filename, consistency_t **ppconsist) +{ + for (int i = 0; i < 512; i++) + { + if (!g_psv.consistency_list[i].filename) + return 0; + + if (!Q_stricmp(filename, g_psv.consistency_list[i].filename)) + { + if (ppconsist) + *ppconsist = &g_psv.consistency_list[i]; + return 1; + } + } + + return 0; +} + +/* ../engine/sv_user.c:298 */ +int SV_TransferConsistencyInfo(void) +{ + consistency_t *pc; + + int c = 0; + for (int i = 0; i < g_psv.num_resources; i++) + { + resource_t *r = &g_psv.resourcelist[i]; + if (r->ucFlags == (RES_CUSTOM | RES_REQUESTED | RES_UNK_6) || (r->ucFlags & RES_CHECKFILE)) + continue; + + if (!SV_FileInConsistencyList(r->szFileName, &pc)) + continue; + + r->ucFlags |= RES_CHECKFILE; + + char filename[MAX_PATH]; + if (r->type != t_sound) + { + Q_strncpy(filename, r->szFileName, MAX_PATH - 1); + filename[MAX_PATH - 1] = 0; + } + else + { + _snprintf(filename, MAX_PATH, "sound/%s", r->szFileName); + } + MD5_Hash_File(r->rgucMD5_hash, filename, FALSE, FALSE, NULL); + + if (r->type == t_model) + { + if (pc->check_type <= 0 || pc->check_type > 3) + { + + } + if (pc->check_type == force_model_samebounds) + { + vec3_t mins; + vec3_t maxs; + + if (!R_GetStudioBounds(filename, mins, maxs)) + Host_Error("Server unable to get bounds for %s\n", filename); + + Q_memcpy(&r->rguc_reserved[1], mins, sizeof(mins)); + Q_memcpy(&r->rguc_reserved[13], maxs, sizeof(maxs)); + } + else if (pc->check_type == force_model_specifybounds || pc->check_type == force_model_specifybounds_if_avail) + { + Q_memcpy(&r->rguc_reserved[1], pc->mins, sizeof(pc->mins)); + Q_memcpy(&r->rguc_reserved[13], pc->maxs, sizeof(pc->maxs)); + } + else + { + ++c; + continue; + } + r->rguc_reserved[0] = pc->check_type; + COM_Munge(r->rguc_reserved, 32, g_psvs.spawncount); + } + ++c; + } + return c; +} + +/* ../engine/sv_user.c:374 */ +void SV_SendConsistencyList(sizebuf_t *msg) +{ + host_client->has_force_unmodified = FALSE; + + if (g_psvs.maxclients == 1 || mp_consistency.value == 0.0f || g_psv.num_consistency == 0 || host_client->proxy) + { + MSG_WriteBits(0, 1); + return; + } + + host_client->has_force_unmodified = TRUE; + + int delta = 0; + int lastcheck = 0; + resource_t *r = g_psv.resourcelist; + + MSG_WriteBits(1, 1); + + for (int i = 0; i < g_psv.num_resources; i++, r++) + { + if (r && (r->ucFlags & RES_CHECKFILE) != 0) + { + MSG_WriteBits(1, 1); + delta = i - lastcheck; + + if (delta > 31) + { + MSG_WriteBits(0, 1); + MSG_WriteBits(i, 10); // LIMIT: Here it write index, not a diff, with resolution of 10 bits. So, it limits not adjacent index to 1023 max. + } + else + { + // Write 5 bits index delta, so it is up to 31 + MSG_WriteBits(1, 1); + MSG_WriteBits(delta, 5); + } + + lastcheck = i; + } + } + + MSG_WriteBits(0, 1); +} + +/* ../engine/sv_user.c:439 */ +void SV_PreRunCmd(void) +{ +} + +/* ../engine/sv_user.c:450 */ +void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check) +{ + model_t *pModel; + + pe->origin[0] = check->v.origin[0]; + pe->origin[1] = check->v.origin[1]; + pe->info = e; + pe->origin[2] = check->v.origin[2]; + if (e < 1 || e > g_psvs.maxclients) + { + pe->player = 0; + } + else + { + SV_GetTrueOrigin(e - 1, pe->origin); + pe->player = pe->info; + } + + pe->angles[0] = check->v.angles[0]; + pe->angles[1] = check->v.angles[1]; + pe->angles[2] = check->v.angles[2]; + pe->studiomodel = 0; + pe->rendermode = check->v.rendermode; + if (check->v.solid == SOLID_BSP) + { + pe->model = g_psv.models[check->v.modelindex]; + Q_strncpy(pe->name, pe->model->name, 0x20u); + pe->name[31] = 0; + } + else if (check->v.solid == SOLID_NOT) + { + if (check->v.modelindex) + { + pe->model = g_psv.models[check->v.modelindex]; + Q_strncpy(pe->name, pe->model->name, 0x20u); + pe->name[31] = 0; + } + else + { + pe->model = 0; + } + } + else + { + pe->model = NULL; + if (check->v.solid != SOLID_BBOX) + { + pe->mins[0] = check->v.mins[0]; + pe->mins[1] = check->v.mins[1]; + pe->maxs[0] = check->v.maxs[0]; + pe->mins[2] = check->v.mins[2]; + pe->maxs[1] = check->v.maxs[1]; + pe->maxs[2] = check->v.maxs[2]; + if (check->v.classname) + { + Q_strncpy(pe->name, &pr_strings[check->v.classname], 0x20u); + pe->name[31] = 0; + } + else + { + sprintf(pe->name, "?"); + } + } + else + { + if (check->v.modelindex) + { + pModel = g_psv.models[check->v.modelindex]; + if (pModel) + { + if (pModel->flags & 0x200) + pe->studiomodel = pModel; + + Q_strncpy(pe->name, pModel->name, 0x20u); + pe->name[31] = 0; + } + } + pe->mins[0] = check->v.mins[0]; + pe->mins[1] = check->v.mins[1]; + pe->mins[2] = check->v.mins[2]; + pe->maxs[0] = check->v.maxs[0]; + pe->maxs[1] = check->v.maxs[1]; + pe->maxs[2] = check->v.maxs[2]; + } + } + pe->skin = check->v.skin; + pe->frame = check->v.frame; + pe->solid = check->v.solid; + pe->sequence = check->v.sequence; + Q_memcpy(pe->controller, check->v.controller, 4); + Q_memcpy(pe->blending, check->v.blending, 2); + pe->movetype = check->v.movetype; + pe->iuser1 = check->v.iuser1; + pe->iuser2 = check->v.iuser2; + pe->iuser3 = check->v.iuser3; + pe->iuser4 = check->v.iuser4; + pe->fuser1 = check->v.fuser1; + pe->fuser2 = check->v.fuser2; + pe->fuser3 = check->v.fuser3; + pe->fuser4 = check->v.fuser4; + pe->vuser1[0] = check->v.vuser1[0]; + pe->vuser1[1] = check->v.vuser1[1]; + pe->vuser1[2] = check->v.vuser1[2]; + pe->vuser2[0] = check->v.vuser2[0]; + pe->vuser2[1] = check->v.vuser2[1]; + pe->vuser2[2] = check->v.vuser2[2]; + pe->vuser3[0] = check->v.vuser3[0]; + pe->vuser3[1] = check->v.vuser3[1]; + pe->vuser3[2] = check->v.vuser3[2]; + pe->takedamage = 0; + pe->blooddecal = 0; + pe->vuser4[0] = check->v.vuser4[0]; + pe->vuser4[1] = check->v.vuser4[1]; + pe->vuser4[2] = check->v.vuser4[2]; +} + +/* ../engine/sv_user.c:579 */ +void SV_AddLinksToPM_(areanode_t *node, float *pmove_mins, float *pmove_maxs) +{ + struct link_s *l; + edict_t *check; + int e; + physent_t *ve; + int i; + link_t *next; + float *fmax; + float *fmin; + physent_t *pe; + + for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) + { + check = (edict_t *)&l[-1]; + next = l->next; + if (check->v.groupinfo) + { + if (g_groupop) + { + if (g_groupop == GROUP_OP_NAND && (check->v.groupinfo & sv_player->v.groupinfo)) + continue; + } + else + { + if (!(check->v.groupinfo & sv_player->v.groupinfo)) + continue; + } + } + + if (check->v.owner == sv_player) + continue; + + if (check->v.solid != SOLID_BSP && check->v.solid != SOLID_BBOX && check->v.solid != SOLID_SLIDEBOX && check->v.solid != SOLID_NOT) + continue; + + e = NUM_FOR_EDICT(check); + ve = &pmove->visents[pmove->numvisent]; + pmove->numvisent = pmove->numvisent + 1; + SV_CopyEdictToPhysent(ve, e, check); + + if ((check->v.solid == SOLID_NOT) && (!check->v.skin || !check->v.modelindex)) + continue; + + if ((check->v.flags & FL_MONSTERCLIP) && check->v.solid == SOLID_BSP) + continue; + + if (check == sv_player) + continue; + + if ((check->v.flags & FL_CLIENT) && check->v.health <= 0.0) + continue; + + if (check->v.mins[2] == 0.0 && check->v.maxs[2] == 1.0 || Length(check->v.size) == 0.0) + continue; + + fmin = check->v.absmin; + fmax = check->v.absmax; + if (check->v.flags & FL_CLIENT) + SV_GetTrueMinMax(e - 1, &fmin, &fmax); + + for (i = 0; i < 3; i++) + { + if (fmin[i] > pmove_maxs[i] || fmax[i] < pmove_mins[i]) + break; + } + + if (i != 3) + continue; + + if (check->v.solid || check->v.skin != -16) + { + if (pmove->numphysent >= MAX_PHYSENTS) + { + Con_DPrintf("SV_AddLinksToPM: pmove->numphysent >= MAX_PHYSENTS\n"); + return; + } + pe = &pmove->physents[pmove->numphysent++]; + } + else + { + if (pmove->nummoveent >= MAX_MOVEENTS) + { + Con_DPrintf("SV_AddLinksToPM: pmove->nummoveent >= MAX_MOVEENTS\n"); + continue; + } + pe = &pmove->moveents[pmove->nummoveent++]; + } + + memcpy(pe, ve, sizeof(physent_t)); + } + + if (node->axis != -1) + { + if (pmove_maxs[node->axis] > node->dist) + SV_AddLinksToPM_(node->children[0], pmove_mins, pmove_maxs); + + if (pmove_mins[node->axis] < node->dist) + SV_AddLinksToPM_(node->children[1], pmove_mins, pmove_maxs); + } +} + +/* ../engine/sv_user.c:712 */ +void SV_AddLinksToPM(areanode_t *node, vec_t *origin) +{ + vec3_t pmove_mins; + vec3_t pmove_maxs; + + Q_memset(&pmove->physents[0], 0, sizeof(physent_t)); + Q_memset(&pmove->visents[0], 0, sizeof(physent_t)); + + pmove->physents[0].model = g_psv.worldmodel; + if (g_psv.worldmodel != NULL) + { + Q_strncpy(pmove->physents[0].name, g_psv.worldmodel->name, 0x20u); + pmove->physents[0].name[31] = 0; + } + pmove->physents[0].origin[0] = vec3_origin[0]; + pmove->physents[0].origin[1] = vec3_origin[1]; + pmove->physents[0].origin[2] = vec3_origin[2]; + pmove->physents[0].info = 0; + pmove->physents[0].solid = 4; + pmove->physents[0].movetype = 0; + pmove->physents[0].takedamage = 1; + pmove->physents[0].blooddecal = 0; + pmove->numphysent = 1; + pmove->numvisent = 1; + pmove->visents[0] = pmove->physents[0]; + pmove->nummoveent = 0; + for (int i = 0; i < 3; i++) + { + pmove_mins[i] = origin[i] - 256.0f; + pmove_maxs[i] = origin[i] + 256.0f; + } + SV_AddLinksToPM_(node, pmove_mins, pmove_maxs); +} + +/* ../engine/sv_user.c:758 */ +void SV_PlayerRunPreThink(edict_t *player, float time) +{ + gGlobalVariables.time = time; + gEntityInterface.pfnPlayerPreThink(player); +} + +/* ../engine/sv_user.c:774 */ +qboolean SV_PlayerRunThink(edict_t *ent, float frametime, double clienttimebase) +{ + float thinktime; + + if (!(ent->v.flags & (FL_DORMANT | FL_KILLME))) + { + thinktime = ent->v.nextthink; + if (thinktime <= 0.0 || frametime + clienttimebase < thinktime) + return 1; + + if (thinktime < clienttimebase) + thinktime = (float)clienttimebase; + + ent->v.nextthink = 0; + gGlobalVariables.time = thinktime; + gEntityInterface.pfnThink(ent); + } + + if (ent->v.flags & FL_KILLME) + ED_Free(ent); + + return ent->free == 0; +} + +/* ../engine/sv_user.c:814 */ +void SV_CheckMovingGround(edict_t *player, float frametime) +{ + edict_t *groundentity; + + if (player->v.flags & FL_ONGROUND) + { + groundentity = player->v.groundentity; + if (groundentity) + { + if (groundentity->v.flags & FL_CONVEYOR) + { + if (player->v.flags & FL_BASEVELOCITY) + VectorMA(player->v.basevelocity, groundentity->v.speed, groundentity->v.movedir, player->v.basevelocity); + else + VectorScale(groundentity->v.movedir, groundentity->v.speed, player->v.basevelocity); + player->v.flags |= FL_BASEVELOCITY; + } + } + } + + if (!(player->v.flags & FL_BASEVELOCITY)) + { + VectorMA(player->v.velocity, frametime * 0.5f + 1.0f, player->v.basevelocity, player->v.velocity); + player->v.basevelocity[0] = 0; + player->v.basevelocity[1] = 0; + player->v.basevelocity[2] = 0; + } + + player->v.flags &= ~FL_BASEVELOCITY; +} + +/* ../engine/sv_user.c:852 */ +void SV_ConvertPMTrace(trace_t *dest, pmtrace_t *src, edict_t *ent) +{ + dest->allsolid = src->allsolid; + dest->startsolid = src->startsolid; + dest->inopen = src->inopen; + dest->inwater = src->inwater; + dest->fraction = src->fraction; + dest->endpos[0] = src->endpos[0]; + dest->endpos[1] = src->endpos[1]; + dest->endpos[2] = src->endpos[2]; + dest->plane.normal[0] = src->plane.normal[0]; + dest->plane.normal[1] = src->plane.normal[1]; + dest->plane.normal[2] = src->plane.normal[2]; + dest->plane.dist = src->plane.dist; + dest->hitgroup = src->hitgroup; + dest->ent = ent; +} + +/* ../engine/sv_user.c:873 */ +void SV_ForceFullClientsUpdate(void) +{ + byte data[9216]; + sizebuf_t msg; + + Q_memset(&msg, 0, sizeof(msg)); + msg.buffername = "Force Update"; + msg.data = data; + msg.cursize = 0; + msg.maxsize = sizeof(data); + + for (int i = 0; i < g_psvs.maxclients; ++i) + { + client_t * client = &g_psvs.clients[i]; + if (client == host_client || client->active || client->connected || client->spawned) + SV_FullClientUpdate(client, &msg); + } + + Con_DPrintf("Client %s started recording. Send full update.\n", host_client->name); + Netchan_CreateFragments(1, &host_client->netchan, &msg); + Netchan_FragSend(&host_client->netchan); +} + +/* ../engine/sv_user.c:918 */ +void SV_RunCmd(usercmd_t *ucmd, int random_seed) +{ + usercmd_t cmd = *ucmd; + int i; + edict_t *ent; + trace_t trace; + float frametime; + + if (host_client->ignorecmdtime > realtime) + { + host_client->cmdtime = (double)ucmd->msec / 1000.0 + host_client->cmdtime; + return; + } + + + host_client->ignorecmdtime = 0; + if (cmd.msec > 50) + { + cmd.msec = (byte)(ucmd->msec / 2.0); + SV_RunCmd(&cmd, random_seed); + cmd.msec = (byte)(ucmd->msec / 2.0); + cmd.impulse = 0; + SV_RunCmd(&cmd, random_seed); + return; + } + + + if (!host_client->fakeclient) + SV_SetupMove(host_client); + + gEntityInterface.pfnCmdStart(sv_player, ucmd, random_seed); + frametime = float(ucmd->msec * 0.001); + host_client->svtimebase = frametime + host_client->svtimebase; + host_client->cmdtime = ucmd->msec / 1000.0 + host_client->cmdtime; + if (ucmd->impulse) + { + sv_player->v.impulse = ucmd->impulse; + + // Disable fullupdate via impulse 204 +#ifndef REHLDS_FIXES + if (ucmd->impulse == 204) + SV_ForceFullClientsUpdate(); +#endif // REHLDS_FIXES + } + sv_player->v.clbasevelocity[0] = 0; + sv_player->v.clbasevelocity[1] = 0; + sv_player->v.clbasevelocity[2] = 0; + sv_player->v.button = ucmd->buttons; + SV_CheckMovingGround(sv_player, frametime); + pmove->oldangles[0] = sv_player->v.v_angle[0]; + pmove->oldangles[1] = sv_player->v.v_angle[1]; + pmove->oldangles[2] = sv_player->v.v_angle[2]; + if (!sv_player->v.fixangle) + { + sv_player->v.v_angle[0] = ucmd->viewangles[0]; + sv_player->v.v_angle[1] = ucmd->viewangles[1]; + sv_player->v.v_angle[2] = ucmd->viewangles[2]; + } + SV_PlayerRunPreThink(sv_player, (float)host_client->svtimebase); + SV_PlayerRunThink(sv_player, frametime, host_client->svtimebase); + if (Length(sv_player->v.basevelocity) > 0.0) + { + sv_player->v.clbasevelocity[0] = sv_player->v.basevelocity[0]; + sv_player->v.clbasevelocity[1] = sv_player->v.basevelocity[1]; + sv_player->v.clbasevelocity[2] = sv_player->v.basevelocity[2]; + } + pmove->server = 1; + pmove->multiplayer = (qboolean)(g_psvs.maxclients > 1); + pmove->time = float(1000.0 * host_client->svtimebase); + pmove->usehull = (sv_player->v.flags & 0x4000) != 0; + pmove->maxspeed = sv_maxspeed.value; + pmove->clientmaxspeed = sv_player->v.maxspeed; + pmove->flDuckTime = (float) sv_player->v.flDuckTime; + pmove->bInDuck = sv_player->v.bInDuck; + pmove->flTimeStepSound = sv_player->v.flTimeStepSound; + pmove->iStepLeft = sv_player->v.iStepLeft; + pmove->flFallVelocity = sv_player->v.flFallVelocity; + pmove->flSwimTime = (float)sv_player->v.flSwimTime; + pmove->oldbuttons = sv_player->v.oldbuttons; + Q_strncpy(pmove->physinfo, host_client->physinfo, 0xFFu); + pmove->physinfo[255] = 0; + pmove->velocity[0] = sv_player->v.velocity[0]; + pmove->velocity[1] = sv_player->v.velocity[1]; + pmove->velocity[2] = sv_player->v.velocity[2]; + pmove->movedir[0] = sv_player->v.movedir[0]; + pmove->movedir[1] = sv_player->v.movedir[1]; + pmove->movedir[2] = sv_player->v.movedir[2]; + pmove->angles[0] = sv_player->v.v_angle[0]; + pmove->angles[1] = sv_player->v.v_angle[1]; + pmove->angles[2] = sv_player->v.v_angle[2]; + pmove->basevelocity[0] = sv_player->v.basevelocity[0]; + pmove->basevelocity[1] = sv_player->v.basevelocity[1]; + pmove->basevelocity[2] = sv_player->v.basevelocity[2]; + pmove->view_ofs[0] = sv_player->v.view_ofs[0]; + pmove->view_ofs[1] = sv_player->v.view_ofs[1]; + pmove->view_ofs[2] = sv_player->v.view_ofs[2]; + pmove->punchangle[0] = sv_player->v.punchangle[0]; + pmove->punchangle[1] = sv_player->v.punchangle[1]; + pmove->punchangle[2] = sv_player->v.punchangle[2]; + pmove->deadflag = sv_player->v.deadflag; + pmove->effects = sv_player->v.effects; + pmove->gravity = sv_player->v.gravity; + pmove->friction = sv_player->v.friction; + pmove->spectator = 0; + pmove->waterjumptime = sv_player->v.teleport_time; + memcpy(&pmove->cmd, &cmd, sizeof(pmove->cmd)); + pmove->dead = sv_player->v.health <= 0.0; + pmove->movetype = sv_player->v.movetype; + pmove->flags = sv_player->v.flags; + pmove->player_index = NUM_FOR_EDICT(sv_player) - 1; + pmove->iuser1 = sv_player->v.iuser1; + pmove->iuser2 = sv_player->v.iuser2; + pmove->iuser3 = sv_player->v.iuser3; + pmove->iuser4 = sv_player->v.iuser4; + pmove->fuser1 = sv_player->v.fuser1; + pmove->fuser2 = sv_player->v.fuser2; + pmove->fuser3 = sv_player->v.fuser3; + pmove->fuser4 = sv_player->v.fuser4; + pmove->vuser1[0] = sv_player->v.vuser1[0]; + pmove->vuser1[1] = sv_player->v.vuser1[1]; + pmove->vuser1[2] = sv_player->v.vuser1[2]; + pmove->vuser2[0] = sv_player->v.vuser2[0]; + pmove->vuser2[1] = sv_player->v.vuser2[1]; + pmove->vuser2[2] = sv_player->v.vuser2[2]; + pmove->vuser3[0] = sv_player->v.vuser3[0]; + pmove->vuser3[1] = sv_player->v.vuser3[1]; + pmove->vuser3[2] = sv_player->v.vuser3[2]; + pmove->vuser4[0] = sv_player->v.vuser4[0]; + pmove->vuser4[1] = sv_player->v.vuser4[1]; + pmove->vuser4[2] = sv_player->v.vuser4[2]; + pmove->origin[0] = sv_player->v.origin[0]; + pmove->origin[1] = sv_player->v.origin[1]; + pmove->origin[2] = sv_player->v.origin[2]; + SV_AddLinksToPM(sv_areanodes, pmove->origin); + pmove->frametime = frametime; + pmove->runfuncs = 1; + pmove->PM_PlaySound = PM_SV_PlaySound; + pmove->PM_TraceTexture = PM_SV_TraceTexture; + pmove->PM_PlaybackEventFull = PM_SV_PlaybackEventFull; + gEntityInterface.pfnPM_Move(pmove, 1); + sv_player->v.deadflag = pmove->deadflag; + sv_player->v.effects = pmove->effects; + sv_player->v.teleport_time = pmove->waterjumptime; + sv_player->v.waterlevel = pmove->waterlevel; + sv_player->v.watertype = pmove->watertype; + sv_player->v.flags = pmove->flags; + sv_player->v.friction = pmove->friction; + sv_player->v.movetype = pmove->movetype; + sv_player->v.maxspeed = pmove->clientmaxspeed; + sv_player->v.iStepLeft = pmove->iStepLeft; + sv_player->v.view_ofs[0] = pmove->view_ofs[0]; + sv_player->v.view_ofs[1] = pmove->view_ofs[1]; + sv_player->v.view_ofs[2] = pmove->view_ofs[2]; + sv_player->v.movedir[0] = pmove->movedir[0]; + sv_player->v.movedir[1] = pmove->movedir[1]; + sv_player->v.movedir[2] = pmove->movedir[2]; + sv_player->v.punchangle[0] = pmove->punchangle[0]; + sv_player->v.punchangle[1] = pmove->punchangle[1]; + sv_player->v.punchangle[2] = pmove->punchangle[2]; + if (pmove->onground == -1) + { + sv_player->v.flags &= ~FL_ONGROUND; + } + else + { + sv_player->v.flags |= FL_ONGROUND; + sv_player->v.groundentity = EDICT_NUM(pmove->physents[pmove->onground].info); + } + sv_player->v.origin[0] = pmove->origin[0]; + sv_player->v.origin[1] = pmove->origin[1]; + sv_player->v.origin[2] = pmove->origin[2]; + sv_player->v.velocity[0] = pmove->velocity[0]; + sv_player->v.velocity[1] = pmove->velocity[1]; + sv_player->v.velocity[2] = pmove->velocity[2]; + sv_player->v.basevelocity[0] = pmove->basevelocity[0]; + sv_player->v.basevelocity[1] = pmove->basevelocity[1]; + sv_player->v.basevelocity[2] = pmove->basevelocity[2]; + if (!sv_player->v.fixangle) + { + sv_player->v.v_angle[0] = pmove->angles[0]; + sv_player->v.v_angle[1] = pmove->angles[1]; + sv_player->v.v_angle[2] = pmove->angles[2]; + sv_player->v.angles[0] = pmove->angles[0]; + sv_player->v.angles[1] = pmove->angles[1]; + sv_player->v.angles[2] = pmove->angles[2]; + sv_player->v.angles[0] = float(-pmove->angles[0] / 3.0); + } + sv_player->v.bInDuck = pmove->bInDuck; + sv_player->v.flDuckTime = (int)pmove->flDuckTime; + sv_player->v.flTimeStepSound = pmove->flTimeStepSound; + sv_player->v.flFallVelocity = pmove->flFallVelocity; + sv_player->v.flSwimTime = (int)pmove->flSwimTime; + sv_player->v.oldbuttons = pmove->cmd.buttons; + sv_player->v.iuser1 = pmove->iuser1; + sv_player->v.iuser2 = pmove->iuser2; + sv_player->v.iuser3 = pmove->iuser3; + sv_player->v.iuser4 = pmove->iuser4; + sv_player->v.fuser1 = pmove->fuser1; + sv_player->v.fuser2 = pmove->fuser2; + sv_player->v.fuser3 = pmove->fuser3; + sv_player->v.fuser4 = pmove->fuser4; + sv_player->v.vuser1[0] = pmove->vuser1[0]; + sv_player->v.vuser1[1] = pmove->vuser1[1]; + sv_player->v.vuser1[2] = pmove->vuser1[2]; + sv_player->v.vuser2[0] = pmove->vuser2[0]; + sv_player->v.vuser2[1] = pmove->vuser2[1]; + sv_player->v.vuser2[2] = pmove->vuser2[2]; + sv_player->v.vuser3[0] = pmove->vuser3[0]; + sv_player->v.vuser3[1] = pmove->vuser3[1]; + sv_player->v.vuser3[2] = pmove->vuser3[2]; + sv_player->v.vuser4[0] = pmove->vuser4[0]; + sv_player->v.vuser4[1] = pmove->vuser4[1]; + sv_player->v.vuser4[2] = pmove->vuser4[2]; + SetMinMaxSize(sv_player, player_mins[pmove->usehull], player_maxs[pmove->usehull], 0); + if (host_client->edict->v.solid) + { + SV_LinkEdict(sv_player, 1); + vec3_t vel; + + vel[0] = sv_player->v.velocity[0]; + vel[1] = sv_player->v.velocity[1]; + vel[2] = sv_player->v.velocity[2]; + for (i = 0; i < pmove->numtouch; ++i) + { + pmtrace_t *tr = &pmove->touchindex[i]; + ent = EDICT_NUM(pmove->physents[tr->ent].info); + SV_ConvertPMTrace(&trace, tr, ent); + sv_player->v.velocity[0] = tr->deltavelocity[0]; + sv_player->v.velocity[1] = tr->deltavelocity[1]; + sv_player->v.velocity[2] = tr->deltavelocity[2]; + SV_Impact(ent, sv_player, &trace); + } + sv_player->v.velocity[0] = vel[0]; + sv_player->v.velocity[1] = vel[1]; + sv_player->v.velocity[2] = vel[2]; + } + gGlobalVariables.time = (float)host_client->svtimebase; + gGlobalVariables.frametime = frametime; + gEntityInterface.pfnPlayerPostThink(sv_player); + gEntityInterface.pfnCmdEnd(sv_player); + + if (!host_client->fakeclient) + SV_RestoreMove(host_client); + + +} + +/* ../engine/sv_user.c:1197 */ +int SV_ValidateClientCommand(char *pszCommand) +{ + char *p; + int i = 0; + + COM_Parse(pszCommand); + while ((p = clcommands[i].command) != NULL) + { + if (!Q_stricmp(com_token, p)) + { + return 1; + } + i++; + } + return 0; +} + +/* ../engine/sv_user.c:1226 */ +float SV_CalcClientTime(client_t *cl) +{ + float minping; + float maxping; + int backtrack; + + float ping = 0.0; + int count = 0; + backtrack = (int)sv_unlagsamples.value; + + if (backtrack < 1) + backtrack = 1; + + if (backtrack >= (SV_UPDATE_BACKUP <= 16 ? SV_UPDATE_BACKUP : 16)) + backtrack = (SV_UPDATE_BACKUP <= 16 ? SV_UPDATE_BACKUP : 16); + + if (backtrack <= 0) + return 0.0f; + + for (int i = 0; i < backtrack; i++) + { + client_frame_t *frame = &cl->frames[SV_UPDATE_MASK & (cl->netchan.incoming_acknowledged - i)]; + if (frame->ping_time <= 0.0f) + continue; + + ++count; + ping += frame->ping_time; + } + + if (!count) + return 0.0f; + + minping = 9999.0; + maxping = -9999.0; + ping /= count; + + for (int i = 0; i < (SV_UPDATE_BACKUP <= 4 ? SV_UPDATE_BACKUP : 4); i++) + { + client_frame_t *frame = &cl->frames[SV_UPDATE_MASK & (cl->netchan.incoming_acknowledged - i)]; + if (frame->ping_time <= 0.0f) + continue; + + if (frame->ping_time < minping) + minping = frame->ping_time; + + if (frame->ping_time > maxping) + maxping = frame->ping_time; + } + + if (maxping < minping || fabs(maxping - minping) <= 0.2) + return ping; + + return 0.0f; +} + +/* ../engine/sv_user.c:1297 */ +void SV_ComputeLatency(client_t *cl) +{ + cl->latency = SV_CalcClientTime(cl); +} + +/* ../engine/sv_user.c:1339 */ +int SV_UnlagCheckTeleport(vec_t *v1, vec_t *v2) +{ + for (int i = 0; i < 3; i++) + { + if (fabs(v1[i] - v2[i]) > 128) + return 1; + } + + return 0; +} + +/* ../engine/sv_user.c:1361 */ +void SV_GetTrueOrigin(int player, vec_t *origin) +{ + if (!host_client->lw || !host_client->lc) + return; + + if (sv_unlag.value == 0 || g_psvs.maxclients <= 1 || !host_client->active) + return; + + if (player < 0 || player >= g_psvs.maxclients) + return; + + + if (truepositions[player].active && truepositions[player].needrelink) + { + origin[0] = truepositions[player].oldorg[0]; + origin[1] = truepositions[player].oldorg[1]; + origin[2] = truepositions[player].oldorg[2]; + } +} + +/* ../engine/sv_user.c:1383 */ +void SV_GetTrueMinMax(int player, float **fmin, float **fmax) +{ + if (!host_client->lw || !host_client->lc) + return; + + if (sv_unlag.value == 0.0f || g_psvs.maxclients <= 1) + return; + + if (!host_client->active || player < 0 || player >= g_psvs.maxclients) + return; + + if (truepositions[player].active && truepositions[player].needrelink) + { + *fmin = truepositions[player].oldabsmin; + *fmax = truepositions[player].oldabsmax; + } + +} + +/* ../engine/sv_user.c:1406 */ +entity_state_t *SV_FindEntInPack(int index, packet_entities_t *pack) +{ + if (pack->num_entities <= 0) + return NULL; + + for (int i = 0; i < pack->num_entities; i++) + { + if (pack->entities[i].number == index) + return &pack->entities[i]; + } + + return NULL; +} + +/* ../engine/sv_user.c:1426 */ +void SV_SetupMove(client_t *_host_client) +{ + struct client_s *cl; + float cl_interptime; + client_frame_t *nextFrame; + entity_state_t *state; + sv_adjusted_positions_t *pos; + float frac; + entity_state_t *pnextstate; + int i; + client_frame_t *frame; + vec3_t origin; + vec3_t delta; + + +#ifdef REHLDS_FIXES + double targettime; //FP precision fix +#else + float targettime; +#endif // REHLDS_FIXES + + Q_memset(truepositions, 0, sizeof(truepositions)); + nofind = 1; + if (!gEntityInterface.pfnAllowLagCompensation()) + return; + + if (sv_unlag.value == 0.0f || !_host_client->lw || !_host_client->lc) + return; + + if (g_psvs.maxclients <= 1 || !_host_client->active) + return; + + nofind = 0; + for (int i = 0; i < g_psvs.maxclients; i++) + { + cl = &g_psvs.clients[i]; + if (cl == _host_client || !cl->active) + continue; + + truepositions[i].oldorg[0] = cl->edict->v.origin[0]; + truepositions[i].oldorg[1] = cl->edict->v.origin[1]; + truepositions[i].oldorg[2] = cl->edict->v.origin[2]; + truepositions[i].oldabsmin[0] = cl->edict->v.absmin[0]; + truepositions[i].oldabsmin[1] = cl->edict->v.absmin[1]; + truepositions[i].oldabsmin[2] = cl->edict->v.absmin[2]; + truepositions[i].oldabsmax[0] = cl->edict->v.absmax[0]; + truepositions[i].oldabsmax[1] = cl->edict->v.absmax[1]; + truepositions[i].active = 1; + truepositions[i].oldabsmax[2] = cl->edict->v.absmax[2]; + } + + float clientLatency = _host_client->latency; + if (clientLatency > 1.5) + clientLatency = 1.5f; + + if (sv_maxunlag.value != 0.0f) + { + if (sv_maxunlag.value < 0.0) + Cvar_SetValue("sv_maxunlag", 0.0); + + if (clientLatency >= sv_maxunlag.value) + clientLatency = sv_maxunlag.value; + } + + cl_interptime = _host_client->lastcmd.lerp_msec / 1000.0f; + + if (cl_interptime > 0.1) + cl_interptime = 0.1f; + + if (_host_client->next_messageinterval > cl_interptime) + cl_interptime = (float) _host_client->next_messageinterval; + +#ifdef REHLDS_FIXES + // FP Precision fix (targettime is double there, not float) + targettime = realtime - clientLatency - cl_interptime + sv_unlagpush.value; + if (targettime > realtime) + targettime = realtime; +#else + targettime = float(realtime - clientLatency - cl_interptime + sv_unlagpush.value); + if (targettime > realtime) + targettime = float(realtime); +#endif // REHLDS_FIXES + + if (SV_UPDATE_BACKUP <= 0) + { + Q_memset(truepositions, 0, sizeof(truepositions)); + nofind = 1; + return; + } + + frame = nextFrame = NULL; + for (i = 0; i < SV_UPDATE_BACKUP; i++, frame = nextFrame) + { + nextFrame = &_host_client->frames[SV_UPDATE_MASK & (_host_client->netchan.outgoing_sequence + ~i)]; + for (int j = 0; j < nextFrame->entities.num_entities; j++) + { + state = &nextFrame->entities.entities[j]; + if (state->number <= 0 || state->number > g_psvs.maxclients) + continue; + + pos = &truepositions[state->number - 1]; + if (pos->deadflag) + continue; + + + if (state->health <= 0) + pos->deadflag = 1; + + if (state->effects & EF_NOINTERP) + pos->deadflag = 1; + + if (pos->temp_org_setflag) + { + if (SV_UnlagCheckTeleport(state->origin, pos->temp_org)) + pos->deadflag = 1; + } + else + { + pos->temp_org_setflag = 1; + } + + pos->temp_org[0] = state->origin[0]; + pos->temp_org[1] = state->origin[1]; + pos->temp_org[2] = state->origin[2]; + } + + if (targettime > nextFrame->senttime) + break; + } + + if ( i >= SV_UPDATE_BACKUP || targettime - nextFrame->senttime > 1.0) + { + Q_memset(truepositions, 0, 0xB00u); + nofind = 1; + return; + } + + if (frame) + { + float timeDiff = float(frame->senttime - nextFrame->senttime); + if (timeDiff == 0.0) + frac = 0.0; + else + { + frac = float((targettime - nextFrame->senttime) / timeDiff); + if (frac <= 1.0) + { + if (frac < 0.0) + frac = 0.0; + } + else + frac = 1.0; + } + } + else + { + frame = nextFrame; + frac = 0.0; + } + + for (i = 0; i < nextFrame->entities.num_entities; i++) + { + state = &nextFrame->entities.entities[i]; + if (state->number <= 0 || state->number > g_psvs.maxclients) + continue; + + cl = &g_psvs.clients[state->number - 1]; + if (cl == _host_client || !cl->active) + continue; + + pos = &truepositions[state->number - 1]; + if (pos->deadflag) + continue; + + if (!pos->active) + { + Con_DPrintf("tried to store off position of bogus player %i/%s\n", i, cl->name); + continue; + } + + pnextstate = SV_FindEntInPack(state->number, &frame->entities); + + if (pnextstate) + { + delta[0] = pnextstate->origin[0] - state->origin[0]; + delta[1] = pnextstate->origin[1] - state->origin[1]; + delta[2] = pnextstate->origin[2] - state->origin[2]; + VectorMA(state->origin, frac, delta, origin); + } + else + { + origin[0] = state->origin[0]; + origin[1] = state->origin[1]; + origin[2] = state->origin[2]; + } + pos->neworg[0] = origin[0]; + pos->neworg[1] = origin[1]; + pos->neworg[2] = origin[2]; + pos->initial_correction_org[0] = origin[0]; + pos->initial_correction_org[1] = origin[1]; + pos->initial_correction_org[2] = origin[2]; + if (!VectorCompare(origin, cl->edict->v.origin)) + { + cl->edict->v.origin[0] = origin[0]; + cl->edict->v.origin[1] = origin[1]; + cl->edict->v.origin[2] = origin[2]; + SV_LinkEdict(cl->edict, 0); + pos->needrelink = 1; + } + } +} + +/* ../engine/sv_user.c:1670 */ +void SV_RestoreMove(client_t *_host_client) +{ + sv_adjusted_positions_t *pos; + client_t *cli; + + if (nofind) + { + nofind = 0; + return; + } + + if (!gEntityInterface.pfnAllowLagCompensation()) + return; + + if (g_psvs.maxclients <= 1 || sv_unlag.value == 0.0) + return; + + if (!_host_client->lw || !_host_client->lc || !_host_client->active) + return; + + for (int i = 0; i < g_psvs.maxclients; i++) + { + cli = &g_psvs.clients[i]; + pos = &truepositions[i]; + + if (cli == _host_client ||! cli->active) + continue; + + if (VectorCompare(pos->neworg, pos->oldorg) || !pos->needrelink) + continue; + + if (!pos->active) + { + Con_DPrintf("SV_RestoreMove: Tried to restore 'inactive' player %i/%s\n", i, &cli->name[4]); + continue; + } + + if (VectorCompare(pos->initial_correction_org, cli->edict->v.origin)) + { + cli->edict->v.origin[0] = pos->oldorg[0]; + cli->edict->v.origin[1] = pos->oldorg[1]; + cli->edict->v.origin[2] = pos->oldorg[2]; + SV_LinkEdict(cli->edict, 0); + } + } +} + +/* ../engine/sv_user.c:1736 */ +void SV_ParseStringCommand(client_t *pSenderClient) +{ + char *s = MSG_ReadString(); + int ret = SV_ValidateClientCommand(s); + switch (ret) + { + case 0: + if (Q_strlen(s) > 127) + { + s[127] = 0; + } + Cmd_TokenizeString(s); + gEntityInterface.pfnClientCommand(sv_player); + break; + case 1: + Cmd_ExecuteString(s, src_client); + break; + case 2: // TODO: Check not used path + Cbuf_InsertText(s); + break; + } +} + +/* ../engine/sv_user.c:1777 */ +void SV_ParseDelta(client_t *pSenderClient) +{ + host_client->delta_sequence = MSG_ReadByte(); +} + +/* ../engine/sv_user.c:1790 */ +void SV_EstablishTimeBase(client_t *cl, usercmd_t *cmds, int dropped, int numbackup, int numcmds) +{ + int cmdnum; + double runcmd_time; + + runcmd_time = 0.0; + cmdnum = dropped; + if (dropped < 24) + { + if (dropped > numbackup) + { + cmdnum = dropped - (dropped - numbackup); + runcmd_time = (double)cl->lastcmd.msec * (dropped - numbackup) / 1000.0; + } + + for (; cmdnum > 0; cmdnum--) + { + runcmd_time += cmds[cmdnum - 1 + numcmds].msec / 1000.0; + } + } + + for (; numcmds > 0; numcmds--) + { + runcmd_time += cmds[numcmds - 1].msec / 1000.0; + } + + cl->svtimebase = host_frametime + g_psv.time - runcmd_time; +} + +/* ../engine/sv_user.c:1835 */ +void SV_ParseMove(client_t *pSenderClient) +{ + client_frame_t *frame; + int placeholder; + int mlen; + unsigned int packetLossByte; + int numcmds; + int totalcmds; + byte cbpktchecksum; + usercmd_t *cmd; + usercmd_t cmds[64]; + usercmd_t cmdNull; + float packet_loss; + byte cbchecksum; + int numbackup; + + if (g_balreadymoved) + { + msg_badread = 1; + return; + } + g_balreadymoved = 1; + + frame = &host_client->frames[SV_UPDATE_MASK & host_client->netchan.incoming_acknowledged]; + Q_memset(&cmdNull, 0, sizeof(cmdNull)); + + placeholder = msg_readcount + 1; + mlen = MSG_ReadByte(); + cbchecksum = MSG_ReadByte(); + COM_UnMunge(&net_message.data[placeholder + 1], mlen, host_client->netchan.incoming_sequence); + + packetLossByte = MSG_ReadByte(); + numbackup = MSG_ReadByte(); + numcmds = MSG_ReadByte(); + + packet_loss = float(packetLossByte & 0x7F); + pSenderClient->m_bLoopback = (packetLossByte >> 7) & 1; + totalcmds = numcmds + numbackup; + net_drop += 1 - numcmds; + if (totalcmds < 0 || totalcmds >= 63) + { + Con_Printf("SV_ReadClientMessage: too many cmds %i sent for %s/%s\n", totalcmds, host_client->name, NET_AdrToString(host_client->netchan.remote_address)); + SV_DropClient(host_client, 0, "CMD_MAXBACKUP hit"); + msg_badread = 1; + return; + } + + usercmd_t* from = &cmdNull; + for (int i = totalcmds - 1; i >= 0; i--) + { + MSG_ReadUsercmd(&cmds[i], from); + from = &cmds[i]; + } + + if (!g_psv.active || !(host_client->active || host_client->spawned)) + return; + + + if (msg_badread) + { + Con_Printf("Client %s:%s sent a bogus command packet\n", host_client->name, NET_AdrToString(host_client->netchan.remote_address)); + return; + } + + cbpktchecksum = COM_BlockSequenceCRCByte(&net_message.data[placeholder + 1], msg_readcount - placeholder - 1, host_client->netchan.incoming_sequence); + if (cbpktchecksum != cbchecksum) + { + Con_DPrintf("Failed command checksum for %s:%s\n", host_client->name, NET_AdrToString(host_client->netchan.remote_address)); + msg_badread = 1; + return; + } + + host_client->packet_loss = packet_loss; + if (!g_psv.paused && (g_psvs.maxclients > 1 || !key_dest) && !(sv_player->v.flags & FL_FROZEN)) + { + sv_player->v.v_angle[0] = cmds[0].viewangles[0]; + sv_player->v.v_angle[1] = cmds[0].viewangles[1]; + sv_player->v.v_angle[2] = cmds[0].viewangles[2]; + } + else + { + for (int i = 0; i < numcmds; i++) + { + cmd = &cmds[i]; + cmd->msec = 0; + cmd->forwardmove = 0; + cmd->sidemove = 0; + cmd->upmove = 0; + cmd->buttons = 0; + + if (sv_player->v.flags & FL_FROZEN) + cmd->impulse = 0; + + cmd->viewangles[0] = sv_player->v.v_angle[0]; + cmd->viewangles[1] = sv_player->v.v_angle[1]; + cmd->viewangles[2] = sv_player->v.v_angle[2]; + } + + net_drop = 0; + } + + sv_player->v.button = cmds[0].buttons; + sv_player->v.light_level = cmds[0].lightlevel; + SV_EstablishTimeBase(host_client, cmds, net_drop, numbackup, numcmds); + if (net_drop < 24) + { + while (net_drop > numbackup) + { + SV_RunCmd(&host_client->lastcmd, 0); + net_drop--; + } + + while (net_drop > 0) + { + SV_RunCmd(&cmds[numcmds + net_drop - 1], host_client->netchan.incoming_sequence - (numcmds + net_drop - 1)); + net_drop--; + } + + } + + for (int i = numcmds - 1; i >= 0; i--) + { + SV_RunCmd(&cmds[i], host_client->netchan.incoming_sequence - i); + } + + host_client->lastcmd = cmds[0]; + + frame->ping_time -= float(host_client->lastcmd.msec * 0.5 / 1000.0); + if (frame->ping_time < 0.0) + frame->ping_time = 0; + + if (sv_player->v.animtime > host_frametime + g_psv.time) + sv_player->v.animtime = float(host_frametime + g_psv.time); +} + +/* ../engine/sv_user.c:2022 */ +void SV_ParseVoiceData(client_t *cl) +{ + char chReceived[4096]; + int iClient = cl - g_psvs.clients; + unsigned int nDataLength = MSG_ReadShort(); + if (nDataLength > sizeof(chReceived)) + { + Con_DPrintf("SV_ParseVoiceData: invalid incoming packet.\n"); + SV_DropClient(cl, 0, "Invalid voice data\n"); + return; + } + + MSG_ReadBuf(nDataLength, chReceived); + cl->m_lastvoicetime = g_psv.time; + + if (sv_voiceenable.value == 0.0f) + return; + + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *pDestClient = &g_psvs.clients[i]; + if (!((1 << (i & 0x1F)) & cl->m_VoiceStreams[i >> 5]) && i != iClient) + continue; + + if (!pDestClient->active && !pDestClient->connected && i != iClient) + continue; + + int nSendLength = nDataLength; + if (i == iClient && !pDestClient->m_bLoopback) + nSendLength = 0; + + if (pDestClient->datagram.cursize + nSendLength + 6 < pDestClient->datagram.maxsize) + { + MSG_WriteByte(&pDestClient->datagram, svc_voicedata); + MSG_WriteByte(&pDestClient->datagram, iClient); + MSG_WriteShort(&pDestClient->datagram, nSendLength); + MSG_WriteBuf(&pDestClient->datagram, nSendLength, chReceived); + } + } +} + +/* ../engine/sv_user.c:2091 */ +void SV_IgnoreHLTV(client_t *cl) +{ +} + +/* ../engine/sv_user.c:2096 */ +void SV_ParseCvarValue(client_t *cl) +{ + char *value; + value = MSG_ReadString(); + if (gNewDLLFunctions.pfnCvarValue) + gNewDLLFunctions.pfnCvarValue(cl->edict, value); + + Con_DPrintf("Cvar query response: name:%s, value:%s\n", cl->name, value); +} + +/* ../engine/sv_user.c:2107 */ +void SV_ParseCvarValue2(client_t *cl) +{ + int requestID = MSG_ReadLong(); + + char cvarName[255]; + Q_strncpy(cvarName, MSG_ReadString(), sizeof(cvarName)); + cvarName[sizeof(cvarName) - 1] = 0; + + char* value = MSG_ReadString(); + + if (gNewDLLFunctions.pfnCvarValue2) + gNewDLLFunctions.pfnCvarValue2(cl->edict, requestID, cvarName, value); + + Con_DPrintf("Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, cvarName, value); +} + +void SV_HandleClientMessage_api(IGameClient* client, int8_t opcode) { + client_t* cl = client->GetClient(); + if (opcode < clc_bad || opcode > clc_cvarvalue2) + { + Con_Printf("SV_ReadClientMessage: unknown command char (%d)\n", opcode); + SV_DropClient(cl, 0, "Bad command character in client command"); + return; + } + + void(*func)(client_t *) = sv_clcfuncs[opcode].pfnParse; + if (func) + func(cl); +} + +/* ../engine/sv_user.c:2155 */ +void SV_ExecuteClientMessage(client_t *cl) +{ + g_balreadymoved = 0; + client_frame_t * frame = &cl->frames[SV_UPDATE_MASK & cl->netchan.incoming_acknowledged]; + frame->ping_time = realtime - frame->senttime - cl->next_messageinterval; + if (frame->senttime == 0.0) + frame->ping_time = 0; + + if (realtime - cl->connection_started < 2.0 && frame->ping_time > 0.0) + frame->ping_time = 0; + + SV_ComputeLatency(cl); + host_client = cl; + sv_player = cl->edict; + cl->delta_sequence = -1; + pmove = &g_svmove; + IGameClient* apiClient = GetRehldsApiClient(cl); + + while (1) + { + if (msg_badread) + { + Con_Printf("SV_ReadClientMessage: badread\n"); + return; + } + + int c = MSG_ReadByte(); + if (c == -1) + return; + + g_RehldsHookchains.m_HandleNetCommand.callChain(SV_HandleClientMessage_api, apiClient, c); + } + +} + +/* ../engine/sv_user.c:2233 */ +qboolean SV_SetPlayer(int idnum) +{ + for (int i = 0; i < g_psvs.maxclients; i++) + { + client_t *cl = &g_psvs.clients[i]; + if (!cl->spawned || !cl->active || !cl->connected) + continue; + + if (cl->userid == idnum) + { + host_client = cl; + sv_player = cl->edict; + return 1; + } + } + + Con_Printf("Userid %i is not on the server\n", idnum); + return 0; +} + +/* ../engine/sv_user.c:2260 */ +void SV_ShowServerinfo_f(void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + } + else + { + Info_Print(Info_Serverinfo()); + } +} + +/* ../engine/sv_user.c:2277 */ +void SV_SendEnts_f(void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + } + else + { + if (host_client->active && host_client->spawned) + { + if (host_client->connected) + host_client->fully_connected = 1; + } + } +} + +/* ../engine/sv_user.c:2302 */ +void SV_FullUpdate_f(void) +{ + int entIndex; + float ltime; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer(); + return; + } + + if (host_client->active) + { + entIndex = IndexOfEdict(host_client->edict); + if (s_LastFullUpdate[entIndex] > g_psv.time) + s_LastFullUpdate[entIndex] = 0; + + ltime = g_psv.time - s_LastFullUpdate[entIndex]; + if (ltime <= 0.0) + ltime = 0.0; + + if (ltime < 0.45 && g_psv.time > 0.45) + { + Con_DPrintf( + "%s is spamming fullupdate: (%f) (%f) (%f)\n", + host_client->name, + g_psv.time, + s_LastFullUpdate[entIndex], + ltime); + return; + } + s_LastFullUpdate[entIndex] = g_psv.time; + } + + SV_ForceFullClientsUpdate(); + gEntityInterface.pfnClientCommand(sv_player); +} diff --git a/rehlds/engine/sv_user.h b/rehlds/engine/sv_user.h new file mode 100644 index 0000000..513db86 --- /dev/null +++ b/rehlds/engine/sv_user.h @@ -0,0 +1,156 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SV_USER_H +#define SV_USER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "server.h" +#include "world.h" +#include "pm_defs.h" + + +typedef struct command_s command_t; + +/* ../engine/sv_user.c:1311 */ +typedef struct sv_adjusted_positions_s +{ + int active; + int needrelink; + vec3_t neworg; + vec3_t oldorg; + vec3_t initial_correction_org; + vec3_t oldabsmin; + vec3_t oldabsmax; + int deadflag; + vec3_t temp_org; + int temp_org_setflag; +} sv_adjusted_positions_t; + +/* ../engine/sv_user.c:2124 */ +typedef struct clc_func_s +{ + unsigned char opcode; + char *pszname; + void(*pfnParse)(client_t *); +} clc_func_t; + +#ifdef HOOK_ENGINE +#define sv_player (*psv_player) +#define clcommands (*pclcommands) +#define truepositions (*ptruepositions) +#define g_balreadymoved (*pg_balreadymoved) +#define sv_clcfuncs (*psv_clcfuncs) + +#define s_LastFullUpdate (*ps_LastFullUpdate) +#define sv_edgefriction (*psv_edgefriction) +#define sv_maxspeed (*psv_maxspeed) +#define sv_accelerate (*psv_accelerate) +#define sv_footsteps (*psv_footsteps) +#define sv_rollspeed (*psv_rollspeed) +#define sv_rollangle (*psv_rollangle) +#define sv_unlag (*psv_unlag) +#define sv_maxunlag (*psv_maxunlag) +#define sv_unlagpush (*psv_unlagpush) +#define sv_unlagsamples (*psv_unlagsamples) +#define mp_consistency (*pmp_consistency) +#define sv_voiceenable (*psv_voiceenable) + +#define nofind (*pnofind) + +#endif // HOOK_ENGINE + +extern edict_t *sv_player; +extern command_t clcommands[23]; +extern sv_adjusted_positions_t truepositions[MAX_CLIENTS]; +extern qboolean g_balreadymoved; + +#ifdef HOOK_ENGINE +extern clc_func_t sv_clcfuncs[12]; +#else +#endif + + +extern float s_LastFullUpdate[33]; +extern cvar_t sv_edgefriction; +extern cvar_t sv_maxspeed; +extern cvar_t sv_accelerate; +extern cvar_t sv_footsteps; +extern cvar_t sv_rollspeed; +extern cvar_t sv_rollangle; +extern cvar_t sv_unlag; +extern cvar_t sv_maxunlag; +extern cvar_t sv_unlagpush; +extern cvar_t sv_unlagsamples; +extern cvar_t mp_consistency; +extern cvar_t sv_voiceenable; + +extern qboolean nofind; + + +void SV_ParseConsistencyResponse(client_t *pSenderClient); +qboolean SV_FileInConsistencyList(const char *filename, consistency_t **ppconsist); +int SV_TransferConsistencyInfo(void); +void SV_SendConsistencyList(sizebuf_t *msg); +void SV_PreRunCmd(void); +void SV_CopyEdictToPhysent(physent_t *pe, int e, edict_t *check); +void SV_AddLinksToPM_(areanode_t *node, float *pmove_mins, float *pmove_maxs); +void SV_AddLinksToPM(areanode_t *node, vec_t *origin); +void SV_PlayerRunPreThink(edict_t *player, float time); +qboolean SV_PlayerRunThink(edict_t *ent, float frametime, double clienttimebase); +void SV_CheckMovingGround(edict_t *player, float frametime); +void SV_ConvertPMTrace(trace_t *dest, pmtrace_t *src, edict_t *ent); +void SV_ForceFullClientsUpdate(void); +void SV_RunCmd(usercmd_t *ucmd, int random_seed); +int SV_ValidateClientCommand(char *pszCommand); +float SV_CalcClientTime(client_t *cl); +void SV_ComputeLatency(client_t *cl); +int SV_UnlagCheckTeleport(vec_t *v1, vec_t *v2); +void SV_GetTrueOrigin(int player, vec_t *origin); +void SV_GetTrueMinMax(int player, float **fmin, float **fmax); +entity_state_t *SV_FindEntInPack(int index, packet_entities_t *pack); +void SV_SetupMove(client_t *_host_client); +void SV_RestoreMove(client_t *_host_client); +void SV_ParseStringCommand(client_t *pSenderClient); +void SV_ParseDelta(client_t *pSenderClient); +void SV_EstablishTimeBase(client_t *cl, usercmd_t *cmds, int dropped, int numbackup, int numcmds); +void SV_ParseMove(client_t *pSenderClient); +void SV_ParseVoiceData(client_t *cl); +void SV_IgnoreHLTV(client_t *cl); +void SV_ParseCvarValue(client_t *cl); +void SV_ParseCvarValue2(client_t *cl); +void SV_ExecuteClientMessage(client_t *cl); +qboolean SV_SetPlayer(int idnum); +void SV_ShowServerinfo_f(void); +void SV_SendEnts_f(void); +void SV_FullUpdate_f(void); + +#endif // SV_USER_H diff --git a/rehlds/engine/sys_dll.cpp b/rehlds/engine/sys_dll.cpp new file mode 100644 index 0000000..ccf78c5 --- /dev/null +++ b/rehlds/engine/sys_dll.cpp @@ -0,0 +1,1400 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +void(*Launcher_ConsolePrintf)(char *, ...); +char *(*Launcher_GetLocalizedString)(unsigned int); +int(*Launcher_MP3subsys_Suspend_Audio)(void); +void(*Launcher_MP3subsys_Resume_Audio)(void); +void(*VID_FlipScreen)(void); + + +//double curtime; +//double lastcurtime; +//qboolean sc_return_on_enter; + +//char findbase[260]; +//char findname[260]; +//char findpath[260]; +//char findpattern[260]; + +//const char g_szExtensionDllSubDir; +//const char g_szHalfLifeDllName; +//const char g_szBaseDllName; + +char gszDisconnectReason[MAX_DISCONNECT_REASON]; +char gszExtendedDisconnectReason[MAX_DISCONNECT_REASON]; + +qboolean gfExtendedError; +qboolean g_bIsDedicatedServer; + +int giSubState; +int giActive; +int giStateInfo; +DLL_FUNCTIONS gEntityInterface; +NEW_DLL_FUNCTIONS gNewDLLFunctions; + +extensiondll_t g_rgextdll[50]; + +int g_iextdllMac; +modinfo_t gmodinfo; +qboolean gfBackground; +//extern jmp_buf host_abortserver; +//int starttime; +//qboolean Win32AtLeastV4; +//int lowshift; +//double pfreq; +qboolean g_bPrintingKeepAliveDots; +//DWORD gProcessorSpeed; +#ifndef _WIN32 +qboolean gHasMMXTechnology; +#endif // _WIN32 +//volatile int sys_checksum; +//char *argv[50]; +qboolean con_debuglog; + +#ifdef REHLDS_FIXES +char g_szFindFirstFileName[MAX_PATH]; +#endif + +#ifdef _WIN32 +int g_PerfCounterInitialized; +CRITICAL_SECTION g_PerfCounterMutex; + +int g_PerfCounterShiftRightAmount; +double g_PerfCounterSlice; +double g_CurrentTime; +double g_StartTime; + + + +int g_WinNTOrHigher; +#endif // _WIN32 + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +int g_FPUCW_Mask_Prec_64Bit = 0; +int g_FPUCW_Mask_Prec_64Bit_2 = 0; +int g_FPUCW_Mask_Round_Trunc = 0; +int g_FPUCW_Mask_Round_Up = 0; + +FileFindHandle_t g_hfind = FILESYSTEM_INVALID_FIND_HANDLE; + +enginefuncs_t g_engfuncsExportedToDlls = { + PF_precache_model_I, PF_precache_sound_I, + PF_setmodel_I, PF_modelindex, + ModelFrames, PF_setsize_I, + PF_changelevel_I, PF_setspawnparms_I, + SaveSpawnParms, PF_vectoyaw_I, + PF_vectoangles_I, SV_MoveToOrigin_I, + PF_changeyaw_I, PF_changepitch_I, + FindEntityByString, GetEntityIllum, + FindEntityInSphere, PF_checkclient_I, + PVSFindEntities, PF_makevectors_I, + AngleVectors, PF_Spawn_I, + PF_Remove_I, CreateNamedEntity, + PF_makestatic_I, PF_checkbottom_I, + PF_droptofloor_I, PF_walkmove_I, + PF_setorigin_I, PF_sound_I, + PF_ambientsound_I, PF_traceline_DLL, + PF_TraceToss_DLL, TraceMonsterHull, + TraceHull, TraceModel, + TraceTexture, TraceSphere, + PF_aim_I, PF_localcmd_I, + PF_localexec_I, PF_stuffcmd_I, + PF_particle_I, PF_lightstyle_I, + PF_DecalIndex, PF_pointcontents_I, + PF_MessageBegin_I, PF_MessageEnd_I, + PF_WriteByte_I, PF_WriteChar_I, + PF_WriteShort_I, PF_WriteLong_I, + PF_WriteAngle_I, PF_WriteCoord_I, + PF_WriteString_I, PF_WriteEntity_I, + CVarRegister, CVarGetFloat, + CVarGetString, CVarSetFloat, + CVarSetString, AlertMessage, + EngineFprintf, PvAllocEntPrivateData, + PvEntPrivateData, FreeEntPrivateData, + SzFromIndex, AllocEngineString, + GetVarsOfEnt, PEntityOfEntOffset, + EntOffsetOfPEntity, IndexOfEdict, + PEntityOfEntIndex, FindEntityByVars, + GetModelPtr, RegUserMsg, + AnimationAutomove, GetBonePosition, + FunctionFromName, NameForFunction, + ClientPrintf, ServerPrint, + Cmd_Args, Cmd_Argv, Cmd_Argc, + GetAttachment, CRC32_Init, + CRC32_ProcessBuffer, CRC32_ProcessByte, + CRC32_Final, RandomLong, + RandomFloat, PF_setview_I, + PF_Time, PF_crosshairangle_I, + COM_LoadFileForMe, COM_FreeFile, + Host_EndSection, COM_CompareFileTime, + COM_GetGameDir, Cvar_RegisterVariable, + PF_FadeVolume, PF_SetClientMaxspeed, + PF_CreateFakeClient_I, + PF_RunPlayerMove_I, + PF_NumberOfEntities_I, + PF_GetInfoKeyBuffer_I, PF_InfoKeyValue_I, + PF_SetKeyValue_I, PF_SetClientKeyValue_I, + PF_IsMapValid_I, PF_StaticDecal, + PF_precache_generic_I, + PF_GetPlayerUserId, PF_BuildSoundMsg_I, + PF_IsDedicatedServer, CVarGetPointer, + PF_GetPlayerWONId, PF_RemoveKey_I, + PF_GetPhysicsKeyValue, + PF_SetPhysicsKeyValue, + PF_GetPhysicsInfoString, EV_Precache, + EV_Playback, SV_FatPVS, SV_FatPAS, + SV_CheckVisibility, DELTA_SetField, + DELTA_UnsetField, DELTA_AddEncoder, + PF_GetCurrentPlayer, PF_CanSkipPlayer, + DELTA_FindFieldIndex, + DELTA_SetFieldByIndex, + DELTA_UnsetFieldByIndex, PF_SetGroupMask, + PF_CreateInstancedBaseline, + PF_Cvar_DirectSet, PF_ForceUnmodified, + PF_GetPlayerStats, Cmd_AddGameCommand, + Voice_GetClientListening, + Voice_SetClientListening, + PF_GetPlayerAuthId, NULL, + NULL, COM_FileSize, + COM_GetApproxWavePlayLength, + VGuiWrap2_IsInCareerMatch, + VGuiWrap2_GetLocalizedStringLength, + RegisterTutorMessageShown, + GetTimesTutorMessageShown, + ProcessTutorMessageDecayBuffer, + ConstructTutorMessageDecayBuffer, + ResetTutorMessageDecayData, + QueryClientCvarValue, QueryClientCvarValue2 +}; + +#else //HOOK_ENGINE + +int g_FPUCW_Mask_Prec_64Bit; +int g_FPUCW_Mask_Prec_64Bit_2; +int g_FPUCW_Mask_Round_Trunc; +int g_FPUCW_Mask_Round_Up; + +FileFindHandle_t g_hfind; + +enginefuncs_t g_engfuncsExportedToDlls; + +#endif //HOOK_ENGINE + +#ifdef _WIN32 +void Sys_SetupFPUOptions() +{ + static uint8_t fpuOpts[32]; + + __asm { fnstenv byte ptr fpuOpts } + fpuOpts[0] |= 0x3Fu; + __asm { fldenv byte ptr fpuOpts } +} + +__declspec(noinline) void Sys_InitFPUControlWords() +{ + int fpucw = 0; + __asm { fnstcw fpucw } + + g_FPUCW_Mask_Prec_64Bit = (fpucw & 0xF0FF) | 0x300; + g_FPUCW_Mask_Prec_64Bit_2 = (fpucw & 0xF0FF) | 0x300; + g_FPUCW_Mask_Round_Trunc = (fpucw & 0xF0FF) | 0xC00; + g_FPUCW_Mask_Round_Up = (fpucw & 0xF0FF) | 0x800; +} + +void __cdecl Sys_SetStartTime() +{ + int startTimeArg; + + Sys_FloatTime(); + startTimeArg = COM_CheckParm("-starttime"); + if (startTimeArg) + g_CurrentTime = Q_atof(com_argv[startTimeArg + 1]); + else + g_CurrentTime = 0; + + g_StartTime = g_CurrentTime; +} + +void __cdecl Sys_InitHardwareTimer() +{ + unsigned int perfHighPart; + unsigned int perfLowPart; + LARGE_INTEGER perfFreq; + + if (!g_PerfCounterInitialized) + { + InitializeCriticalSection(&g_PerfCounterMutex); + g_PerfCounterInitialized = 1; + } + Sys_SetupFPUOptions(); + Sys_InitFPUControlWords(); + + if (!CRehldsPlatformHolder::get()->QueryPerfFreq(&perfFreq)) + Sys_Error("No hardware timer available"); + + perfHighPart = perfFreq.HighPart; + perfLowPart = perfFreq.LowPart; + g_PerfCounterShiftRightAmount = 0; + while (perfHighPart || perfLowPart > 2000000.0) + { + g_PerfCounterShiftRightAmount++; + perfLowPart = (perfHighPart << 31) | (perfLowPart >> 1); + perfHighPart >>= 1; + } + g_PerfCounterSlice = 1.0 / (double)perfLowPart; + + Sys_CheckOSVersion(); + Sys_SetStartTime(); +} + +int g_SavedFPUCW1 = 0; +__declspec(noinline) void Sys_FPUCW_Push_Prec64() { + uint16_t tmp = g_FPUCW_Mask_Prec_64Bit; + __asm { fnstcw g_SavedFPUCW1 } + __asm { fldcw tmp } +} + +__declspec(noinline) void Sys_FPUCW_Pop_Prec64() { + uint16_t tmp = g_SavedFPUCW1; + __asm { fldcw tmp } +} + +#endif // _WIN32 + +/* <8d234> ../engine/sys_dll.c:161 */ +NOXREF void Sys_PageIn(void *ptr, int size) +{ +} + +// TODO: investigate filesystem_stdio problem (multiple enumeration of files). +/* <8d0fa> ../engine/sys_dll.c:201 */ +const char *Sys_FindFirst(const char *path, char *basename) +{ + if (g_hfind != -1) + { + Sys_Error(__FUNCTION__ " without close"); + } + + const char *psz = FS_FindFirst(path, &g_hfind, 0); + +#ifdef REHLDS_FIXES + // Hack: store first file name to fix multiple enumeration of files in the filesystem module + if (psz != NULL) + { + Q_strncpy(g_szFindFirstFileName, psz, MAX_PATH - 1); + } +#endif // REHLDS_FIXES + + if (basename && psz) + { + COM_FileBase((char *)psz, basename); + } + + return psz; +} + +/* <8d565> ../engine/sys_dll.c:227 */ +const char *Sys_FindFirstPathID(const char *path, char *pathid) +{ + //const char *psz;//unused? + if (g_hfind != -1) + Sys_Error("Sys_FindFirst without close"); + return FS_FindFirst(path, &g_hfind, pathid); +} + +// TODO: investigate filesystem_stdio problem (multiple enumeration of files). +/* <8d168> ../engine/sys_dll.c:247 */ +const char *Sys_FindNext(char *basename) +{ + const char *psz = FS_FindNext(g_hfind); + +#ifdef REHLDS_FIXES + // Hack: stop if we are starting over again + if (psz && !Q_strcmp(g_szFindFirstFileName, psz)) + { + return NULL; + } +#endif // REHLDS_FIXES + + if (basename && psz) + { + COM_FileBase((char *)psz, basename); + } + + return psz; +} + +/* <8d290> ../engine/sys_dll.c:263 */ +void Sys_FindClose(void) +{ + if (g_hfind != -1) + { + FS_FindClose(g_hfind); + g_hfind = -1; + } + +#ifdef REHLDS_FIXES + g_szFindFirstFileName[0] = 0; +#endif // REHLDS_FIXES +} + +/* <8d2ac> ../engine/sys_dll.c:280 */ +NOBODY int glob_match_after_star(char *pattern, char *text); +//{ +// char *p; // 282 +// char *t; // 282 +// char c; // 283 +// char c1; // 283 +//} + +/* <8d300> ../engine/sys_dll.c:323 */ +NOBODY int glob_match(char *pattern, char *text); +//{ +// char *p; // 325 +// char *t; // 325 +// char c; // 326 +// +//match : // 386; +// { +// char c1; // 347 +// int invert; // 348 +// { +// char cstart; // 359 +// char cend; // 359 +// } +// } +// glob_match_after_star(char *pattern, +// char *text); /* size=0, low_pc=0 */ // 343 +//} + +/* <8d403> ../engine/sys_dll.c:424 */ +NOXREF void Sys_MakeCodeWriteable(uint32 startaddr, uint32 length) +{ +#ifdef _WIN32 + if (!VirtualProtect((LPVOID)startaddr, length, PAGE_EXECUTE_READWRITE, (PDWORD)&length)) + Sys_Error("Protection change failed."); +#endif // _WIN32 +} + +/* <8d43b> ../engine/sys_dll.c:441 */ +NOBODY void Sys_SetFPCW(void); +//{ +//} + +/* <8d450> ../engine/sys_dll.c:445 */ +NOBODY void Sys_PushFPCW_SetHigh(void); +//{ +//} + +/* <8d465> ../engine/sys_dll.c:449 */ +NOBODY void Sys_PopFPCW(void); +//{ +//} + +/* <8d47a> ../engine/sys_dll.c:453 */ +NOBODY void MaskExceptions(void); +//{ +//} + +/* <8d48f> ../engine/sys_dll.c:469 */ +NOBODY void Sys_Init(void); + +/* <8d4a4> ../engine/sys_dll.c:509 */ +NOXREF void Sys_Sleep(int msec) +{ +#ifdef _WIN32 + Sleep(msec); +#else + usleep(1000 *msec); +#endif // _WIN32 +} + +/* <8d4cd> ../engine/sys_dll.c:519 */ +NOBODY void Sys_DebugOutStraight(const char *pStr); +//{ +//} + +/* <8d4f7> ../engine/sys_dll.c:529 */ +void __declspec(noreturn) Sys_Error(const char *error, ...) +{ + va_list argptr; + char text[1024]; + static qboolean bReentry; + + va_start(argptr, error); + Q_vsnprintf(text, ARRAYSIZE(text), error, argptr); + va_end(argptr); + +#ifdef _WIN32 + MessageBox(GetForegroundWindow(), text, "Fatal error - Dedicated server", MB_ICONERROR | MB_OK); +#endif // _WIN32 + + if (bReentry) + { + fprintf(stderr, "%s\n", text); + longjmp(host_abortserver, 2); + } + bReentry = true; + + if (g_psvs.dll_initialized && gEntityInterface.pfnSys_Error) + gEntityInterface.pfnSys_Error(text); + + Log_Printf("FATAL ERROR (shutting down): %s\n", text); + + if (g_bIsDedicatedServer) + { + if (Launcher_ConsolePrintf) + Launcher_ConsolePrintf("FATAL ERROR (shutting down): %s\n", text); + else + printf("FATAL ERROR (shutting down): %s\n", text); + } +#ifndef SWDS + else + { + HWND hWnd = 0; + if (pmainwindow) + hWnd = *pmainwindow; + + Sys_Printf(text); + SDL_ShowSimpleMessageBox(MB_ICONERROR | MB_OK, "Fatal Error", text, hWnd); + VideoMode_IsWindowed(); + } +#endif // SWDS + + //exit(-1); + //Allahu akbar! + *(int *)NULL = NULL; +} + +/* <8d626> ../engine/sys_dll.c:600 */ +NOXREF void Sys_Warning(const char *pszWarning, ...) +{ + va_list argptr; + char text[1024]; + + va_start(argptr, pszWarning); + vsnprintf(text, sizeof(text), pszWarning, argptr); + va_end(argptr); + + Sys_Printf(text); +} + +/* <8d5db> ../engine/sys_dll.c:612 */ +void Sys_Printf(const char *fmt, ...) +{ + char Dest[1024]; + va_list va; + + va_start(va, fmt); + Q_vsnprintf(Dest, sizeof(Dest), fmt, va); + va_end(va); + + if (g_bIsDedicatedServer && Launcher_ConsolePrintf) + Launcher_ConsolePrintf("%s", Dest); + +#ifdef _WIN32 + OutputDebugStringA(Dest); +#else + if (!g_bIsDedicatedServer) + fprintf(stderr, "%s\n", Dest); +#endif // _WIN32 + +} + +/* <8d671> ../engine/sys_dll.c:645 */ +void Sys_Quit(void) +{ + giActive = DLL_CLOSE; +} + +#ifdef _WIN32 + +double Sys_FloatTime(void) +{ + unsigned int currentTime; + int savedOldTime; + LARGE_INTEGER PerformanceCount; + + static bool s_NeedInit = true; + static unsigned int s_oldTime = 0; + static int s_timeNotChangedCounter = 0; + + if (!g_PerfCounterInitialized) + return 1.0; + + EnterCriticalSection(&g_PerfCounterMutex); + Sys_FPUCW_Push_Prec64(); + + CRehldsPlatformHolder::get()->QueryPerfCounter(&PerformanceCount); + if (g_PerfCounterShiftRightAmount) + currentTime = (PerformanceCount.LowPart >> g_PerfCounterShiftRightAmount) | (PerformanceCount.HighPart << (32 - g_PerfCounterShiftRightAmount)); + else + currentTime = PerformanceCount.LowPart; + + if (!s_NeedInit) + { + savedOldTime = s_oldTime; + if (currentTime <= s_oldTime && s_oldTime - currentTime < 0x10000000) + { + s_oldTime = currentTime; + } + else + { + s_oldTime = currentTime; + g_CurrentTime = g_CurrentTime + (double)(currentTime - savedOldTime) * g_PerfCounterSlice; + if (g_CurrentTime == g_StartTime) + { + if (s_timeNotChangedCounter >= 100000) + { + g_CurrentTime = g_CurrentTime + 1.0; + s_timeNotChangedCounter = 0; + } + } + else + { + s_timeNotChangedCounter = 0; + } + g_StartTime = g_CurrentTime; + } + } + else + { + s_oldTime = currentTime; + s_NeedInit = false; + } + + Sys_FPUCW_Pop_Prec64(); + LeaveCriticalSection(&g_PerfCounterMutex); + return g_CurrentTime; +} + +#else // not _WIN32 + +double Sys_FloatTime(void) +{ + static struct timespec start_time; + static bool bInitialized; + struct timespec now; + + if ( !bInitialized ) + { + bInitialized = 1; + clock_gettime(1, &start_time); + } + clock_gettime(1, &now); + return (now.tv_sec - start_time.tv_sec) + now.tv_nsec * 0.000000001; +} + +#endif //_WIN32 + +/* <8d042> ../engine/sys_dll.c:830 */ +void Dispatch_Substate(int iSubState) +{ + giSubState = iSubState; +} + +/* <8d6f5> ../engine/sys_dll.c:835 */ +void GameSetSubState(int iSubState) +{ + if (iSubState & 2) + { + Dispatch_Substate(1); + } + else if (iSubState != 1) + { + Dispatch_Substate(iSubState); + } +} + +/* <8d753> ../engine/sys_dll.c:847 */ +void GameSetState(int iState) +{ + giActive = iState; +} + +/* <8d77c> ../engine/sys_dll.c:853 */ +NOBODY void GameSetBackground(qboolean bNewSetting); +//{ +//} + +/* <8d191> ../engine/sys_dll.c:1076 */ +qboolean Voice_GetClientListening(int iReceiver, int iSender) +{ + --iReceiver; + --iSender; + + if (iReceiver < 0 || iSender < 0 || iReceiver >= g_psvs.maxclients || iSender >= g_psvs.maxclients) + return 0; + + return (1 << iReceiver) & (g_psvs.clients[iSender].m_VoiceStreams[iReceiver >> 5] != 0); +} + +/* <8d1d0> ../engine/sys_dll.c:1090 */ +qboolean Voice_SetClientListening(int iReceiver, int iSender, qboolean bListen) +{ + --iReceiver; + --iSender; + + if (iReceiver < 0 || iSender < 0 || iReceiver >= g_psvs.maxclients || iSender >= g_psvs.maxclients) + return 0; + + uint32 *pDest = g_psvs.clients[iSender].m_VoiceStreams; + if (bListen) + { + pDest[iReceiver >> 5] |= 1 << iReceiver; + } + else + { + pDest[iReceiver >> 5] &= ~(1 << iReceiver); + } + + return 1; +} + +/* <8d7a5> ../engine/sys_dll.c:1332 */ +DISPATCHFUNCTION GetDispatch(char *pname) +{ + int i; + DISPATCHFUNCTION pDispatch; + + for (i = 0; i < g_iextdllMac; i++) + { + pDispatch = (DISPATCHFUNCTION)GetProcAddress((HMODULE)g_rgextdll[i].lDLLHandle, pname); + if (pDispatch) + { + return pDispatch; + } + } + + return NULL; +} + +/* <8d80b> ../engine/sys_dll.c:1362 */ +const char *FindAddressInTable(extensiondll_t *pDll, uint32 function) +{ +#ifdef _WIN32 + for (int i = 0; i < pDll->functionCount; i++) + { + if (pDll[i].functionTable->pFunction == function) + { + return pDll[i].functionTable->pFunctionName; + } + } +#else // _WIN32 + Dl_info addrInfo; + if (dladdr((void *)function, &addrInfo)) + { + return addrInfo.dli_sname; + } +#endif // _WIN32 + + return NULL; +} + +/* <8d05e> ../engine/sys_dll.c:1383 */ +uint32 FindNameInTable(extensiondll_t *pDll, const char *pName) +{ +#ifdef _WIN32 + for (int i = 0; i < pDll->functionCount; i++) + { + if (!Q_strcmp(pName, pDll->functionTable[i].pFunctionName)) + { + return pDll[i].functionTable->pFunction; + } + } + return NULL; +#else + return (uint32)dlsym(pDll->lDLLHandle, pName); +#endif // _WIN32 +} + +/* <8d8a0> ../engine/sys_dll.c:1407 */ +NOBODY const char *ConvertNameToLocalPlatform(const char *pchInName); +//{ +// char s_szNewName; // 1409 +// { +// char szTempName; // 1463 +// char *pchAt; // 1464 +// char *pchClassName; // 1465 +// char *pchFunctionName; // 1466 +// FindNameInTable(extensiondll_t *pDll, +// const char *pName); /* size=0, low_pc=0 */ // 1483 +// FindNameInTable(extensiondll_t *pDll, +// const char *pName); /* size=0, low_pc=0 */ // 1487 +// FindNameInTable(extensiondll_t *pDll, +// const char *pName); /* size=0, low_pc=0 */ // 1491 +// } +//} + +/* <8df19> ../engine/sys_dll.c:1499 */ +uint32 FunctionFromName(const char *pName) +{ + return 0; //TODO: do we really need to reverse it? +} + +/* <8de9a> ../engine/sys_dll.c:1518 */ +const char *NameForFunction(uint32 function) +{ + int i; + const char *pName; + + for (i = 0; i < g_iextdllMac; i++) + { + pName = FindAddressInTable(&g_rgextdll[i], function); + if (pName) + { + return pName; + } + } + + Con_Printf("Can't find address: %08lx\n", function); + return NULL; +} + +/* <8d9e7> ../engine/sys_dll.c:1536 */ +ENTITYINIT GetEntityInit(char *pClassName) +{ + return (ENTITYINIT)GetDispatch(pClassName); +} + +/* <8da46> ../engine/sys_dll.c:1543 */ +FIELDIOFUNCTION GetIOFunction(char *pName) +{ + return (FIELDIOFUNCTION)GetDispatch(pName); +} + +/* <8daa5> ../engine/sys_dll.c:1550 */ +void DLL_SetModKey(modinfo_t *pinfo, char *pkey, char *pvalue) +{ + if (!Q_stricmp(pkey, "url_info")) + { + pinfo->bIsMod = 1; + Q_strncpy(pinfo->szInfo, pvalue, sizeof(pinfo->szInfo) - 1); + pinfo->szInfo[sizeof(pinfo->szInfo) - 1] = 0; + } + else if (!Q_stricmp(pkey, "url_dl")) + { + pinfo->bIsMod = 1; + Q_strncpy(pinfo->szDL, pvalue, sizeof(pinfo->szDL) - 1); + pinfo->szDL[sizeof(pinfo->szDL) - 1] = 0; + } + else if (!Q_stricmp(pkey, "version")) + { + pinfo->bIsMod = 1; + pinfo->version = atoi(pvalue); + } + else if (!Q_stricmp(pkey, "size")) + { + pinfo->bIsMod = 1; + pinfo->size = atoi(pvalue); + } + else if (!Q_stricmp(pkey, "svonly")) + { + pinfo->bIsMod = 1; + pinfo->svonly = atoi(pvalue) != 0; + } + else if (!Q_stricmp(pkey, "cldll")) + { + pinfo->bIsMod = 1; + pinfo->cldll = atoi(pvalue) != 0; + } + else if (!Q_stricmp(pkey, "secure")) + { + pinfo->bIsMod = 1; + pinfo->secure = atoi(pvalue) != 0; + } + else if (!Q_stricmp(pkey, "hlversion")) + { + Q_strncpy(pinfo->szHLVersion, pvalue, sizeof(pinfo->szHLVersion) - 1); + pinfo->szHLVersion[sizeof(pinfo->szHLVersion) - 1] = 0; + } + else if (!Q_stricmp(pkey, "edicts")) + { + pinfo->num_edicts = atoi(pvalue); + if (pinfo->num_edicts < 900) + pinfo->num_edicts = 900; + } + else if (!Q_stricmp(pkey, "crcclientdll")) + { + pinfo->bIsMod = 1; + pinfo->clientDllCRC = atoi(pvalue) != 0; + } + else if (!Q_stricmp(pkey, "type")) + { + if (!Q_stricmp(pvalue, "singleplayer_only")) + pinfo->type = SINGLEPLAYER_ONLY; + else if (!Q_stricmp(pvalue, "multiplayer_only")) + pinfo->type = MULTIPLAYER_ONLY; + else + pinfo->type = BOTH; + } + else if (!Q_stricmp(pkey, "fallback_dir")) + { + COM_AddDefaultDir(pvalue); + } + +} + +/* <8e07f> ../engine/sys_dll.c:1629 */ +void LoadEntityDLLs(const char *szBaseDir) +{ + FileHandle_t hLibListFile; + unsigned int nFileSize; + unsigned int nFileSize2; + char *pszInputStream; + int nBytesRead; + char *pStreamPos; + const char *findfn; + NEW_DLL_FUNCTIONS_FN pNewAPI; + APIFUNCTION2 pfnGetAPI2; + APIFUNCTION pfnGetAPI; + char szDllFilename[8192]; + char szDllWildcard[260]; + char szDllListFile[260]; + char szValue[256]; + char szKey[64]; + char szGameDir[64]; + int interface_version; + + SV_ResetModInfo(); + g_iextdllMac = 0; + Q_memset(g_rgextdll, 0, sizeof(g_rgextdll)); + + Q_strncpy(szGameDir, com_gamedir, sizeof(szGameDir) - 1); + if (Q_stricmp(szGameDir, "valve")) + gmodinfo.bIsMod = 1; + + Q_snprintf(szDllListFile, sizeof(szDllListFile), "%s", "liblist.gam"); + hLibListFile = FS_Open(szDllListFile, "rb"); + if (hLibListFile) + { + nFileSize = FS_Size(hLibListFile); + nFileSize2 = nFileSize; + if (!nFileSize || (signed int)nFileSize > 262144) + Sys_Error("Game listing file size is bogus [%s: size %i]", "liblist.gam", nFileSize); + + pszInputStream = (char *)Mem_Malloc(nFileSize + 1); + if (!pszInputStream) + Sys_Error("Could not allocate space for game listing file of %i bytes", nFileSize2 + 1); + + nBytesRead = FS_Read(pszInputStream, nFileSize2, 1, hLibListFile); + if (nBytesRead != nFileSize2) + Sys_Error("Error reading in game listing file, expected %i bytes, read %i", nFileSize2, nBytesRead); + + pszInputStream[nFileSize2] = 0; + pStreamPos = pszInputStream; + com_ignorecolons = 1; + while (1) + { + pStreamPos = COM_Parse(pStreamPos); + if (Q_strlen(com_token) <= 0) + break; + + Q_strncpy(szKey, com_token, sizeof(szKey) - 1); + szKey[sizeof(szKey) - 1] = 0; + pStreamPos = COM_Parse(pStreamPos); + Q_strncpy(szValue, com_token, sizeof(szValue) - 1); + szValue[sizeof(szValue) - 1] = 0; +#ifdef _WIN32 + if (Q_stricmp(szKey, "gamedll")) +#else // _WIN32 + if (Q_stricmp(szKey, "gamedll_linux")) +#endif // _WIN32 + { + DLL_SetModKey(&gmodinfo, szKey, szValue); + } + else + { + int index = COM_CheckParm("-dll"); + if (index && index < com_argc - 1) + { + Q_strncpy(szValue, com_argv[index + 1], sizeof(szValue) - 1); + szValue[sizeof(szValue) - 1] = 0; + } +#ifdef _WIN32 + if (Q_strstr(szValue, ".dll")) +#else // _WIN32 + if (Q_strstr(szValue, ".so")) +#endif // _WIN32 + { + FS_GetLocalPath(szValue, szDllFilename, sizeof(szDllFilename)); + Con_DPrintf("\nAdding: %s/%s\n", szGameDir, szValue); + LoadThisDll(szDllFilename); + } + else + { + Con_DPrintf("Skipping non-dll: %s\n", szValue); + } + } + } + com_ignorecolons = 0; + Mem_Free(pszInputStream); + FS_Close(hLibListFile); + } + else + { +#ifdef _WIN32 + Q_snprintf(szDllWildcard, sizeof(szDllWildcard), "%s\\*.dll", "valve\\dlls"); +#else // _WIN32 + Q_snprintf(szDllWildcard, sizeof(szDllWildcard), "%s\\*.so", "valve\\dlls"); +#endif // _WIN32 + for (findfn = Sys_FindFirst(szDllWildcard, 0); findfn; findfn = Sys_FindNext(0)) + { + Q_snprintf(szDllFilename, sizeof(szDllWildcard), "%s/%s/%s", szBaseDir, "valve\\dlls", findfn); + LoadThisDll(szDllFilename); + } + Sys_FindClose(); + } + gNewDLLFunctions.pfnOnFreeEntPrivateData = NULL; + gNewDLLFunctions.pfnGameShutdown = NULL; + gNewDLLFunctions.pfnShouldCollide = NULL; + gNewDLLFunctions.pfnCvarValue = NULL; + gNewDLLFunctions.pfnCvarValue2 = NULL; + pNewAPI = (NEW_DLL_FUNCTIONS_FN)GetDispatch("GetNewDLLFunctions"); + if (pNewAPI) + { + interface_version = NEW_DLL_FUNCTIONS_VERSION; + pNewAPI(&gNewDLLFunctions, &interface_version); + } + + pfnGetAPI2 = (APIFUNCTION2)GetDispatch("GetEntityAPI2"); + if (pfnGetAPI2) + { + interface_version = INTERFACE_VERSION; + if (!pfnGetAPI2(&gEntityInterface, &interface_version)) + { + Con_Printf("==================\n"); + Con_Printf("Game DLL version mismatch\n"); + Con_Printf("DLL version is %i, engine version is %i\n", interface_version, INTERFACE_VERSION); + if (interface_version <= INTERFACE_VERSION) + Con_Printf("The game DLL for %s appears to be outdated, check for updates\n", szGameDir); + else + Con_Printf("Engine appears to be outdated, check for updates\n"); + Con_Printf("==================\n"); + Host_Error("\n"); + } + } + else + { + pfnGetAPI = (APIFUNCTION)GetDispatch("GetEntityAPI"); + if (!pfnGetAPI) + Host_Error("Couldn't get DLL API from %s!", szDllFilename); + interface_version = INTERFACE_VERSION; + if (!pfnGetAPI(&gEntityInterface, interface_version)) + { + Con_Printf("==================\n"); + Con_Printf("Game DLL version mismatch\n"); + Con_Printf("The game DLL for %s appears to be outdated, check for updates\n", szGameDir); + Con_Printf("==================\n"); + Host_Error("\n"); + } + } + + Con_DPrintf("Dll loaded for %s %s\n", gmodinfo.bIsMod ? "mod" : "game", gEntityInterface.pfnGetGameDescription()); +} + +#ifdef _WIN32 +HMODULE LoadWindowsDLL(LPCSTR lpLibFileName) +{ + if (!lpLibFileName) + return NULL; + + FS_GetLocalCopy(lpLibFileName); + return LoadLibraryA(lpLibFileName); +} +#endif //_WIN32 + +/* <8de05> ../engine/sys_dll.c:1884 */ +void LoadThisDll(const char *szDllFilename) +{ +#ifdef _WIN32 + typedef void(__stdcall *PFN_GiveFnptrsToDll)(enginefuncs_t *, globalvars_t *); +#else + typedef void(__cdecl *PFN_GiveFnptrsToDll)(enginefuncs_t *, globalvars_t *); +#endif // _WIN32 + PFN_GiveFnptrsToDll pfnGiveFnptrsToDll; + extensiondll_t *pextdll; + +#ifdef _WIN32 + HMODULE hDLL = LoadWindowsDLL(szDllFilename); + if (!hDLL) + { + Con_Printf("LoadLibrary failed on %s (%d)\n", szDllFilename, GetLastError()); + goto IgnoreThisDLL; + } +#else // _WIN32 + void *hDLL = dlopen(szDllFilename, RTLD_NOW); + if (!hDLL) + { + Con_Printf("LoadLibrary failed on %s: %s\n", szDllFilename, dlerror()); + goto IgnoreThisDLL; + } +#endif + + +#ifdef _WIN32 + pfnGiveFnptrsToDll = (PFN_GiveFnptrsToDll)GetProcAddress(hDLL, "GiveFnptrsToDll"); +#else + pfnGiveFnptrsToDll = (PFN_GiveFnptrsToDll) dlsym(hDLL, "GiveFnptrsToDll"); +#endif // _WIN32 + + if (pfnGiveFnptrsToDll == NULL) + { + Con_Printf("Couldn't get GiveFnptrsToDll in %s\n", szDllFilename); + goto IgnoreThisDLL; + } + + pfnGiveFnptrsToDll(&g_engfuncsExportedToDlls, &gGlobalVariables); + if (g_iextdllMac == 50) + { + Con_Printf("Too many DLLs, ignoring remainder\n"); + goto IgnoreThisDLL; + } + + pextdll = &g_rgextdll[g_iextdllMac++]; + memset(pextdll, 0, sizeof(*pextdll)); + pextdll->lDLLHandle = hDLL; + return; + +IgnoreThisDLL: + if (hDLL) + { +#ifdef _WIN32 + FreeLibrary(hDLL); +#else + dlclose(hDLL); +#endif // _WIN32 + } +} + +/* <8dba1> ../engine/sys_dll.c:1958 */ +void ReleaseEntityDlls(void) +{ + extensiondll_t *pextdll; + extensiondll_t *pextdllMac; + + if (!g_psvs.dll_initialized) + return; + + FreeAllEntPrivateData(); + + if (gNewDLLFunctions.pfnGameShutdown) + gNewDLLFunctions.pfnGameShutdown(); + + Cvar_UnlinkExternals(); + + pextdll = &g_rgextdll[0]; + pextdllMac = &g_rgextdll[g_iextdllMac]; + + while (pextdll < pextdllMac) + { +#ifdef _WIN32 + FreeLibrary((HMODULE)pextdll->lDLLHandle); +#else + dlclose(pextdll->lDLLHandle); +#endif // _WIN32 + + pextdll->lDLLHandle = NULL; + if (pextdll->functionTable) + { + Mem_Free((void *)pextdll->functionTable); + pextdll->functionTable = NULL; + } + pextdll++; + } + g_psvs.dll_initialized = FALSE; +} + +/* <8ddcb> ../engine/sys_dll.c:2006 */ +void EngineFprintf(void *pfile, const char *szFmt, ...) +{ + AlertMessage(at_console, "EngineFprintf: Obsolete API\n"); +} + +/* <8dd6f> ../engine/sys_dll.c:2022 */ +void AlertMessage(ALERT_TYPE atype, const char *szFmt, ...) +{ + va_list argptr; + static char szOut[1024]; + + va_start(argptr, szFmt); + if (atype == at_logged && g_psvs.maxclients > 1) + { + Q_vsnprintf(szOut, sizeof(szOut), szFmt, argptr); + Log_Printf("%s", szOut); + } + else if (developer.value != 0.0f) + { + switch (atype) + { + case at_notice: + Q_strcpy(szOut, "NOTE: "); + break; + case at_console: + szOut[0] = 0; + break; + case at_aiconsole: + if (developer.value < 2.0f) + return; + szOut[0] = 0; + break; + case at_warning: + Q_strcpy(szOut, "WARNING: "); + break; + case at_error: + Q_strcpy(szOut, "ERROR: "); + break; + case at_logged: + break; + default: + break; + } + int iLen = Q_strlen(szOut); + Q_vsnprintf(&szOut[iLen], sizeof(szOut) - iLen, szFmt, argptr); + Con_Printf("%s\n", szOut); + } + va_end(argptr); +} + +/* <8dbdc> ../engine/sys_dll.c:2198 */ +NOXREF void Sys_SplitPath(const char *path, char *drive, char *dir, char *fname, char *ext) +{ +#ifdef _WIN32 + _splitpath(path, drive, dir, fname, ext); +#else // _WIN32 + + char *p; + char *last_slash = NULL; + char *dot = NULL; + unsigned int len; + + if (path[0] && path[1] == ':') + { + if (drive) + { + Q_strncpy(drive, path, 2); + drive[2] = 0; + } + path += 2; + } + else if (drive) + drive[0] = 0; + + for (p = (char *)path; *p; p++) + { + if (*p == '\\' || *p == '/') + last_slash = ++p; + } + + if (last_slash) + { + if (dir) + { + len = (unsigned int)(last_slash - path); + if (len > 0xFF) + len = 0xFF; + + Q_strncpy(dir, path, len); + dir[len] = 0; + } + path = last_slash; + } + else if (dir) + dir[0] = 0; + + for (p = (char *)path; *p; p++) + { + if (*p == '.') + dot = p; + } + + if (!dot) + dot = p; + + if (fname) + { + len = (unsigned int)(dot - path); + if (len > 0xFF) + len = 0xFF; + + Q_strncpy(fname, path, len); + fname[len] = 0; + } + + if (ext) + { + len = (unsigned int)(dot - path); + if (len > 0xFF) + len = 0xFF; + + Q_strncpy(ext, dot, len); + ext[len] = 0; + } + +#endif // _WIN32 +} + +/* <8d0c6> ../engine/sys_dll.c:2344 */ +void Con_Debug_f(void) +{ + if (con_debuglog) + { + Con_Printf("condebug disabled\n"); + con_debuglog = FALSE; + } + else + { + con_debuglog = TRUE; + Con_Printf("condebug enabled\n"); + } +} + +/* <8e069> ../engine/sys_dll.c:2364 */ +void Con_Init(void) +{ + con_debuglog = COM_CheckParm("-condebug"); + Con_DPrintf("Console initialized.\n"); + +#ifdef HOOK_ENGINE + Cmd_AddCommand("condebug", (xcommand_t)GetOriginalFuncAddrOrDefault("Con_Debug_f", (void *)Con_Debug_f)); +#else + Cmd_AddCommand("condebug", Con_Debug_f); +#endif +} + +/* <8dc81> ../engine/sys_dll.c:2385 */ +void Con_DebugLog(const char *file, const char *fmt, ...) +{ + va_list argptr; + static char data[8192]; + + va_start(argptr, fmt); + Q_vsnprintf(data, sizeof(data), fmt, argptr); + va_end(argptr); + + data[sizeof(data) - 1] = 0; + +#ifdef _WIN32 + + int fd = _open(file, _O_WRONLY | _O_APPEND | _O_CREAT, _S_IREAD | _S_IWRITE); + int len = Q_strlen(data); + _write(fd, data, len); + _close(fd); + +#else // _WIN32 + + FILE *fd = FS_Open(file, "at"); + FS_FPrintf(fd, "%s", data); + FS_Close(fd); + +#endif // _WIN32 +} + +/* <8dcfd> ../engine/sys_dll.c:2407 */ +void Con_Printf(const char *fmt, ...) +{ + char Dest[4096]; + va_list va; + + va_start(va, fmt); + Q_vsnprintf(Dest, sizeof(Dest), fmt, va); + va_end(va); + + Sys_Printf("%s", Dest); + if (sv_redirected) + { + if ((Q_strlen(outputbuf) + Q_strlen(Dest)) > sizeof(outputbuf) - 1) + SV_FlushRedirect(); + Q_strncat(outputbuf, Dest, sizeof(outputbuf) - 1); + } + else + { + if (con_debuglog) + Con_DebugLog("qconsole.log", "%s", Dest); +#ifndef SWDS + if (host_initialized && con_initialized && g_pcls.state) + { + if (developer.value != 0.0f) + { + Q_strncpy(g_szNotifyAreaString, msg, 255); + g_szNotifyAreaString[255] = 0; + *con_times = realtime; + } + VGuiWrap2_ConPrintf(msg); + } +#endif // SWDS + } +} + +/* <8dfae> ../engine/sys_dll.c:2442 */ +void Con_SafePrintf(const char *fmt, ...) +{ + va_list argptr; + va_start(argptr, fmt); + +#ifdef _WIN32 + char Dest[1024]; + Q_vsnprintf(Dest, sizeof(Dest), fmt, argptr); + va_end(argptr); + Con_Printf("%s", Dest); +#else + vfprintf(stdout, fmt, argptr); + va_end(argptr); + fflush(stdout); +#endif // _WIN32 +} + +/* <8e00b> ../engine/sys_dll.c:2459 */ +void Con_DPrintf(const char *fmt, ...) +{ + va_list argptr; + + va_start(argptr, fmt); + if (developer.value != 0.0f) + { +#ifdef _WIN32 + char Dest[4096]; + Q_vsnprintf(Dest, sizeof(Dest), fmt, argptr); + OutputDebugStringA(Dest); + if (con_debuglog) + Con_DebugLog("qconsole.log", "%s", Dest); +#else + vfprintf(stdout, fmt, argptr); + fflush(stdout); +#endif // _WIN32 + } + va_end(argptr); +} + diff --git a/rehlds/engine/sys_dll.h b/rehlds/engine/sys_dll.h new file mode 100644 index 0000000..1d9e368 --- /dev/null +++ b/rehlds/engine/sys_dll.h @@ -0,0 +1,194 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "maintypes.h" +#include "modinfo.h" +#include "FileSystem.h" +#include "pr_dlls.h" + +//vmodes.h must be included before cdll_int.h (wrect_t declaration) +#include "vmodes.h" +#include "cdll_int.h" + + +#ifdef _WIN32 +#define NOXREFCHECK __asm { push [ebp + 4] } Sys_Error(__FUNCTION__ " NOXREF, but called from 0x%.08x") +#else +#define NOXREFCHECK int *a = 0; *a = 0 +#endif + + +#define MAX_DISCONNECT_REASON 256 + + +#ifdef HOOK_ENGINE +#define g_hfind (*pg_hfind) + +#define g_engfuncsExportedToDlls (*pg_engfuncsExportedToDlls) + +#define gszDisconnectReason (*pgszDisconnectReason) +#define gszExtendedDisconnectReason (*pgszExtendedDisconnectReason) +#define gfExtendedError (*pgfExtendedError) +#define g_bIsDedicatedServer (*pg_bIsDedicatedServer) +#define giSubState (*pgiSubState) +#define giActive (*pgiActive) +#define giStateInfo (*pgiStateInfo) +#define gEntityInterface (*pgEntityInterface) +#define gNewDLLFunctions (*pgNewDLLFunctions) +#define g_modfuncs (*pg_modfuncs) +#define g_rgextdll (*pg_rgextdll) +#define g_iextdllMac (*pg_iextdllMac) +#define gmodinfo (*pgmodinfo) +#define gfBackground (*pgfBackground) + +#ifndef _WIN32 +#define gHasMMXTechnology (*pgHasMMXTechnology) +#endif + +#define con_debuglog (*pcon_debuglog) +#define g_bPrintingKeepAliveDots (*pg_bPrintingKeepAliveDots) +#define Launcher_ConsolePrintf (*pLauncher_ConsolePrintf) +#endif // HOOK_ENGINE + + +extern FileFindHandle_t g_hfind; +extern enginefuncs_t g_engfuncsExportedToDlls; + +extern char gszDisconnectReason[MAX_DISCONNECT_REASON]; +extern char gszExtendedDisconnectReason[MAX_DISCONNECT_REASON]; + +extern qboolean gfExtendedError; +extern qboolean g_bIsDedicatedServer; +extern int giSubState; +extern int giActive; +extern int giStateInfo; +extern DLL_FUNCTIONS gEntityInterface; +extern NEW_DLL_FUNCTIONS gNewDLLFunctions; +extern modfuncs_t g_modfuncs; + + +extern extensiondll_t g_rgextdll[50]; + +extern int g_iextdllMac; +extern modinfo_t gmodinfo; +extern qboolean gfBackground; + +#ifndef _WIN32 +extern qboolean gHasMMXTechnology; +#endif +extern qboolean g_bPrintingKeepAliveDots; + +extern qboolean con_debuglog; +extern void(*Launcher_ConsolePrintf)(char *, ...); + +#ifdef _WIN32 + #ifdef HOOK_ENGINE + #define g_PerfCounterInitialized (*pg_PerfCounterInitialized) + #define g_PerfCounterMutex (*pg_PerfCounterMutex) + + #define g_PerfCounterShiftRightAmount (*pg_PerfCounterShiftRightAmount) + #define g_PerfCounterSlice (*pg_PerfCounterSlice) + #define g_CurrentTime (*pg_CurrentTime) + #define g_StartTime (*pg_StartTime) + + #define g_FPUCW_Mask_Prec_64Bit (*pg_FPUCW_Mask_Prec_64Bit) + #define g_FPUCW_Mask_Prec_64Bit_2 (*pg_FPUCW_Mask_Prec_64Bit_2) + #define g_FPUCW_Mask_Round_Trunc (*pg_FPUCW_Mask_Round_Trunc) + #define g_FPUCW_Mask_Round_Up (*pg_FPUCW_Mask_Round_Up) + + #define g_WinNTOrHigher (*pg_WinNTOrHigher) + #endif + + extern int g_PerfCounterInitialized; + extern CRITICAL_SECTION g_PerfCounterMutex; + + extern int g_PerfCounterShiftRightAmount; + extern double g_PerfCounterSlice; + extern double g_CurrentTime; + extern double g_StartTime; + + extern int g_FPUCW_Mask_Prec_64Bit; + extern int g_FPUCW_Mask_Prec_64Bit_2; + extern int g_FPUCW_Mask_Round_Trunc; + extern int g_FPUCW_Mask_Round_Up; + + extern int g_WinNTOrHigher; +#endif //_WIN32 + +#ifdef _WIN32 + extern void __cdecl Sys_InitHardwareTimer(); +#endif //_WIN32 + +NOXREF void Sys_PageIn(void *ptr, int size); +const char *Sys_FindFirst(const char *path, char *basename); +const char *Sys_FindFirstPathID(const char *path, char *pathid); +const char *Sys_FindNext(char *basename); +void Sys_FindClose(void); +NOBODY int glob_match_after_star(char *pattern, char *text); +NOBODY int glob_match(char *pattern, char *text); +NOXREF void Sys_MakeCodeWriteable(uint32 startaddr, uint32 length); +NOBODY void Sys_SetFPCW(void); +NOBODY void Sys_PushFPCW_SetHigh(void); +NOBODY void Sys_PopFPCW(void); +NOBODY void MaskExceptions(void); +NOBODY void Sys_Init(void); +NOXREF void Sys_Sleep(int msec); +NOBODY void Sys_DebugOutStraight(const char *pStr); +NOBODY void __declspec(noreturn) Sys_Error(const char *error, ...); +NOXREF void Sys_Warning(const char *pszWarning, ...); +void Sys_Printf(const char *fmt, ...); +void Sys_Quit(void); +double Sys_FloatTime(void); +void Dispatch_Substate(int iSubState); +void GameSetSubState(int iSubState); +void GameSetState(int iState); +NOBODY void GameSetBackground(qboolean bNewSetting); +qboolean Voice_GetClientListening(int iReceiver, int iSender); +qboolean Voice_SetClientListening(int iReceiver, int iSender, qboolean bListen); +DISPATCHFUNCTION GetDispatch(char *pname); +const char *FindAddressInTable(extensiondll_t *pDll, uint32 function); +uint32 FindNameInTable(extensiondll_t *pDll, const char *pName); +NOBODY const char *ConvertNameToLocalPlatform(const char *pchInName); +uint32 FunctionFromName(const char *pName); +const char *NameForFunction(uint32 function); +ENTITYINIT GetEntityInit(char *pClassName); +FIELDIOFUNCTION GetIOFunction(char *pName); +NOBODY void DLL_SetModKey(modinfo_t *pinfo, char *pkey, char *pvalue); +void LoadEntityDLLs(const char *szBaseDir); +void LoadThisDll(const char *szDllFilename); +void ReleaseEntityDlls(void); +void EngineFprintf(void *pfile, const char *szFmt, ...); +void AlertMessage(ALERT_TYPE atype, const char *szFmt, ...); +NOXREF void Sys_SplitPath(const char *path, char *drive, char *dir, char *fname, char *ext); +void Con_Debug_f(void); +void Con_Init(void); +void Con_DebugLog(const char *file, const char *fmt, ...); +void Con_Printf(const char *fmt, ...); +void Con_SafePrintf(const char *fmt, ...); +void Con_DPrintf(const char *fmt, ...); diff --git a/rehlds/engine/sys_dll2.cpp b/rehlds/engine/sys_dll2.cpp new file mode 100644 index 0000000..6e67d49 --- /dev/null +++ b/rehlds/engine/sys_dll2.cpp @@ -0,0 +1,785 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#define FIFTEEN_MB (15 * 1024 * 1024) +#define MINIMUM_WIN_MEMORY 0x0e00000 +#define WARNING_MEMORY 0x0200000 +#define MAXIMUM_WIN_MEMORY 0x2800000 // Ask for 40 MB max +#define MAXIMUM_DEDICATED_MEMORY 0x2800000 // Ask for 40 MB max + +IDedicatedExports *dedicated_; +qboolean g_bIsWin95; +qboolean g_bIsWin98; +double g_flLastSteamProgressUpdateTime; + +//CEngineAPI __g_CEngineAPI_singleton; +//InterfaceReg __g_CreateCEngineAPIIEngineAPI_reg; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +char *szCommonPreloads = "multiplayer_preloads"; +char *szReslistsBaseDir = "reslists"; +char *szReslistsExt = ".lst"; + +#else //HOOK_ENGINE + +char *szCommonPreloads; +char *szReslistsBaseDir; +char *szReslistsExt; + +#endif //HOOK_ENGINE + +//CDedicatedServerAPI __g_CDedicatedServerAPI_singleton; +//InterfaceReg __g_CreateCDedicatedServerAPIIDedicatedServerAPI_reg + +/* <8fce7> ../engine/sys_dll2.cpp:150 */ +const char *GetCurrentSteamAppName(void) +{ + if (!Q_stricmp(com_gamedir, "cstrike") || !Q_stricmp(com_gamedir, "cstrike_beta")) + return "Counter-Strike"; + + else if (!Q_stricmp(com_gamedir, "valve")) + return "Half-Life"; + + else if (!Q_stricmp(com_gamedir, "ricochet")) + return "Ricochet"; + + else if (!Q_stricmp(com_gamedir, "dod")) + return "Day of Defeat"; + + else if (!Q_stricmp(com_gamedir, "tfc")) + return "Team Fortress Classic"; + + else if (!Q_stricmp(com_gamedir, "dmc")) + return "Deathmatch Classic"; + + else if (!Q_stricmp(com_gamedir, "czero")) + return "Condition Zero"; + + return "Half-Life"; +} + +/* <90345> ../engine/sys_dll2.cpp:184 */ +NOXREF void SetRateRegistrySetting(const char *pchRate) +{ + registry->WriteString("rate", pchRate); +} + +/* <9036c> ../engine/sys_dll2.cpp:189 */ +NOXREF const char *GetRateRegistrySetting(const char *pchDef) +{ + return registry->ReadString("rate", pchDef); +} + +/* <90397> ../engine/sys_dll2.cpp:198 */ +void EXPORT F(IEngineAPI **api) +{ + CreateInterfaceFn fn; + fn = Sys_GetFactoryThis(); + *api = (IEngineAPI *)fn("VENGINE_LAUNCHER_API_VERSION002", NULL); +} + +/* <903c2> ../engine/sys_dll2.cpp:245 */ +void Sys_GetCDKey(char *pszCDKey, int *nLength, int *bDedicated) +{ + char key[65]; + char hostname[4096]; + + if (CRehldsPlatformHolder::get()->gethostname(hostname, sizeof(hostname))) + Q_snprintf(key, sizeof(key), "%u", RandomLong(0, 0x7FFFFFFF)); + else + { + struct hostent *hostinfo; + hostinfo = CRehldsPlatformHolder::get()->gethostbyname(hostname); + if (hostinfo && hostinfo->h_length == 4 && *hostinfo->h_addr_list != NULL) + { + Q_snprintf(key, sizeof(key), "%u.%u.%u.%u", + (*hostinfo->h_addr_list)[0], + (*hostinfo->h_addr_list)[1], + (*hostinfo->h_addr_list)[2], + (*hostinfo->h_addr_list)[3]); + } + else + { + CRC32_t crc; + CRC32_ProcessBuffer(&crc, hostname, Q_strlen(hostname)); + Q_snprintf(key, sizeof(key), "%u", crc); + } + } + key[64] = 0; + Q_strcpy(pszCDKey, key); + + if (nLength) + *nLength = Q_strlen(key); + + if (bDedicated) + *bDedicated = 0; +} + +/* <9049d> ../engine/sys_dll2.cpp:287 */ +NOXREF void Legacy_ErrorMessage(int nLevel, const char *pszErrorMessage) +{ +} + +/* <90286> ../engine/sys_dll2.cpp:291 */ +void Legacy_Sys_Printf(char *fmt, ...) +{ + va_list argptr; + char text[1024]; + + va_start(argptr, fmt); + Q_vsnprintf(text, sizeof(text), fmt, argptr); + va_end(argptr); + + if (dedicated_) + dedicated_->Sys_Printf(text); +} + +/* <904d8> ../engine/sys_dll2.cpp:307 */ +NOXREF void Legacy_MP3subsys_Suspend_Audio(void) +{ +} + +/* <904f0> ../engine/sys_dll2.cpp:311 */ +NOXREF void Legacy_MP3subsys_Resume_Audio(void) +{ +} + +/* <90508> ../engine/sys_dll2.cpp:315 */ +void Sys_SetupLegacyAPIs(void) +{ +#ifndef SWDS + VID_FlipScreen = Sys_VID_FlipScreen; + D_SurfaceCacheForRes = Sys_GetSurfaceCacheSize; +#endif // SWDS + Launcher_ConsolePrintf = Legacy_Sys_Printf; +} + +/* <90518> ../engine/sys_dll2.cpp:335 */ +NOXREF int Sys_IsWin95(void) +{ +#ifdef _WIN32 + return g_bIsWin95; +#else + // TODO: no need to check is win + return 0; +#endif // _WIN32 +} + +/* <90534> ../engine/sys_dll2.cpp:340 */ +NOXREF int Sys_IsWin98(void) +{ +#ifdef _WIN32 + return g_bIsWin98; +#else + // TODO: no need to check is win + return 0; +#endif // _WIN32 +} + +/* <90550> ../engine/sys_dll2.cpp:348 */ +#ifdef _WIN32 +NOXREF void Sys_CheckOSVersion(void) +{ + struct _OSVERSIONINFOA verInfo; + + memset(&verInfo, 0, sizeof(verInfo)); + verInfo.dwOSVersionInfoSize = sizeof(verInfo); + if (!GetVersionExA(&verInfo)) + Sys_Error("Couldn't get OS info"); + + g_WinNTOrHigher = verInfo.dwMajorVersion >= 4; + if (verInfo.dwPlatformId == 1 && verInfo.dwMajorVersion == 4) + { + if (verInfo.dwMinorVersion) + { + if (verInfo.dwMinorVersion < 90) + g_bIsWin98 = 1; + } + else + { + g_bIsWin95 = 1; + } + } +} +#endif // _WIN32 + +/* <8fd53> ../engine/sys_dll2.cpp:397 */ +void Sys_Init(void) +{ +#ifndef SWDS + Sys_InitFloatTime(); +#endif +} + +/* <8fd7b> ../engine/sys_dll2.cpp:445 */ +void Sys_Shutdown(void) +{ +#ifndef SWDS + Sys_ShutdownFloatTime(); +#endif // SWDS + Steam_ShutdownClient(); +#ifdef _WIN32 + if (g_PerfCounterInitialized) + { + DeleteCriticalSection(&g_PerfCounterMutex); + g_PerfCounterInitialized = 0; + } +#else + #ifndef SWDS + GL_Shutdown(*pmainwindow, maindc, baseRC); + #endif // SWDS + +#endif // _WIN32 +} + +/* <90588> ../engine/sys_dll2.cpp:475 */ +void Sys_InitArgv(char *lpCmdLine) +{ + static char *argv[MAX_COMMAND_LINE_PARAMS]; + unsigned char c; +#ifdef REHLDS_FIXES + bool inQuotes; +#endif + + argv[0] = ""; + c = *lpCmdLine; + for (host_parms.argc = 1; c && host_parms.argc < MAX_COMMAND_LINE_PARAMS; c = *(++lpCmdLine)) + { +#ifdef REHLDS_FIXES + // Skip whitespace + while (c && c <= ' ') + { + lpCmdLine++; + c = *lpCmdLine; + } + if (!c) + { + break; + } + + // TODO: Add MultiByteToWideChar conversion under Windows, to correctly get UTF8, but need to alloc memory to store it + // Store arg pointer + argv[host_parms.argc] = lpCmdLine; + host_parms.argc++; + + // Find end of the argument + inQuotes = false; + while (c > ' ' || (c && inQuotes)) // FIXED: Do not break quoted arguments + { + if (c == '"') + { + inQuotes = !inQuotes; + } + lpCmdLine++; + c = *lpCmdLine; + } +#else // REHLDS_FIXES + // Skip whitespace and UTF8 + while (c && (c <= ' ' || c > '~')) + { + lpCmdLine++; + c = *lpCmdLine; + } + if (!c) + { + break; + } + + // Store arg pointer + argv[host_parms.argc] = lpCmdLine; + host_parms.argc++; + + // Find end of the argument + while (c > ' ' && c <= '~') + { + lpCmdLine++; + c = *lpCmdLine; + } +#endif // REHLDS_FIXES + if (!c) + { + break; + } + *lpCmdLine = 0; + } + + host_parms.argv = argv; + COM_InitArgv(host_parms.argc, argv); + host_parms.argc = com_argc; + host_parms.argv = com_argv; +} + +/* <8fd20> ../engine/sys_dll2.cpp:514 */ +NOXREF void Sys_ShutdownArgv(void) +{ +} + +/* <9066a> ../engine/sys_dll2.cpp:530 */ +void Sys_InitMemory(void) +{ + int i; + //bool bDidDefault;//unsued? + + i = COM_CheckParm("-heapsize"); + if (i && i < Cmd_Argc() - 1) + host_parms.memsize = atoi(Cmd_Argv(i + 1)) * 1024; + +#ifdef _WIN32 + MEMORYSTATUS lpBuffer; + if (host_parms.memsize < MINIMUM_WIN_MEMORY) + { + lpBuffer.dwLength = sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&lpBuffer); + + if (lpBuffer.dwTotalPhys) + { + if (lpBuffer.dwTotalPhys < FIFTEEN_MB) + Sys_Error("Available memory less than 15MB!!! %i", i); + + host_parms.memsize = (int)(lpBuffer.dwTotalPhys >> 1); + if ((signed int)host_parms.memsize < MINIMUM_WIN_MEMORY) + host_parms.memsize = MINIMUM_WIN_MEMORY; + } + else + host_parms.memsize = 0x8000000; + + if (g_bIsDedicatedServer) + host_parms.memsize = MAXIMUM_DEDICATED_MEMORY; + } +#else + if ((signed int)host_parms.memsize <= 0xDFFFFFu) + host_parms.memsize = MAXIMUM_DEDICATED_MEMORY; + +#endif // _WIN32 + + if ((signed int)host_parms.memsize > 0x8000000) + host_parms.memsize = 0x8000000; + + if (COM_CheckParm("-minmemory")) + host_parms.memsize = MINIMUM_WIN_MEMORY; +#ifdef _WIN32 + host_parms.membase = (void *)GlobalAlloc(GMEM_FIXED, host_parms.memsize); +#else + host_parms.membase = Mem_Malloc(host_parms.memsize); +#endif // _WIN32 + + if (!host_parms.membase) + Sys_Error("Unable to allocate %.2f MB\n", (float)(host_parms.memsize) / (1024.0f * 1024.0f)); +} + +/* <906c2> ../engine/sys_dll2.cpp:626 */ +void Sys_ShutdownMemory(void) +{ +#ifdef _WIN32 + GlobalFree((HGLOBAL)host_parms.membase); +#else + Mem_Free(host_parms.membase); +#endif // _WIN32 + host_parms.membase = NULL; + host_parms.memsize = 0; +} + +/* <906dd> ../engine/sys_dll2.cpp:644 */ +void Sys_InitLauncherInterface(void) +{ +#ifdef _WIN32 + //TODO: client-side code + Launcher_ConsolePrintf = Legacy_Sys_Printf; +#else + #ifndef SWDS + gHasMMXTechnology = TRUE; + #endif + + Sys_SetupLegacyAPIs(); +#endif // _WIN32 +} + +/* <90702> ../engine/sys_dll2.cpp:666 */ +NOXREF void Sys_ShutdownLauncherInterface(void) +{ +} + +/* <90712> ../engine/sys_dll2.cpp:673 */ +void Sys_InitAuthentication(void) +{ + Sys_Printf("STEAM Auth Server\r\n"); +} + +/* <8fd71> ../engine/sys_dll2.cpp:678 */ +NOXREF void Sys_ShutdownAuthentication(void) +{ +} + +/* <9073d> ../engine/sys_dll2.cpp:694 */ +void Sys_ShowProgressTicks(char *specialProgressMsg) +{ + static bool recursionGuard = false; + static int32 numTics = 0; + + double currentTime; + if (!recursionGuard) + { + recursionGuard = true; + if (COM_CheckParm("-steam")) + { + currentTime = Sys_FloatTime(); + + if (g_flLastSteamProgressUpdateTime + 2.0 <= currentTime) + { + g_flLastSteamProgressUpdateTime = currentTime; + numTics++; + if (g_bIsDedicatedServer) + { + if (g_bMajorMapChange) + { + g_bPrintingKeepAliveDots = TRUE; + Sys_Printf("."); + recursionGuard = false; + return; + } + } + else + { + int i; + int numTicsToPrint = (numTics % 5 + 1); + char msg[128]; + + Q_strncpy(msg, "Updating game resources", sizeof(msg) - 1); + msg[sizeof(msg) - 1] = '\0'; + + for (i = 1; i < numTicsToPrint; i++) + { + Q_strncat(msg, ".", sizeof(msg) - 1); + msg[sizeof(msg) - 1] = '\0'; + } + SetLoadingProgressBarStatusText(msg); + } + } + } + recursionGuard = false; + } +} + +/* <907de> ../engine/sys_dll2.cpp:748 */ +int Sys_InitGame(char *lpOrgCmdLine, char *pBaseDir, void *pwnd, int bIsDedicated) +{ + host_initialized = FALSE; + +#ifndef SWDS + if (!bIsDedicated) + { + pmainwindow = (HWND *)pwnd; +#ifdef _WIN32 + videomode->UpdateWindowPosition(); +#endif // _WIN32 + } +#endif // SWDS + g_bIsDedicatedServer = bIsDedicated; + memset(&gmodinfo, 0, sizeof(modinfo_t)); + SV_ResetModInfo(); + TraceInit("Sys_Init()", "Sys_Shutdown()", 0); + +#ifdef _WIN32 + Sys_InitHardwareTimer(); +#endif // _WIN32 + +#ifndef SWDS + Sys_InitFloatTime(); +#endif // SWDS + FS_LogLevelLoadStarted("Launcher"); + SeedRandomNumberGenerator(); + TraceInit("Sys_InitMemory()", "Sys_ShutdownMemory()", 0); + Sys_InitMemory(); + TraceInit("Sys_InitLauncherInterface()", "Sys_ShutdownLauncherInterface()", 0); + Sys_InitLauncherInterface(); + +#ifndef SWDS + if (!GL_SetMode(*pmainwindow, &maindc, &baseRC)) + return 0; +#endif // SWDS + TraceInit("Host_Init( &host_parms )", "Host_Shutdown()", 0); + Host_Init(&host_parms); + if (!host_initialized) + return 0; + + TraceInit("Sys_InitAuthentication()", "Sys_ShutdownAuthentication()", 0); + Sys_InitAuthentication(); + if (g_bIsDedicatedServer) + { + Host_InitializeGameDLL(); + NET_Config(TRUE); + } + +#ifndef SWDS + else + ClientDLL_ActivateMouse(); + + char MessageText[512]; + const char en_US[12]; + + Q_strcpy(en_US, "en_US.UTF-8"); + en_US[16] = 0; + + char *cat = setlocale(6, NULL); + if (!cat) + cat = "c"; + + if (Q_stricmp(cat, en_US) ) + { + Q_snprintf(MessageText, sizeof(MessageText), "SetLocale('%s') failed. Using '%s'.\nYou may have limited glyph support.\nPlease install '%s' locale.", en_US, cat, en_US); + SDL_ShowSimpleMessageBox(0, "Warning", MessageText, *pmainwindow); + } +#endif // SWDS + return 1; +} + +/* <90871> ../engine/sys_dll2.cpp:841 */ +void Sys_ShutdownGame(void) +{ + if (!g_bIsDedicatedServer) + ClientDLL_DeactivateMouse(); + + TraceShutdown("Host_Shutdown()", 0); + Host_Shutdown(); + + if (g_bIsDedicatedServer) + NET_Config(FALSE); + + TraceShutdown("Sys_ShutdownLauncherInterface()", 0); + TraceShutdown("Sys_ShutdownAuthentication()", 0); + TraceShutdown("Sys_ShutdownMemory()", 0); + Sys_ShutdownMemory(); + TraceShutdown("Sys_Shutdown()", 0); + Sys_Shutdown(); +} + +/* <9089f> ../engine/sys_dll2.cpp:869 */ +void ClearIOStates(void) +{ +#ifndef SWDS + int i; + for (i = 0; i < 256; i++) + { + Key_Event(i, false); + } + Key_ClearStates(); + ClientDLL_ClearStates(); +#endif // SWDS +} + + +/* <8f74a> ../engine/sys_dll2.cpp:982 */ +class CEngineAPI : public IEngineAPI +{ +public: + /* <8f797> ../engine/sys_dll2.cpp:1004 */ + int Run(void *instance, char *basedir, char *cmdline, char *postRestartCmdLineArgs, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) + { + return 0; + } +}; + +static CEngineAPI g_CEngineAPI; + +/* <8ff0c> ../engine/sys_dll2.cpp:1034 */ +IBaseInterface *CreateCEngineAPI(void) +{ + return &g_CEngineAPI; +}; + +InterfaceReg g_CreateCEngineAPI = InterfaceReg(CreateCEngineAPI, "VENGINE_LAUNCHER_API_VERSION002"); + +/* <908b7> ../engine/sys_dll2.cpp:1070 */ +NOXREF int BuildMapCycleListHints(char **hints) +{ + char szMap[262]; + unsigned int length; + char *pFileList; + char szMod[MAX_PATH]; + char cszMapCycleTxtFile[MAX_PATH]; + FileHandle_t pFile; + + COM_FileBase(com_gamedir, szMod); + Q_sprintf(cszMapCycleTxtFile, "%s/%s", szMod, mapcyclefile.string); + pFile = FS_Open(cszMapCycleTxtFile, "rb"); + if (!pFile) + { + Con_Printf("Unable to open %s\n", cszMapCycleTxtFile); + return 0; + } + Q_sprintf(szMap, "%s\\%s\\%s%s\r\n", szReslistsBaseDir, GetCurrentSteamAppName(), szCommonPreloads, szReslistsExt); + + *hints = (char *)Mem_Malloc(strlen(szMap) + 1); + if (*hints == NULL) + { + Con_Printf("Unable to allocate memory for map cycle hints list"); + return 0; + } + strcpy(*hints, szMap); + length = FS_Size(pFile); + if (length) + { + pFileList = (char *)malloc(length); + if (pFileList && FS_Read(pFileList, length, 0, pFile) != 1) + { + while (1) + { + pFileList = COM_Parse(pFileList); + if (strlen(com_token) <= 0) + { + Mem_Free(*hints); + break; + } + + Q_strncpy(szMap, com_token, sizeof(szMap) - 1); + szMap[sizeof(szMap) - 1] = '\0'; + + if (COM_TokenWaiting(pFileList)) + pFileList = COM_Parse(pFileList); + + char mapLine[sizeof(szMap)]; + Q_snprintf(mapLine, sizeof(mapLine), "%s\\%s\\%s%s\r\n", szReslistsBaseDir, szMod, szMap, szReslistsExt); + + *hints = (char *)Mem_Realloc(*hints, strlen(*hints) + 1 + strlen(mapLine) + 1); + if (*hints == NULL) + { + Con_Printf("Unable to reallocate memory for map cycle hints list"); + return 0; + } + Q_strcat(*hints, mapLine); + } + } + } + FS_Close(pFile); + Q_sprintf(szMap, "%s\\%s\\mp_maps.txt\r\n", szReslistsBaseDir, GetCurrentSteamAppName()); + *hints = (char *)Mem_Realloc(*hints, strlen(*hints) + 1 + strlen(szMap) + 1); + Q_strcat(*hints, szMap); + return 1; +} + +bool CDedicatedServerAPI::Init(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) +{ + return Init_noVirt(basedir, cmdline, launcherFactory, filesystemFactory); +} + +bool CDedicatedServerAPI::Init_noVirt(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) +{ + dedicated_ = (IDedicatedExports *)launcherFactory(VENGINE_DEDICATEDEXPORTS_API_VERSION, NULL); + if (!dedicated_) + return false; + + strcpy(this->m_OrigCmd, cmdline); + if (!strstr(cmdline, "-nobreakpad")) + { + CRehldsPlatformHolder::get()->SteamAPI_UseBreakpadCrashHandler(va("%d", build_number()), "Aug 8 2013", "11:17:26", 0, 0, 0); + } + TraceInit("Sys_InitArgv( m_OrigCmd )", "Sys_ShutdownArgv()", 0); + Sys_InitArgv(m_OrigCmd); + eng->SetQuitting(IEngine::QUIT_NOTQUITTING); + registry->Init(); + + g_bIsDedicatedServer = TRUE; + TraceInit("FileSystem_Init(basedir, (void *)filesystemFactory)", "FileSystem_Shutdown()", 0); + if (FileSystem_Init(basedir, filesystemFactory) && game->Init(0) && eng->Load(true, basedir, cmdline)) + { + char text[256]; + Q_snprintf(text, ARRAYSIZE(text), "exec %s\n", servercfgfile.string); + text[255] = 0; + Cbuf_InsertText(text); + return true; + } + + return false; +} + +int CDedicatedServerAPI::Shutdown(void) +{ + return Shutdown_noVirt(); +} + +int CDedicatedServerAPI::Shutdown_noVirt(void) +{ + eng->Unload(); + game->Shutdown(); + + TraceShutdown("FileSystem_Shutdown()", 0); + FileSystem_Shutdown(); + + registry->Shutdown(); + + TraceShutdown("Sys_ShutdownArgv()", 0); + dedicated_ = NULL; + return giActive; +} + +bool CDedicatedServerAPI::RunFrame(void) +{ + return RunFrame_noVirt(); +} + +bool CDedicatedServerAPI::RunFrame_noVirt(void) +{ + if (eng->GetQuitting()) + return false; + + eng->Frame(); + return true; +} + +void CDedicatedServerAPI::AddConsoleText(char *text) +{ + AddConsoleText_noVirt(text); +} + +void CDedicatedServerAPI::AddConsoleText_noVirt(char *text) +{ + Cbuf_AddText(text); +} + +void CDedicatedServerAPI::UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap) +{ + UpdateStatus_noVirt(fps, nActive, nMaxPlayers, pszMap); +} + +void CDedicatedServerAPI::UpdateStatus_noVirt(float *fps, int *nActive, int *nMaxPlayers, char *pszMap) +{ + Host_GetHostInfo(fps, nActive, NULL, nMaxPlayers, pszMap); +} + +#ifndef HOOK_ENGINE + +EXPOSE_SINGLE_INTERFACE(CDedicatedServerAPI, IDedicatedServerAPI, VENGINE_HLDS_API_VERSION); + +#endif //HOOK_ENGINE + diff --git a/rehlds/engine/sys_dll2.h b/rehlds/engine/sys_dll2.h new file mode 100644 index 0000000..fed5bdb --- /dev/null +++ b/rehlds/engine/sys_dll2.h @@ -0,0 +1,122 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SYS_DLL2_H +#define SYS_DLL2_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "interface.h" +#include "tier0/platform.h" + +#include "engine_hlds_api.h" +#include "engine_launcher_api.h" +#include "idedicatedexports.h" + +#ifdef HOOK_ENGINE +#define dedicated_ (*pdedicated) +#define g_bIsWin95 (*pg_bIsWin95) +#define g_bIsWin98 (*pg_bIsWin98) +#define g_flLastSteamProgressUpdateTime (*pg_flLastSteamProgressUpdateTime) +#define szCommonPreloads (*pszCommonPreloads) +#define szReslistsBaseDir (*pszReslistsBaseDir) +#define szReslistsExt (*pszReslistsExt) +#endif + +extern IDedicatedExports *dedicated_; +extern qboolean g_bIsWin95; +extern qboolean g_bIsWin98; +extern double g_flLastSteamProgressUpdateTime; +extern char *szCommonPreloads; +extern char *szReslistsBaseDir; +extern char *szReslistsExt; + +class CDedicatedServerAPI : public IDedicatedServerAPI +{ +private: + char m_OrigCmd[1024]; + +public: + + virtual bool Init(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory); + bool Init_noVirt(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory); + + virtual int Shutdown(void); + int Shutdown_noVirt(void); + + virtual bool RunFrame(void); + bool RunFrame_noVirt(void); + + virtual void AddConsoleText(char *text); + void AddConsoleText_noVirt(char *text); + + virtual void UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap); + void UpdateStatus_noVirt(float *fps, int *nActive, int *nMaxPlayers, char *pszMap); +}; + +const char *GetCurrentSteamAppName(void); +NOXREF void SetRateRegistrySetting(const char *pchRate); +NOXREF const char *GetRateRegistrySetting(const char *pchDef); +void EXPORT F(IEngineAPI **api); +void Sys_GetCDKey(char *pszCDKey, int *nLength, int *bDedicated); +NOXREF void Legacy_ErrorMessage(int nLevel, const char *pszErrorMessage); +void Legacy_Sys_Printf(char *fmt, ...); +NOXREF void Legacy_MP3subsys_Suspend_Audio(void); +NOXREF void Legacy_MP3subsys_Resume_Audio(void); +void Sys_SetupLegacyAPIs(void); +NOXREF int Sys_IsWin95(void); +NOXREF int Sys_IsWin98(void); + +#ifdef _WIN32 +NOXREF void Sys_CheckOSVersion(void); +#endif + +NOXREF void Sys_Init(void); +NOXREF void Sys_Shutdown(void); +void Sys_InitArgv(char *lpCmdLine); +NOXREF void Sys_ShutdownArgv(void); +void Sys_InitMemory(void); +void Sys_ShutdownMemory(void); +void Sys_InitLauncherInterface(void); +NOXREF void Sys_ShutdownLauncherInterface(void); +void Sys_InitAuthentication(void); +NOXREF void Sys_ShutdownAuthentication(void); +void Sys_ShowProgressTicks(char *specialProgressMsg); +int Sys_InitGame(char *lpOrgCmdLine, char *pBaseDir, void *pwnd, int bIsDedicated); +void Sys_ShutdownGame(void); +void ClearIOStates(void); + +NOBODY class IBaseInterface *__CreateCEngineAPIIEngineAPI_interface(void); +NOXREF int BuildMapCycleListHints(char **hints); + +NOBODY class IBaseInterface *__CreateCDedicatedServerAPIIDedicatedServerAPI_interface(void); +NOBODY void _GLOBAL__sub_I_D_SurfaceCacheForRes(void); + +#endif // SYS_DLL2_H diff --git a/rehlds/engine/sys_engine.cpp b/rehlds/engine/sys_engine.cpp new file mode 100644 index 0000000..6ba3525 --- /dev/null +++ b/rehlds/engine/sys_engine.cpp @@ -0,0 +1,335 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +// sleep time when not focus +#define NOT_FOCUS_SLEEP 50 +#define MINIMIZED_SLEEP 20 + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +CEngine g_Engine; +IEngine *eng = &g_Engine; + +#else // HOOK_ENGINE + +IEngine *eng; + +#endif // HOOK_ENGINE + +/* <95a20> ../engine/sys_engine.cpp:145 */ +CEngine::CEngine() +{ + m_fFrameTime = 0.0; + m_nSubState = 0; + m_nDLLState = DLL_INACTIVE; + m_fOldTime = 0.0; + m_bTrapMode = false; + m_bDoneTrapping = false; + m_nTrapKey = 0; + m_nTrapButtons = 0; + m_nQuitting = QUIT_NOTQUITTING; +} + +/* <95a38> ../engine/sys_engine.cpp:164 */ +CEngine::~CEngine() +{ +} + +/* <95a92> ../engine/sys_engine.cpp:171 */ +void CEngine::Unload() +{ + Unload_noVirt(); +} + +void CEngine::Unload_noVirt() +{ + Sys_ShutdownGame(); + m_nDLLState = DLL_INACTIVE; +} + +void ForceReloadProfile() +{ + Cbuf_AddText("exec config.cfg\n"); + Cbuf_AddText("+mlook\n"); + Cbuf_Execute(); + if (COM_CheckParm("-nomousegrab")) + Cvar_Set("cl_mousegrab", "0"); + + //Key_SetBinding(126, "toggleconsole"); + //Key_SetBinding(96, "toggleconsole"); + //Key_SetBinding(27, "cancelselect"); + //SDL_GL_SetSwapInterval((gl_vsync.value <= 0.0) - 1); + if (g_pcls.state != ca_dedicated) + { + Sys_Error("Only dedicated mode is supported"); + /* + v0 = GetRateRegistrySetting(rate.string); + strncpy(szRate, v0, 0x20u); + Cvar_DirectSet(&rate, szRate); + */ + } +} + +bool CEngine::Load(bool dedicated, char *basedir, char *cmdline) +{ + return Load_noVirt(dedicated, basedir, cmdline); +} + +bool CEngine::Load_noVirt(bool dedicated, char *basedir, char *cmdline) +{ + bool success = false; + SetState(DLL_ACTIVE); + if (Sys_InitGame(cmdline, basedir, game->GetMainWindowAddress(), dedicated)) + { + success = true; +#ifdef _WIN32 + ForceReloadProfile(); +#endif // _WIN32 + } + return success; +} + +int CEngine::Frame() +{ + return Frame_noVirt(); +} + +int CEngine::Frame_noVirt() +{ +#ifndef SWDS + (*(void(**)(void))(*(_DWORD *)cdaudio + 24))(); +#endif // SWDS + + if (!game->IsActiveApp()) + game->SleepUntilInput(m_nDLLState != DLL_PAUSED ? MINIMIZED_SLEEP : NOT_FOCUS_SLEEP); + + m_fCurTime = Sys_FloatTime(); + m_fFrameTime = m_fCurTime - m_fOldTime; + m_fOldTime = m_fCurTime; + if (m_fFrameTime < 0.0) + { + m_fFrameTime = 0.001; + } + + if (m_nDLLState == DLL_INACTIVE) + return m_nDLLState; + + int dummy; + int iState = Host_Frame(m_fFrameTime, m_nDLLState, &dummy); + if (iState == m_nDLLState) + return m_nDLLState; + + SetState(iState); + if (m_nDLLState == DLL_CLOSE) + { + SetQuitting(QUIT_TODESKTOP); + } + else if (m_nDLLState == DLL_RESTART) + { + SetQuitting(QUIT_RESTART); + } + + return m_nDLLState; +} + +/* <96468> ../engine/sys_engine.cpp:274 */ +void CEngine::SetSubState(int iSubState) +{ + SetSubState_noVirt(iSubState); +} + +void CEngine::SetSubState_noVirt(int iSubState) +{ + if (iSubState != 1) + GameSetSubState(iSubState); +} + +/* <96433> ../engine/sys_engine.cpp:286 */ +void CEngine::SetState(int iState) +{ + SetState_noVirt(iState); +} + +void CEngine::SetState_noVirt(int iState) +{ + m_nDLLState = iState; + GameSetState(iState); +} + +/* <95ae0> ../engine/sys_engine.cpp:296 */ +int CEngine::GetState() +{ + return GetState_noVirt(); +} + +int CEngine::GetState_noVirt() +{ + return m_nDLLState; +} + +/* <95b33> ../engine/sys_engine.cpp:305 */ +int CEngine::GetSubState() +{ + return GetSubState_noVirt(); +} + +int CEngine::GetSubState_noVirt() +{ + return m_nSubState; +} + +/* <95b84> ../engine/sys_engine.cpp:314 */ +double CEngine::GetFrameTime() +{ + return GetFrameTime_noVirt(); +} + +double CEngine::GetFrameTime_noVirt() +{ + return m_fFrameTime; +} + +/* <95bad> ../engine/sys_engine.cpp:323 */ +double CEngine::GetCurTime() +{ + return GetCurTime_noVirt(); +} + +double CEngine::GetCurTime_noVirt() +{ + return m_fCurTime; +} + +/* <96348> ../engine/sys_engine.cpp:333 */ +void CEngine::TrapKey_Event(int key, bool down) +{ + TrapKey_Event_noVirt(key, down); +} + +void CEngine::TrapKey_Event_noVirt(int key, bool down) +{ +} + +/* <960ca> ../engine/sys_engine.cpp:356 */ +void CEngine::TrapMouse_Event(int buttons, bool down) +{ + TrapMouse_Event_noVirt(buttons, down); +} + +void CEngine::TrapMouse_Event_noVirt(int buttons, bool down) +{ + if (m_bTrapMode && buttons && !down) + { + m_bTrapMode = false; + m_bDoneTrapping = true; + m_nTrapKey = 0; + m_nTrapButtons = buttons; + } + else + { + ClientDLL_MouseEvent(buttons); + } +} + +/* <95c34> ../engine/sys_engine.cpp:376 */ +void CEngine::StartTrapMode() +{ + StartTrapMode_noVirt(); +} + +void CEngine::StartTrapMode_noVirt() +{ + if (!m_bTrapMode) + { + m_bDoneTrapping = false; + m_bTrapMode = true; + } +} + +/* <95c59> ../engine/sys_engine.cpp:389 */ +bool CEngine::IsTrapping() +{ + return IsTrapping_noVirt(); +} + +bool CEngine::IsTrapping_noVirt() +{ + return m_bTrapMode; +} + +/* <96100> ../engine/sys_engine.cpp:400 */ +bool CEngine::CheckDoneTrapping(int & buttons, int & key) +{ + return CheckDoneTrapping_noVirt(buttons, key); +} + +bool CEngine::CheckDoneTrapping_noVirt(int & buttons, int & key) +{ + if (m_bTrapMode) + { + return false; + } + else if (m_bDoneTrapping) + { + m_bDoneTrapping = false; + key = m_nTrapKey; + buttons = m_nTrapButtons; + return true; + } + else + { + return false; + } +} + +/* <963d8> ../engine/sys_engine.cpp:419 */ +void CEngine::SetQuitting(int quittype) +{ + SetQuitting_noVirt(quittype); +} + +void CEngine::SetQuitting_noVirt(int quittype) +{ + m_nQuitting = quittype; +} + +/* <9640d> ../engine/sys_engine.cpp:427 */ +int CEngine::GetQuitting() +{ + return GetQuitting_noVirt(); +} + +int CEngine::GetQuitting_noVirt() +{ + return m_nQuitting; +} diff --git a/rehlds/engine/sys_engine.h b/rehlds/engine/sys_engine.h new file mode 100644 index 0000000..1a91cc8 --- /dev/null +++ b/rehlds/engine/sys_engine.h @@ -0,0 +1,137 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + + +#include "maintypes.h" +#include "igame.h" +#include "iengine.h" + +#ifdef HOOK_ENGINE +#define game (*pgame) +#define eng (*peng) +#endif // HOOK_ENGINE + +extern IGame* game; +extern IEngine* eng; + + +/* <95955> ../engine/sys_engine.cpp:92 */ +class CEngine : public IEngine +{ +private: + + int m_nQuitting; /* 4 4 */ + int m_nDLLState; /* 8 4 */ + int m_nSubState; /* 12 4 */ + double m_fCurTime; /* 16 8 */ + double m_fFrameTime; /* 24 8 */ + double m_fOldTime; /* 32 8 */ + bool m_bTrapMode; /* 40 1 */ + bool m_bDoneTrapping; /* 41 1 */ + int m_nTrapKey; /* 44 4 */ + int m_nTrapButtons; /* 48 4 */ + +public: + + CEngine(); + virtual ~CEngine(); + + virtual bool Load(bool dedicated, char *rootDir, char *cmdLine); + bool Load_noVirt(bool dedicated, char *rootDir, char *cmdLine); + + virtual void Unload(); + void Unload_noVirt(); + + virtual void SetState(int iState); + void SetState_noVirt(int iState); + + virtual int GetState(); + int GetState_noVirt(); + + virtual void SetSubState(int iSubstate); + void SetSubState_noVirt(int iSubstate); + + virtual int GetSubState(); + int GetSubState_noVirt(); + + virtual int Frame(); + int Frame_noVirt(); + + virtual double GetFrameTime(); + double GetFrameTime_noVirt(); + + virtual double GetCurTime(); + double GetCurTime_noVirt(); + + virtual void TrapKey_Event(int key, bool down); + void TrapKey_Event_noVirt(int key, bool down); + + virtual void TrapMouse_Event(int buttons, bool down); + void TrapMouse_Event_noVirt(int buttons, bool down); + + virtual void StartTrapMode(); + void StartTrapMode_noVirt(); + + virtual bool IsTrapping(); + bool IsTrapping_noVirt(); + + virtual bool CheckDoneTrapping(int& buttons, int& keys); + bool CheckDoneTrapping_noVirt(int& buttons, int& keys); + + virtual int GetQuitting(); + int GetQuitting_noVirt(); + + virtual void SetQuitting(int quittype); + void SetQuitting_noVirt(int quittype); + + /* vtable has 16 entries: { + [2] = Load(_ZN7CEngine4LoadEbPcS0_), + [3] = Unload(_ZN7CEngine6UnloadEv), + [4] = SetState(_ZN7CEngine8SetStateEi), + [5] = GetState(_ZN7CEngine8GetStateEv), + [6] = SetSubState(_ZN7CEngine11SetSubStateEi), + [7] = GetSubState(_ZN7CEngine11GetSubStateEv), + [8] = Frame(_ZN7CEngine5FrameEv), + [9] = GetFrameTime(_ZN7CEngine12GetFrameTimeEv), + [10] = GetCurTime(_ZN7CEngine10GetCurTimeEv), + [11] = TrapKey_Event(_ZN7CEngine13TrapKey_EventEib), + [12] = TrapMouse_Event(_ZN7CEngine15TrapMouse_EventEib), + [13] = StartTrapMode(_ZN7CEngine13StartTrapModeEv), + [14] = IsTrapping(_ZN7CEngine10IsTrappingEv), + [15] = CheckDoneTrapping(_ZN7CEngine17CheckDoneTrappingERiS0_), + [16] = GetQuitting(_ZN7CEngine11GetQuittingEv), + [17] = SetQuitting(_ZN7CEngine11SetQuittingEi), + } */ + /* size: 52, cachelines: 1, members: 11 */ + /* last cacheline: 52 bytes */ + + /* BRAIN FART ALERT! 52 != 50 + 0(holes), diff = 2 */ + +}; /* size: 52 */ diff --git a/rehlds/engine/sys_linuxwind.cpp b/rehlds/engine/sys_linuxwind.cpp new file mode 100644 index 0000000..83abcb8 --- /dev/null +++ b/rehlds/engine/sys_linuxwind.cpp @@ -0,0 +1,194 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +CGame g_Game; +IGame *game = &g_Game; + +#else //HOOK_ENGINE + +IGame *game; + +#endif //HOOK_ENGINE + +CGame::CGame() +{ + m_bActiveApp = true; +} + +CGame::~CGame() +{ +} + +bool CGame::Init(void *pvInstance) +{ + return Init_noVirt(pvInstance); +} + +bool CGame::Init_noVirt(void *pvInstance) +{ + return true; +} + +bool CGame::Shutdown() +{ + return Shutdown_noVirt(); +} + +bool CGame::Shutdown_noVirt() +{ + return true; +} + +bool CGame::CreateGameWindow() +{ + return CreateGameWindow_noVirt(); +} + +bool CGame::CreateGameWindow_noVirt() +{ + return true; +} + +void CGame::SleepUntilInput(int time) +{ + SleepUntilInput_noVirt(time); +} + +void CGame::SleepUntilInput_noVirt(int time) +{ +#ifdef _WIN32 + Sleep(time * 1000); +#else // _WIN32 + sleep(time); +#endif // _WIN32 +} + +HWND CGame::GetMainWindow() +{ + return GetMainWindow_noVirt(); +} + +HWND CGame::GetMainWindow_noVirt() +{ + return NULL; +} + +HWND * CGame::GetMainWindowAddress() +{ + return GetMainWindowAddress_noVirt(); +} + +HWND * CGame::GetMainWindowAddress_noVirt() +{ + return NULL; +} + +void CGame::SetWindowXY(int x, int y) +{ + SetWindowXY_noVirt(x, y); +} + +void CGame::SetWindowXY_noVirt(int x, int y) +{ +} + +void CGame::SetWindowSize(int w, int h) +{ + SetWindowSize_noVirt(w, h); +} + +void CGame::SetWindowSize_noVirt(int w, int h) +{ +} + +void CGame::GetWindowRect(int *x, int *y, int *w, int *h) +{ + GetWindowRect_noVirt(x, y, w, h); +} + +void CGame::GetWindowRect_noVirt(int *x, int *y, int *w, int *h) +{ + if (x) *x = 0; + if (y) *y = 0; + if (w) *w = 0; + if (h) *h = 0; +} + +bool CGame::IsActiveApp() +{ + return IsActiveApp_noVirt(); +} + +bool CGame::IsActiveApp_noVirt() +{ + return m_bActiveApp; +} + +bool CGame::IsMultiplayer() +{ + return IsMultiplayer_noVirt(); +} + +bool CGame::IsMultiplayer_noVirt() +{ + return true; +} + +void CGame::PlayStartupVideos() +{ + return PlayStartupVideos_noVirt(); +} + +void CGame::PlayStartupVideos_noVirt() +{ +} + +void CGame::PlayAVIAndWait(const char *aviFile) +{ + PlayAVIAndWait_noVirt(aviFile); +} + +void CGame::PlayAVIAndWait_noVirt(const char *aviFile) +{ +} + +void CGame::SetCursorVisible(bool vis) +{ + SetCursorVisible_noVirt(vis); +} + +void CGame::SetCursorVisible_noVirt(bool vis) +{ +} diff --git a/rehlds/engine/sys_linuxwnd.h b/rehlds/engine/sys_linuxwnd.h new file mode 100644 index 0000000..39e5eef --- /dev/null +++ b/rehlds/engine/sys_linuxwnd.h @@ -0,0 +1,85 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "maintypes.h" +#include "igame.h" + +class CGame : public IGame { +private: + bool m_bActiveApp; /* 4 1 */ + +public: + + CGame(); + + virtual ~CGame(); + + virtual bool Init(void *pvInstance); + bool Init_noVirt(void *pvInstance); + + virtual bool Shutdown(); + bool Shutdown_noVirt(); + + virtual bool CreateGameWindow(); + bool CreateGameWindow_noVirt(); + + virtual void SleepUntilInput(int time); + void SleepUntilInput_noVirt(int time); + + virtual HWND GetMainWindow(); + HWND GetMainWindow_noVirt(); + + virtual HWND * GetMainWindowAddress(); + HWND * GetMainWindowAddress_noVirt(); + + virtual void SetWindowXY(int x, int y); + void SetWindowXY_noVirt(int x, int y); + + virtual void SetWindowSize(int w, int h); + void SetWindowSize_noVirt(int w, int h); + + virtual void GetWindowRect(int *x, int *y, int *w, int *h); + void GetWindowRect_noVirt(int *x, int *y, int *w, int *h); + + virtual bool IsActiveApp(); + bool IsActiveApp_noVirt(); + + virtual bool IsMultiplayer(); + bool IsMultiplayer_noVirt(); + + virtual void PlayStartupVideos(); + void PlayStartupVideos_noVirt(); + + virtual void PlayAVIAndWait(const char *aviFile); + void PlayAVIAndWait_noVirt(const char *aviFile); + + virtual void SetCursorVisible(bool vis); + void SetCursorVisible_noVirt(bool vis); +}; diff --git a/rehlds/engine/textures.cpp b/rehlds/engine/textures.cpp new file mode 100644 index 0000000..4f20625 --- /dev/null +++ b/rehlds/engine/textures.cpp @@ -0,0 +1,245 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +texlumpinfo_t* lumpinfo; +int nTexLumps; +FILE* texfiles[128]; +int nTexFiles; + +unsigned char texgammatable[256]; +texture_t * r_notexture_mip; + +int nummiptex; +char miptex[512][64]; + + + +/* + * Globals initialization + */ +#ifndef HOOK_ENGINE + +cvar_t r_wadtextures = { "r_wadtextures", "0", 0, 0.0f, NULL }; + +#else //HOOK_ENGINE + +cvar_t r_wadtextures; + +#endif //HOOK_ENGINE + +/* ../engine/textures.c:35 */ +void SafeRead(FileHandle_t f, void *buffer, int count) +{ + if (FS_Read(buffer, count, 1, f) != count) + Sys_Error("File read failure"); +} + +void CleanupName(char *in, char *out) +{ + int i = 0; + while (in[i] && i < 16) { + out[i] = toupper(in[i]); + i++; + } + + while (i < 16) { + out[i++] = 0; + } +} + +/* ../engine/textures.c:64 */ +int lump_sorter(const void *lump1, const void *lump2) +{ + const texlumpinfo_t *plump1 = (const texlumpinfo_t *)lump1; + const texlumpinfo_t *plump2 = (const texlumpinfo_t *)lump2; + return strcmp(plump1->lump.name, plump2->lump.name); +} + +/* ../engine/textures.c:72 */ +void ForwardSlashes(char *pname) +{ + while (*pname) { + if (*pname == '\\') + *pname = '/'; + + pname++; + } +} + +/* ../engine/textures.c:87 */ +qboolean TEX_InitFromWad(char *path) +{ + char *pszWadFile; + FileHandle_t texfile; + char szTmpPath[1024]; + char wadName[260]; + char wadPath[260]; + wadinfo_t header; + + Q_strncpy(szTmpPath, path, 1022); + szTmpPath[1022] = 0; + if (!strchr(szTmpPath, ';')) + Q_strcat(szTmpPath, ";"); + for (pszWadFile = strtok(szTmpPath, ";"); pszWadFile; pszWadFile = strtok(NULL, ";")) + { + ForwardSlashes(pszWadFile); + COM_FileBase(pszWadFile, wadName); + _snprintf(wadPath, 0x100u, "%s", wadName); + COM_DefaultExtension(wadPath, ".wad"); + + if (Q_strstr(wadName, "pldecal") || Q_strstr(wadName, "tempdecal")) + continue; + + texfile = FS_Open(wadPath, "rb"); + texfiles[nTexFiles++] = texfile; + if (!texfile) + Sys_Error("WARNING: couldn't open %s\n", wadPath); + + Con_DPrintf("Using WAD File: %s\n", wadPath); + SafeRead(texfile, &header, 12); + if (Q_strncmp(header.identification, "WAD2", 4) && Q_strncmp(header.identification, "WAD3", 4)) + Sys_Error("TEX_InitFromWad: %s isn't a wadfile", wadPath); + + header.numlumps = LittleLong(header.numlumps); + header.infotableofs = LittleLong(header.infotableofs); + FS_Seek(texfile, header.infotableofs, FILESYSTEM_SEEK_HEAD); + lumpinfo = (texlumpinfo_t *)Mem_Realloc(lumpinfo, sizeof(texlumpinfo_t) * (header.numlumps + nTexLumps)); + + for (int i = 0; i < header.numlumps; i++, nTexLumps++) + { + SafeRead(texfile, &lumpinfo[nTexLumps], sizeof(lumpinfo_t)); + CleanupName(lumpinfo[nTexLumps].lump.name, lumpinfo[nTexLumps].lump.name); + lumpinfo[nTexLumps].lump.filepos = LittleLong(lumpinfo[nTexLumps].lump.filepos); + lumpinfo[nTexLumps].lump.disksize = LittleLong(lumpinfo[nTexLumps].lump.disksize);; + lumpinfo[nTexLumps].iTexFile = nTexFiles - 1; + } + + } + qsort(lumpinfo, nTexLumps, sizeof(texlumpinfo_t), lump_sorter); + return 1; +} + +/* ../engine/textures.c:178 */ +void TEX_CleanupWadInfo(void) +{ + if (lumpinfo) + { + Mem_Free(lumpinfo); + lumpinfo = 0; + } + + for (int i = 0; i < nTexFiles; i++) + { + FS_Close(texfiles[i]); + texfiles[i] = 0; + } + + nTexLumps = 0; + nTexFiles = 0; +} + +/* ../engine/textures.c:203 */ +int TEX_LoadLump(char *name, unsigned char *dest) +{ + texlumpinfo_t *found; + texlumpinfo_t key; + + CleanupName(name, key.lump.name); + found = (texlumpinfo_t *)bsearch(&key, lumpinfo, nTexLumps, sizeof(texlumpinfo_t), lump_sorter); + if (found) + { + FS_Seek(texfiles[found->iTexFile], found->lump.filepos, FILESYSTEM_SEEK_HEAD); + SafeRead(texfiles[found->iTexFile], dest, found->lump.disksize); + return found->lump.disksize; + } + else + { + Con_SafePrintf("WARNING: texture lump \"%s\" not found\n", name); + return 0; + } +} + +/* ../engine/textures.c:220 */ +int FindMiptex(char *name) +{ + int i = 0; // 222 + for (i = 0; i < nummiptex; i++) + { + if (!Q_stricmp(name, miptex[i])) + return i; + } + + if (nummiptex == 512) + Sys_Error("Exceeded MAX_MAP_TEXTURES"); + + Q_strncpy(miptex[i], name, 63); + miptex[i][63] = 0; + ++nummiptex; + return i; +} + +/* ../engine/textures.c:241 */ +void TEX_AddAnimatingTextures(void) +{ + char name[32]; + + int base = nummiptex; + for (int i = 0; i < base; i++) + { + if (miptex[i][0] != '+' && miptex[i][0] != '-') + continue; + + + Q_strncpy(name, miptex[i], 0x1Fu); + name[31] = 0; + + for (int j = 0; j < 20; j++) + { + if (j >= 10) + name[1] = j + 55; + else + name[1] = j + 48; + + for (int k = 0; k < nTexLumps; k++) + { + if (!Q_strcmp(name, lumpinfo[k].lump.name)) + { + FindMiptex(name); + break; + } + } + } + } + + + if (nummiptex != base) + Con_DPrintf("added %i texture frames\n", nummiptex - base); +} diff --git a/rehlds/engine/textures.h b/rehlds/engine/textures.h new file mode 100644 index 0000000..0a50492 --- /dev/null +++ b/rehlds/engine/textures.h @@ -0,0 +1,84 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef TEXTURES_H +#define TEXTURES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "wad.h" + +#define MAX_MAP_TEXTURES 512 + +typedef struct texlumpinfo_s +{ + lumpinfo_t lump; + int iTexFile; +} texlumpinfo_t; + +#ifdef HOOK_ENGINE +#define lumpinfo (*plumpinfo) +#define nTexLumps (*pnTexLumps) +#define texfiles (*ptexfiles) +#define nTexFiles (*pnTexFiles) + +#define texgammatable (*ptexgammatable) +#define r_notexture_mip (*pr_notexture_mip) + +#define nummiptex (*pnummiptex) +#define miptex (*pmiptex) + +#define r_wadtextures (*pr_wadtextures) +#endif + +extern texlumpinfo_t* lumpinfo; +extern int nTexLumps; +extern FILE* texfiles[128]; +extern int nTexFiles; + +extern unsigned char texgammatable[256]; +extern texture_t * r_notexture_mip; + +extern int nummiptex; +extern char miptex[512][64]; + +extern cvar_t r_wadtextures; + +void SafeRead(FileHandle_t f, void *buffer, int count); +void CleanupName(char *in, char *out); +int lump_sorter(const void *lump1, const void *lump2); +void ForwardSlashes(char *pname); +qboolean TEX_InitFromWad(char *path); +void TEX_CleanupWadInfo(void); +int TEX_LoadLump(char *name, unsigned char *dest); +int FindMiptex(char *name); +void TEX_AddAnimatingTextures(void); + +#endif // TEXTURES_H diff --git a/rehlds/engine/tmessage.cpp b/rehlds/engine/tmessage.cpp new file mode 100644 index 0000000..817186a --- /dev/null +++ b/rehlds/engine/tmessage.cpp @@ -0,0 +1,516 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#define MSGFILE_NAME 0 +#define MSGFILE_TEXT 1 + +#define NAME_HEAP_SIZE 16384 +#define MAX_MESSAGES 1000 + +char gNetworkTextMessageBuffer[MAX_NETMESSAGE][512]; +client_textmessage_t gMessageParms; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +client_textmessage_t *gMessageTable = NULL; +int gMessageTableCount = 0; + +const char *gNetworkMessageNames[MAX_NETMESSAGE] = +{ + NETWORK_MESSAGE1, + NETWORK_MESSAGE2, + NETWORK_MESSAGE3, + NETWORK_MESSAGE4 +}; + +client_textmessage_t gNetworkTextMessage[MAX_NETMESSAGE] = +{ + 0, // effect + 255, 255, 255, 255, + 255, 255, 255, 255, + -1.0f, // x + -1.0f, // y + 0.0f, // fadein + 0.0f, // fadeout + 0.0f, // holdtime + 0.0f, // fxTime, + NETWORK_MESSAGE1,// pName message name. + gNetworkTextMessageBuffer[0] // pMessage +}; + +#else //HOOK_ENGINE + +client_textmessage_t *gMessageTable; +int gMessageTableCount; + +const char *gNetworkMessageNames[MAX_NETMESSAGE]; +client_textmessage_t gNetworkTextMessage[MAX_NETMESSAGE]; + +#endif //HOOK_ENGINE + +/* ../engine/tmessage.c:47 */ +char *memfgets(unsigned char *pMemFile, int fileSize, int *pFilePos, char *pBuffer, int bufferSize) +{ + int filePos; + int last; + int i; + int stop; + int size; + + filePos = *pFilePos; + if (!pMemFile || !pBuffer || filePos >= fileSize) + return NULL; + + last = fileSize; + i = *pFilePos; + if (fileSize - filePos > bufferSize - 1) + last = filePos + bufferSize - 1; + stop = 0; + + if (filePos >= last) + return NULL; + + do + { + if (stop) + break; + if (pMemFile[i] == 10) + stop = 1; + ++i; + } while (i < last); + + if (i == filePos) + return NULL; + + size = i - filePos; + Q_memcpy(pBuffer, &pMemFile[filePos], i - filePos); + if (size < bufferSize) + pBuffer[size] = 0; + *pFilePos = i; + return pBuffer; +} + +/* ../engine/tmessage.c:99 */ +int IsComment(char *pText) +{ + int length; + if (!pText) + { + return TRUE; + } + + length = Q_strlen(pText); + if (length >= 2 && pText[0] == '/' && pText[1] == '/' || length <= 0) + { + return TRUE; + } + + return FALSE; +} + +/* ../engine/tmessage.c:118 */ +int IsStartOfText(char *pText) +{ + return pText && pText[0] == '{'; +} + +/* ../engine/tmessage.c:130 */ +int IsEndOfText(char *pText) +{ + return pText && pText[0] == '}'; +} + +/* ../engine/tmessage.c:141 */ +int IsWhiteSpace(char space) +{ + return space == ' ' || space == '\t' || space == '\r' || space == '\n'; +} + +/* ../engine/tmessage.c:149 */ +NOXREF const char *SkipSpace(const char *pText) +{ + if (pText) + { + int pos = 0; + while (pText[pos] && IsWhiteSpace(pText[pos])) + pos++; + + return pText + pos; + } + return NULL; +} + +/* ../engine/tmessage.c:163 */ +NOXREF const char *SkipText(const char *pText) +{ + if (pText) + { + int pos = 0; + while (pText[pos] && !IsWhiteSpace(pText[pos])) + pos++; + return pText + pos; + } + return NULL; +} + +/* ../engine/tmessage.c:177 */ +NOXREF int ParseFloats(const char *pText, float *pFloat, int count) +{ + const char *pTemp = pText; + int index = 0; + + while (pTemp && count > 0) + { + pTemp = SkipText(pTemp); + pTemp = SkipSpace(pTemp); + + if (pTemp) + { + pFloat[index] = (float)atof(pTemp); + count--; + index++; + } + } + if (count == 0) + return 1; + + return 0; +} + +/* ../engine/tmessage.c:205 */ +void TrimSpace(const char *source, char *dest) +{ + int start, end, length; + + length = Q_strlen(source); + + for (start = 0; start < length; start++) + { + if (!IsWhiteSpace(source[start])) + break; + } + + for (end = length - 1; end > start; end--) + { + if (!IsWhiteSpace(source[end])) + break; + } + + length = end - start + 1; + + if (length <= 0) + { + dest[0] = 0; + } + else + { + Q_strncpy(dest, &source[start], length); + dest[length] = 0; + } +} + +/* ../engine/tmessage.c:232 */ +NOXREF int IsToken(const char *pText, const char *pTokenName) +{ + if (!pText || !pTokenName) + return 0; + + if (!Q_strnicmp(pText + 1, pTokenName, Q_strlen(pTokenName))) + return 1; + + return 0; +} + +/* ../engine/tmessage.c:245 */ +NOXREF int ParseDirective(const char *pText) +{ + if (pText && pText[0] == '$') + { + float tempFloat[8]; + if (IsToken(pText, "position")) + { + if (ParseFloats(pText, tempFloat, 2)) + { + gMessageParms.x = tempFloat[0]; + gMessageParms.y = tempFloat[1]; + } + } + else if (IsToken(pText, "effect")) + { + if (ParseFloats(pText, tempFloat, 1)) + { + gMessageParms.effect = (int)tempFloat[0]; + } + } + else if (IsToken(pText, "fxtime")) + { + if (ParseFloats(pText, tempFloat, 1)) + { + gMessageParms.fxtime = tempFloat[0]; + } + } + else if (IsToken(pText, "color2")) + { + if (ParseFloats(pText, tempFloat, 3)) + { + gMessageParms.r2 = (int)tempFloat[0]; + gMessageParms.g2 = (int)tempFloat[1]; + gMessageParms.b2 = (int)tempFloat[2]; + } + } + else if (IsToken(pText, "color")) + { + if (ParseFloats(pText, tempFloat, 3)) + { + gMessageParms.r1 = (int)tempFloat[0]; + gMessageParms.g1 = (int)tempFloat[1]; + gMessageParms.b1 = (int)tempFloat[2]; + } + } + else if (IsToken(pText, "fadein")) + { + if (ParseFloats(pText, tempFloat, 1)) + { + gMessageParms.fadein = tempFloat[0]; + } + } + else if (IsToken(pText, "fadeout")) + { + if (ParseFloats(pText, tempFloat, 3)) + { + gMessageParms.fadeout = tempFloat[0]; + } + } + else if (IsToken(pText, "holdtime")) + { + if (ParseFloats(pText, tempFloat, 3)) + { + gMessageParms.holdtime = tempFloat[0]; + } + } + else + { + Con_DPrintf("Unknown token: %s\n", pText); + } + return 1; + } + return 0; +} + +/* ../engine/tmessage.c:324 */ +NOXREF void TextMessageParse(unsigned char *pMemFile, int fileSize) +{ + char buf[512]; + char trim[512]; + char *pCurrentText; + char *pNameHeap; + char currentName[512]; + char nameHeap[NAME_HEAP_SIZE]; + int lastNamePos; + int mode; + int lineNumber; + int filePos; + int lastLinePos; + int messageCount; + client_textmessage_t textMessages[MAX_MESSAGES]; + int i; + int nameHeapSize; + int textHeapSize; + int messageSize; + int nameOffset; + + lastNamePos = 0; + lineNumber = 0; + filePos = 0; + lastLinePos = 0; + messageCount = 0; + mode = MSGFILE_NAME; + + while (memfgets(pMemFile, fileSize, &filePos, buf, 512) != NULL) + { + if(messageCount >= MAX_MESSAGES) + Sys_Error("tmessage::TextMessageParse : messageCount>=MAX_MESSAGES"); + + TrimSpace(buf, trim); + switch (mode) + { + case MSGFILE_NAME: + { + if (IsComment(trim)) + break; + + if (ParseDirective(trim)) + break; + + if (IsStartOfText(trim)) + { + mode = MSGFILE_TEXT; + pCurrentText = (char *)(pMemFile + filePos); + break; + } + if (IsEndOfText(trim)) + { + Con_DPrintf("Unexpected '}' found, line %d\n", lineNumber); + return; + } + Q_strncpy(currentName, trim, 511); + currentName[511] = 0; + + break; + } + case MSGFILE_TEXT: + { + if (IsEndOfText(trim)) + { + int length = Q_strlen(currentName); + if (lastNamePos + length > sizeof(nameHeap)) + { + Con_DPrintf("Error parsing file! length > %i bytes\n", sizeof(nameHeap)); + return; + } + + Q_strcpy(nameHeap + lastNamePos, currentName); + + pMemFile[lastLinePos - 1] = 0; + + textMessages[messageCount] = gMessageParms; + textMessages[messageCount].pName = nameHeap + lastNamePos; + lastNamePos += Q_strlen(currentName) + 1; + textMessages[messageCount].pMessage = pCurrentText; + messageCount++; + + mode = MSGFILE_NAME; + break; + } + if (IsStartOfText(trim)) + { + Con_DPrintf("Unexpected '{' found, line %d\n", lineNumber); + return; + } + break; + } + } + + lineNumber++; + lastLinePos = filePos; + } + + Con_DPrintf("Parsed %d text messages\n", messageCount); + nameHeapSize = lastNamePos; + textHeapSize = 0; + + for (i = 0; i < messageCount; i++) + textHeapSize += Q_strlen(textMessages[i].pMessage) + 1; + + messageSize = (messageCount * sizeof(client_textmessage_t)); + + gMessageTable = (client_textmessage_t *)Mem_Malloc(textHeapSize + nameHeapSize + messageSize); + + Q_memcpy(gMessageTable, textMessages, messageSize); + + pNameHeap = ((char *)gMessageTable) + messageSize; + Q_memcpy(pNameHeap, nameHeap, nameHeapSize); + nameOffset = pNameHeap - gMessageTable[0].pName; + + pCurrentText = pNameHeap + nameHeapSize; + for (i = 0; i < messageCount; i++) + { + gMessageTable[i].pName += nameOffset; + Q_strcpy(pCurrentText, gMessageTable[i].pMessage); + gMessageTable[i].pMessage = pCurrentText; + pCurrentText += Q_strlen(pCurrentText) + 1; + } + + gMessageTableCount = messageCount; +} + +/* ../engine/tmessage.c:454 */ +NOXREF void TextMessageShutdown(void) +{ + if (gMessageTable) + { + Mem_Free(gMessageTable); + gMessageTable = NULL; + } +} + +/* ../engine/tmessage.c:464 */ +NOXREF void TextMessageInit(void) +{ + int fileSize; + unsigned char *pMemFile; + + if (gMessageTable) + { + Mem_Free(gMessageTable); + gMessageTable = NULL; + } + + pMemFile = COM_LoadTempFile("titles.txt", &fileSize); + + if (pMemFile) + TextMessageParse(pMemFile, fileSize); +} + +/* ../engine/tmessage.c:497 */ +NOXREF client_textmessage_t *TextMessageGet(const char *pName) +{ + int i; + +#ifndef SWDS + + g_engdstAddrs->pfnTextMessageGet(&pName); + + if (!Q_stricmp(pName, DEMO_MESSAGE)) + return &tm_demomessage; +#endif // SWDS + + if (!Q_stricmp(pName, NETWORK_MESSAGE1)) + return gNetworkTextMessage; + + else if (!Q_stricmp(pName, NETWORK_MESSAGE2)) + return gNetworkTextMessage + 1; + + else if (!Q_stricmp(pName, NETWORK_MESSAGE3)) + return gNetworkTextMessage + 2; + + else if (!Q_stricmp(pName, NETWORK_MESSAGE4)) + return gNetworkTextMessage + 3; + + for (i = 0; i < gMessageTableCount; i++) + { + if (!Q_strcmp(pName, gMessageTable[i].pName)) + return &gMessageTable[i]; + } + return NULL; +} diff --git a/rehlds/engine/tmessage.h b/rehlds/engine/tmessage.h new file mode 100644 index 0000000..dffc511 --- /dev/null +++ b/rehlds/engine/tmessage.h @@ -0,0 +1,81 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef TMESSAGE_H +#define TMESSAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + +#define DEMO_MESSAGE "__DEMOMESSAGE__" +#define NETWORK_MESSAGE1 "__NETMESSAGE__1" +#define NETWORK_MESSAGE2 "__NETMESSAGE__2" +#define NETWORK_MESSAGE3 "__NETMESSAGE__3" +#define NETWORK_MESSAGE4 "__NETMESSAGE__4" + +#define MAX_NETMESSAGE 4 + +#ifdef HOOK_ENGINE + +#define gMessageTable (*pgMessageTable) +#define gMessageTableCount (*pgMessageTableCount) +#define gMessageParms (*pgMessageParms) + +#define gNetworkTextMessageBuffer (*pgNetworkTextMessageBuffer) +#define gNetworkMessageNames (*pgNetworkMessageNames) +#define gNetworkTextMessage (*pgNetworkTextMessage) + +#endif // HOOK_ENGINE + +extern client_textmessage_t *gMessageTable; +extern int gMessageTableCount; +extern client_textmessage_t gMessageParms; + +extern char gNetworkTextMessageBuffer[MAX_NETMESSAGE][512]; +extern const char *gNetworkMessageNames[MAX_NETMESSAGE]; +extern client_textmessage_t gNetworkTextMessage[MAX_NETMESSAGE]; + +char *memfgets(unsigned char *pMemFile, int fileSize, int *pFilePos, char *pBuffer, int bufferSize); +int IsComment(char *pText); +int IsStartOfText(char *pText); +int IsEndOfText(char *pText); +int IsWhiteSpace(char space); +NOXREF const char *SkipSpace(const char *pText); +NOXREF const char *SkipText(const char *pText); +NOXREF int ParseFloats(const char *pText, float *pFloat, int count); +void TrimSpace(const char *source, char *dest); +NOXREF int IsToken(const char *pText, const char *pTokenName); +NOXREF int ParseDirective(const char *pText); +NOXREF void TextMessageParse(unsigned char *pMemFile, int fileSize); +NOXREF void TextMessageShutdown(void); +NOXREF void TextMessageInit(void); +NOXREF client_textmessage_t *TextMessageGet(const char *pName); + +#endif // TMESSAGE_H diff --git a/rehlds/engine/traceinit.cpp b/rehlds/engine/traceinit.cpp new file mode 100644 index 0000000..079b59e --- /dev/null +++ b/rehlds/engine/traceinit.cpp @@ -0,0 +1,123 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +CInitTracker g_InitTracker; + +/* ../engine/traceinit.cpp:56 */ +CInitTracker::CInitTracker(void) +{ + for (int l = 0; l < NUM_LISTS; l++) + { + m_Funcs[l].RemoveAll(); + m_nNumFuncs[l] = 0; + } +} + +/* ../engine/traceinit.cpp:67 */ +CInitTracker::~CInitTracker(void) +{ + for (int l = 0; l < NUM_LISTS; l++) + { + for (int i = 0; i < m_nNumFuncs[l]; i++) + { + InitFunc *f = m_Funcs[l][i]; + if (f->referencecount) + { + Sys_Printf("Missing shutdown function for %s : %s\n", f->initname, f->shutdownname); + } + delete f; + } + m_Funcs[l].RemoveAll(); + m_nNumFuncs[l] = 0; + } +} + +/* ../engine/traceinit.cpp:91 */ +void CInitTracker::Init(const char *init, const char *shutdown, int listnum) +{ + InitFunc *f = new InitFunc; + + f->initname = init; + f->shutdownname = shutdown; + f->inittime = 0.0f; + f->referencecount = 1; + f->shutdowntime = 0.0f; + f->sequence = m_nNumFuncs[listnum]; + f->warningprinted = false; + + m_Funcs[listnum].AddToHead(f); + m_nNumFuncs[listnum]++; +} + +/* ../engine/traceinit.cpp:111 */ +void CInitTracker::Shutdown(const char *shutdown, int listnum) +{ + int i = 0; + InitFunc *f = NULL; + + if (!m_nNumFuncs[listnum]) + { + Sys_Printf("Mismatched shutdown function %s\n", shutdown); + return; + } + for (i = 0; i < m_nNumFuncs[listnum]; i++) + { + f = m_Funcs[listnum][i]; + if (f->referencecount) + break; + } + if (f && f->referencecount && Q_stricmp(f->shutdownname, shutdown)) + { + if (!f->warningprinted) + f->warningprinted = true; + } + for (i = 0; i < m_nNumFuncs[listnum]; i++) + { + InitFunc *f = m_Funcs[listnum][i]; + if (!Q_stricmp(f->shutdownname, shutdown)) + { + f->referencecount--; + return; + } + } + Sys_Printf("Shutdown function %s not in list!!!\n", shutdown); +} + +/* ../engine/traceinit.cpp:158 */ +void TraceInit(const char *i, const char *s, int listnum) +{ + g_InitTracker.Init(i, s, listnum); +} + +/* ../engine/traceinit.cpp:167 */ +void TraceShutdown(const char *s, int listnum) +{ + g_InitTracker.Shutdown(s, listnum); +} diff --git a/rehlds/engine/traceinit.h b/rehlds/engine/traceinit.h new file mode 100644 index 0000000..9e08236 --- /dev/null +++ b/rehlds/engine/traceinit.h @@ -0,0 +1,84 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef TRACEINIT_H +#define TRACEINIT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlvector.h" + +#ifndef HOOK_ENGINE +#define CInitTracker_construct CInitTracker +#define CInitTracker_destruct ~CInitTracker +#endif + +/* ../engine/traceinit.cpp:16 */ +class CInitTracker +{ +public: + enum + { + NUM_LISTS = 4, + }; + + class InitFunc + { + public: + const char *initname; + const char *shutdownname; + int referencecount; + int sequence; + bool warningprinted; + + double inittime; + double shutdowntime; + }; + + CInitTracker(void); + ~CInitTracker(void); + + void Init(const char *init, const char *shutdown, int listnum); + void Shutdown(const char *shutdown, int listnum); + +private: + int m_nNumFuncs[NUM_LISTS]; + CUtlVector m_Funcs[NUM_LISTS]; +}; + +#ifdef HOOK_ENGINE +#define g_InitTracker (*pg_InitTracker) +#endif + +extern CInitTracker g_InitTracker; + +void TraceInit(const char *i, const char *s, int listnum); +void TraceShutdown(const char *s, int listnum); + +#endif // TRACEINIT_H diff --git a/rehlds/engine/unicode_strtools.cpp b/rehlds/engine/unicode_strtools.cpp new file mode 100644 index 0000000..2ef3ca2 --- /dev/null +++ b/rehlds/engine/unicode_strtools.cpp @@ -0,0 +1,488 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +/* ../engine/unicode_strtools.cpp:23 */ +//----------------------------------------------------------------------------- +// Purpose: determine if a uchar32 represents a valid Unicode code point +//----------------------------------------------------------------------------- +qboolean Q_IsValidUChar32(uchar32 uVal) +{ + // Values > 0x10FFFF are explicitly invalid; ditto for UTF-16 surrogate halves, + // values ending in FFFE or FFFF, or values in the 0x00FDD0-0x00FDEF reserved range + return (uVal < 0x110000u) && ((uVal - 0x00D800u) > 0x7FFu) && ((uVal & 0xFFFFu) < 0xFFFEu) && ((uVal - 0x00FDD0u) > 0x1Fu); +} + +/* ../engine/unicode_strtools.cpp:346 */ +// Decode one character from a UTF-8 encoded string. Treats 6-byte CESU-8 sequences +// as a single character, as if they were a correctly-encoded 4-byte UTF-8 sequence. +int Q_UTF8ToUChar32(const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut) +{ + const uint8_t *pUTF8 = (const uint8_t *)pUTF8_; + + int nBytes = 1; + uint32_t uValue = pUTF8[0]; + uint32_t uMinValue = 0; + + // 0....... single byte + if (uValue < 0x80) + goto decodeFinishedNoCheck; + + // Expecting at least a two-byte sequence with 0xC0 <= first <= 0xF7 (110...... and 11110...) + if ((uValue - 0xC0u) > 0x37u || (pUTF8[1] & 0xC0) != 0x80) + goto decodeError; + + uValue = (uValue << 6) - (0xC0 << 6) + pUTF8[1] - 0x80; + nBytes = 2; + uMinValue = 0x80; + + // 110..... two-byte lead byte + if (!(uValue & (0x20 << 6))) + goto decodeFinished; + + // Expecting at least a three-byte sequence + if ((pUTF8[2] & 0xC0) != 0x80) + goto decodeError; + + uValue = (uValue << 6) - (0x20 << 12) + pUTF8[2] - 0x80; + nBytes = 3; + uMinValue = 0x800; + + // 1110.... three-byte lead byte + if (!(uValue & (0x10 << 12))) + goto decodeFinishedMaybeCESU8; + + // Expecting a four-byte sequence, longest permissible in UTF-8 + if ((pUTF8[3] & 0xC0) != 0x80) + goto decodeError; + + uValue = (uValue << 6) - (0x10 << 18) + pUTF8[3] - 0x80; + nBytes = 4; + uMinValue = 0x10000; + + // 11110... four-byte lead byte. fall through to finished. + +decodeFinished: + if (uValue >= uMinValue && Q_IsValidUChar32(uValue)) + { +decodeFinishedNoCheck: + uValueOut = uValue; + bErrorOut = false; + return nBytes; + } +decodeError: + uValueOut = '?'; + bErrorOut = true; + return nBytes; + +decodeFinishedMaybeCESU8: + // Do we have a full UTF-16 surrogate pair that's been UTF-8 encoded afterwards? + // That is, do we have 0xD800-0xDBFF followed by 0xDC00-0xDFFF? If so, decode it all. + if ((uValue - 0xD800u) < 0x400u && pUTF8[3] == 0xED && (uint8_t)(pUTF8[4] - 0xB0) < 0x10 && (pUTF8[5] & 0xC0) == 0x80) + { + uValue = 0x10000 + ((uValue - 0xD800u) << 10) + ((uint8_t)(pUTF8[4] - 0xB0) << 6) + pUTF8[5] - 0x80; + nBytes = 6; + uMinValue = 0x10000; + } + goto decodeFinished; +} + +int __cdecl Q_IsUnprintableW(uchar16 c) +{ + switch (c) + { + case 0x202A: + case 0x202B: + case 0x202C: + case 0x202D: + case 0x202E: + case 0x206A: + case 0x206B: + case 0x206C: + case 0x206D: + case 0x206E: + case 0x206F: + return 1; + + default: + return 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if a wide character is a "mean" space; that is, +// if it is technically a space or punctuation, but causes disruptive +// behavior when used in names, web pages, chat windows, etc. +// +// characters in this set are removed from the beginning and/or end of strings +// by Q_AggressiveStripPrecedingAndTrailingWhitespaceW() +//----------------------------------------------------------------------------- +bool Q_IsMeanSpaceW(uchar16 wch) +{ + bool bIsMean = false; + + switch (wch) + { + case 0x0082: // BREAK PERMITTED HERE + case 0x0083: // NO BREAK PERMITTED HERE + case 0x00A0: // NO-BREAK SPACE + case 0x034F: // COMBINING GRAPHEME JOINER + case 0x2000: // EN QUAD + case 0x2001: // EM QUAD + case 0x2002: // EN SPACE + case 0x2003: // EM SPACE + case 0x2004: // THICK SPACE + case 0x2005: // MID SPACE + case 0x2006: // SIX SPACE + case 0x2007: // figure space + case 0x2008: // PUNCTUATION SPACE + case 0x2009: // THIN SPACE + case 0x200A: // HAIR SPACE + case 0x200B: // ZERO-WIDTH SPACE + case 0x200C: // ZERO-WIDTH NON-JOINER + case 0x200D: // ZERO WIDTH JOINER + case 0x2028: // LINE SEPARATOR + case 0x2029: // PARAGRAPH SEPARATOR + case 0x202F: // NARROW NO-BREAK SPACE + case 0x2060: // word joiner + case 0xFEFF: // ZERO-WIDTH NO BREAK SPACE + case 0xFFFC: // OBJECT REPLACEMENT CHARACTER + bIsMean = true; + break; + } + + return bIsMean; +} + +//----------------------------------------------------------------------------- +// Purpose: strips trailing whitespace; returns pointer inside string just past +// any leading whitespace. +// +// bAggresive = true causes this function to also check for "mean" spaces, +// which we don't want in persona names or chat strings as they're disruptive +// to the user experience. +//----------------------------------------------------------------------------- +static uchar16 *StripWhitespaceWorker(uchar16 *pwch, int cchLength, bool *pbStrippedWhitespace) +{ + // walk backwards from the end of the string, killing any whitespace + *pbStrippedWhitespace = false; + + uchar16 *pwchEnd = pwch + cchLength; + while (--pwchEnd >= pwch) + { + if (!iswspace(*pwchEnd) && !Q_IsMeanSpaceW(*pwchEnd)) + break; + + *pwchEnd = 0; + *pbStrippedWhitespace = true; + } + + // walk forward in the string + while (pwch < pwchEnd) + { + if (!iswspace(*pwch)) + break; + + *pbStrippedWhitespace = true; + pwch++; + } + + return pwch; +} + +uchar16 *__cdecl StripUnprintableWorker(uchar16 *pwch, bool *pStripped) +{ + uchar16* rPos = pwch; + uchar16* wPos = pwch; + *pStripped = 0; + + while(*rPos) + { + uchar16 cc = *rPos; + if (*rPos >= 0x20u && !Q_IsUnprintableW(cc) && cc != 0x2026) + { + *wPos = cc; + ++wPos; + } + ++rPos; + } + + *wPos = 0; + *pStripped = rPos != wPos; + return pwch; +} + +/* ../engine/unicode_strtools.cpp:423 */ +//----------------------------------------------------------------------------- +// Purpose: Returns false if UTF-8 string contains invalid sequences. +//----------------------------------------------------------------------------- +qboolean Q_UnicodeValidate(const char *pUTF8) +{ + bool bError = false; + while (*pUTF8) + { + uchar32 uVal; + // Our UTF-8 decoder silently fixes up 6-byte CESU-8 (improperly re-encoded UTF-16) sequences. + // However, these are technically not valid UTF-8. So if we eat 6 bytes at once, it's an error. + int nCharSize = Q_UTF8ToUChar32(pUTF8, uVal, bError); + if (bError || nCharSize == 6) + return false; + pUTF8 += nCharSize; + } + return true; +} + +/* ../engine/unicode_strtools.cpp:459 */ +char *Q_UnicodeAdvance(char *pUTF8, int nChars) +{ + uchar32 uVal = 0; + bool bError = false; + + while (nChars > 0 && *pUTF8) + { + pUTF8 += Q_UTF8ToUChar32(pUTF8, uVal, bError); + --nChars; + } + + return pUTF8; +} + + + +/* ../engine/unicode_strtools.cpp:717 */ +qboolean V_UTF8ToUChar32(const char *pUTF8_, uchar32 *uValueOut) +{ + bool bError = false; + Q_UTF8ToUChar32(pUTF8_, *uValueOut, bError); + return bError; +} + +/* ../engine/unicode_strtools.cpp:137 */ +int Q_UChar32ToUTF8Len(uchar32 uVal) { + if (uVal <= 0x7F) + return 1; + + if (uVal > 0x7FF) + return (uVal > 0xFFFF) + 3; + else + return 2; +} + +/* ../engine/unicode_strtools.cpp:180 */ +int Q_UChar32ToUTF8(uchar32 uVal, char * pUTF8Out) { + if (uVal <= 0x7F) + { + *pUTF8Out = uVal; + return 1; + } + else if (uVal <= 0x7FF) + { + *pUTF8Out = (uVal >> 6) | 0xC0; + pUTF8Out[1] = uVal & 0x3F | 0x80; + return 2; + } + else if (uVal <= 0xFFFF) + { + *pUTF8Out = (uVal >> 12) | 0xE0; + pUTF8Out[2] = uVal & 0x3F | 0x80; + pUTF8Out[1] = (uVal >> 6) & 0x3F | 0x80; + return 3; + } + else + { + *pUTF8Out = (uVal >> 18) & 7 | 0xF0; + pUTF8Out[1] = (uVal >> 12) & 0x3F | 0x80; + pUTF8Out[3] = uVal & 0x3F | 0x80; + pUTF8Out[2] = (uVal >> 6) & 0x3F | 0x80; + return 4; + } +} + +int Q_UChar32ToUTF16Len(uchar32 uVal) +{ + return (uVal > 0xFFFF) ? 2 : 1; +} + +int __cdecl Q_UChar32ToUTF16(uchar32 uVal, uchar16 *pUTF16Out) +{ + + if (uVal <= 0xFFFF) + { + pUTF16Out[0] = uVal; + return 1; + } + else + { + pUTF16Out[1] = uVal & 0x3FF | 0xDC00; + pUTF16Out[0] = ((uVal - 0x10000) >> 10) | 0xD800; + return 2; + } +} + +template< + typename T_IN, + typename T_OUT, + bool UNK, + qboolean(*IN_TO_UCHAR32)(const T_IN *pUTF8, uchar32 &uValueOut, bool &bErrorOut), + int(UCHAR32_TO_OUT_LEN)(uchar32 uVal), + int(UCHAR32_TO_OUT)(uchar32 uVal, T_OUT *pUTF8Out) +> +int Q_UnicodeConvertT(const T_IN* pIn, T_OUT *pOut, int nOutBytes, enum EStringConvertErrorPolicy ePolicy) +{ + int nOut = 0; + if (pOut) + { + int nMaxOut = nOutBytes / sizeof(T_OUT) - 1; + if (nMaxOut <= 0) + return 0; + + while (pIn) + { + bool bErr; + uchar32 uVal; + pIn += IN_TO_UCHAR32(pIn, uVal, bErr); + int nOutElems = UCHAR32_TO_OUT_LEN(uVal); + if (nOutElems + nOut > nMaxOut) + break; + nOut += UCHAR32_TO_OUT(uVal, &pOut[nOut]); + if (bErr) + { + if (ePolicy & STRINGCONVERT_SKIP) + { + nOut -= nOutElems; + } + else if (ePolicy & STRINGCONVERT_FAIL) + { + pOut[0] = 0; + return 0; + } + + } + }; + + pOut[nOut] = 0; + } + else + { + while (*pIn) + { + bool bErr; + uchar32 uVal; + pIn += IN_TO_UCHAR32(pIn, uVal, bErr); + int nOutElems = UCHAR32_TO_OUT_LEN(uVal); + if (bErr) + { + if (ePolicy & STRINGCONVERT_SKIP) + { + nOut -= nOutElems; + } + else if (ePolicy & STRINGCONVERT_FAIL) + { +#ifndef REHLDS_FIXES + pOut[0] = 0; //FIXME: pOut is always null there + //TODO: V522 Dereferencing of the null pointer 'pOut' might take place. +#endif // REHLDS_FIXES + return 0; + } + + } + } + } + return (nOut + 1) * sizeof(T_OUT); +} + +int __cdecl Q_UTF16ToUChar32(const uchar16 *pUTF16, uchar32 &uValueOut, bool &bErrorOut) +{ + if (Q_IsValidUChar32(pUTF16[0])) + { + uValueOut = pUTF16[0]; + bErrorOut = false; + return 1; + } + else if (pUTF16[0] - 55296 >= 0x400 || (pUTF16[1] - 56320) >= 0x400) + { + uValueOut = 63; + bErrorOut = true; + return 1; + } + else + { + uValueOut = pUTF16[1] + ((uchar32)(pUTF16[0] - 55287) << 10); + if (Q_IsValidUChar32(uValueOut)) + { + bErrorOut = false; + } + else + { + uValueOut = 63; + bErrorOut = true; + } + return 2; + } +} + +/* ../engine/unicode_strtools.cpp:246 */ +int Q_UTF8ToUTF16(const char *pUTF8, uchar16 *pUTF16, int cubDestSizeInBytes, enum EStringConvertErrorPolicy ePolicy) +{ + return Q_UnicodeConvertT(pUTF8, pUTF16, cubDestSizeInBytes, ePolicy); +} + +int Q_UTF16ToUTF8(const uchar16 *pUTF16, char *pUTF8, int cubDestSizeInBytes, enum EStringConvertErrorPolicy ePolicy) /* linkage=_Z13Q_UTF16ToUTF8PKtPci25EStringConvertErrorPolicy */ +{ + return Q_UnicodeConvertT(pUTF16, pUTF8, cubDestSizeInBytes, ePolicy); +} + + +/* ../engine/unicode_strtools.cpp:724 */ +int Q_UnicodeRepair(char *pUTF8) +{ + return Q_UnicodeConvertT(pUTF8, pUTF8, 65535, STRINGCONVERT_SKIP); +} + +/* ../engine/unicode_strtools.cpp:691 */ +qboolean Q_StripUnprintableAndSpace(char *pch) +{ + bool bStrippedAny; + bool bStrippedWhitespace; + + int cch = Q_strlen(pch); + int cubDest = (cch + 1) * sizeof(uchar16); + uchar16 *pwch_alloced = (uchar16*)malloc(cubDest); + bStrippedAny = false; + bStrippedWhitespace = false; + int cwch = (unsigned int)Q_UTF8ToUTF16(pch, (uchar16 *)pwch_alloced, cubDest, _STRINGCONVERTFLAG_ASSERT) >> 1; + uchar16 * pwch = StripUnprintableWorker(pwch_alloced, &bStrippedAny); + pwch = StripWhitespaceWorker(pwch, cwch - 1, &bStrippedWhitespace); + if (bStrippedWhitespace || bStrippedAny) + Q_UTF16ToUTF8(pwch, pch, cch, STRINGCONVERT_ASSERT_REPLACE); + + free(pwch_alloced); + return bStrippedAny; +} \ No newline at end of file diff --git a/rehlds/engine/unicode_strtools.h b/rehlds/engine/unicode_strtools.h new file mode 100644 index 0000000..5b08a4d --- /dev/null +++ b/rehlds/engine/unicode_strtools.h @@ -0,0 +1,66 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef UNICODE_STR_TOOLS_H +#define UNICODE_STR_TOOLS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + + +#ifdef _WIN32 +typedef wchar_t uchar16; +typedef unsigned int uchar32; +#else +typedef unsigned short uchar16; +typedef wchar_t uchar32; +#endif + +enum EStringConvertErrorPolicy { + _STRINGCONVERTFLAG_SKIP = 1, + _STRINGCONVERTFLAG_FAIL = 2, + _STRINGCONVERTFLAG_ASSERT = 4, + STRINGCONVERT_REPLACE = 0, + STRINGCONVERT_SKIP = 1, + STRINGCONVERT_FAIL = 2, + STRINGCONVERT_ASSERT_REPLACE = 4, + STRINGCONVERT_ASSERT_SKIP = 5, + STRINGCONVERT_ASSERT_FAIL = 6, +}; /* size: 4 */ + +qboolean Q_IsValidUChar32(uchar32 uVal); +int Q_UTF8ToUChar32(const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut); +qboolean Q_UnicodeValidate(const char *pUTF8); +char *Q_UnicodeAdvance(char *pUTF8, int nChars); +qboolean Q_StripUnprintableAndSpace(char *pch);; +qboolean V_UTF8ToUChar32(const char *pUTF8_, uchar32 *uValueOut); +int Q_UnicodeRepair(char *pUTF8); + +#endif // UNICODE_STR_TOOLS_H diff --git a/rehlds/engine/userid.h b/rehlds/engine/userid.h new file mode 100644 index 0000000..884537c --- /dev/null +++ b/rehlds/engine/userid.h @@ -0,0 +1,32 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + + +#pragma once + +#include "userid_rehlds.h" diff --git a/rehlds/engine/usermsg.h b/rehlds/engine/usermsg.h new file mode 100644 index 0000000..883f097 --- /dev/null +++ b/rehlds/engine/usermsg.h @@ -0,0 +1,49 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef USERMSG_H +#define USERMSG_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "quakedef.h" + + +/* <3d23a> ../engine/usermsg.h:17 */ +typedef struct _UserMsg +{ + int iMsg; + int iSize; + char szName[16]; + struct _UserMsg *next; + pfnUserMsgHook pfn; +} UserMsg; + +#endif // USERMSG_H diff --git a/rehlds/engine/vid_null.cpp b/rehlds/engine/vid_null.cpp new file mode 100644 index 0000000..5dcf6fd --- /dev/null +++ b/rehlds/engine/vid_null.cpp @@ -0,0 +1,135 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +float scr_con_current; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +int r_pixbytes = 1; +cvar_t gl_vsync = { "gl_vsync", "1", 0, 0.0f, NULL }; + +#else //HOOK_ENGINE + +int r_pixbytes; +cvar_t gl_vsync; + +#endif //HOOK_ENGINE + +/* ../engine/vid_null.c:28 */ +void VID_SetPalette(unsigned char *palette) { } + +/* ../engine/vid_null.c:29 */ +void VID_ShiftPalette(unsigned char *palette) { } + +/* ../engine/vid_null.c:30 */ +void VID_WriteBuffer(const char *pFilename) { } + +/* ../engine/vid_null.c:32 */ +int VID_Init(short unsigned int *palette) { return 1; } + +/* ../engine/vid_null.c:51 */ +void D_FlushCaches(void) { } + +/* ../engine/vid_null.c:52 */ +void R_SetStackBase(void) { } + +/* ../engine/vid_null.c:53 */ +void SCR_UpdateScreen(void) { } + +/* ../engine/vid_null.c:54 */ +void V_Init(void) { } + +/* ../engine/vid_null.c:56 */ +void Draw_Init(void) { } + +/* ../engine/vid_null.c:57 */ +void SCR_Init(void) { } + +/* ../engine/vid_null.c:58 */ +void R_Init(void) { } + +void R_ForceCVars(qboolean multiplayer) { } + +/* ../engine/vid_null.c:59 */ +void SCR_BeginLoadingPlaque(qboolean reconnect) { } + +/* ../engine/vid_null.c:60 */ +void SCR_EndLoadingPlaque(void) { } + +/* ../engine/vid_null.c:62 */ +void R_InitSky(void) { } + +/* ../engine/vid_null.c:63 */ +void R_MarkLeaves(void) +{ +} + +/* ../engine/vid_null.c:78 */ +void R_InitTextures(void) +{ + r_notexture_mip = (texture_t *)Hunk_AllocName(404, "notexture"); + r_notexture_mip->height = 16; + r_notexture_mip->width = 16; + r_notexture_mip->offsets[0] = 64; + r_notexture_mip->offsets[1] = 320; + r_notexture_mip->offsets[2] = 384; + r_notexture_mip->offsets[3] = 400; + + for (int m = 0; m < 4; m++) + { + int texSize = 16 >> m; + unsigned char* dest = (unsigned char *)r_notexture_mip + r_notexture_mip->offsets[m]; + + for (int x = 0; x < texSize; x++) + { + for (int y = 0; y < texSize; y++, dest++) + { + if (x < (texSize / 2) == y < (texSize / 2)) + *dest = -1; + else + *dest = 0; + } + } + + } + +} + +/* ../engine/vid_null.c:110 */ +void StartLoadingProgressBar(const char *loadingType, int numProgressPoints) { } + +/* ../engine/vid_null.c:114 */ +void ContinueLoadingProgressBar(const char *loadingType, int progressPoint, float progressFraction) { } + +/* ../engine/vid_null.c:118 */ +void SetLoadingProgressBarStatusText(const char *statusText) { } diff --git a/rehlds/engine/vid_null.h b/rehlds/engine/vid_null.h new file mode 100644 index 0000000..20c0123 --- /dev/null +++ b/rehlds/engine/vid_null.h @@ -0,0 +1,62 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "maintypes.h" + +#ifdef HOOK_ENGINE +#define r_pixbytes (*pr_pixbytes) +#define gl_vsync (*pgl_vsync) +#define scr_con_current (*pscr_con_current) +#endif //HOOK_ENGINE + +extern int r_pixbytes; +extern cvar_t gl_vsync; +extern float scr_con_current; + +void VID_SetPalette(unsigned char *palette); +void VID_ShiftPalette(unsigned char *palette); +void VID_WriteBuffer(const char *pFilename); +NOBODY int VID_Init(short unsigned int *palette); +void D_FlushCaches(void); +void R_SetStackBase(void); +void SCR_UpdateScreen(void); +void V_Init(void); +void Draw_Init(void); +void SCR_Init(void); +void R_Init(void); +void R_ForceCVars(qboolean multiplayer); +void SCR_BeginLoadingPlaque(qboolean reconnect); +void SCR_EndLoadingPlaque(void); +void R_InitSky(void); +void R_MarkLeaves(void); +void R_InitTextures(void); +void StartLoadingProgressBar(const char *loadingType, int numProgressPoints); +void ContinueLoadingProgressBar(const char *loadingType, int progressPoint, float progressFraction); +void SetLoadingProgressBarStatusText(const char *statusText); diff --git a/rehlds/engine/wad.cpp b/rehlds/engine/wad.cpp new file mode 100644 index 0000000..4d22ec4 --- /dev/null +++ b/rehlds/engine/wad.cpp @@ -0,0 +1,164 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +wadlist_t wads[NUM_WADS]; + +/* ../engine/wad.c:35 */ +void W_CleanupName(char *in, char *out) +{ + int i; + int c; + + for (i = 0; i < 16; i++) + { + c = in[i]; + if (!c) + break; + if (c >= 'A' && c <= 'Z') + c += 'a' - 'A'; + out[i] = c; + } + if (i < 16) + memset(&out[i], 0, 16 - i); +} + +/* ../engine/wad.c:62 */ +int W_LoadWadFile(char *filename) +{ + int slot = 0; + for (; slot < NUM_WADS; slot++) + { + if (!wads[slot].loaded) + break; + } + + if (slot >= NUM_WADS) + { + Con_Printf("No room for wad %s\n", filename); + return -1; + } + + wadlist_t *wad = &wads[slot]; + + wad->wad_base = (byte *)COM_LoadHunkFile(filename); + if (!wad->wad_base) + { + if (!slot) + Sys_Error("W_LoadWadFile: couldn't load %s", filename); + Con_Printf("WARNING: W_LoadWadFile, couldn't load %s\n", filename); + return -1; + } + + Q_strncpy(wad->wadname, filename, sizeof(wad->wadname) - 1); + wadinfo_t *header = (wadinfo_t *)wad->wad_base; + wad->wadname[sizeof(wad->wadname) - 1] = 0; + wad->loaded = 1; + if (header->identification[0] != 'W' + || header->identification[1] != 'A' + || header->identification[2] != 'D' + || header->identification[3] != '3') + Sys_Error("Wad file %s doesn't have WAD3 id\n", filename); + wad->wad_numlumps = LittleLong(header->numlumps); + + lumpinfo_t * lump_p = (lumpinfo_t *)&wad->wad_base[LittleLong(header->infotableofs)]; + wad->wad_lumps = lump_p; + + for (int i = 0; i < wad->wad_numlumps; ++i, ++lump_p) + { + lump_p->filepos = LittleLong(lump_p->filepos); + lump_p->size = LittleLong(lump_p->size); + W_CleanupName(lump_p->name, lump_p->name); + if (lump_p->type == 66) + SwapPic((qpic_t *)&wad->wad_base[lump_p->filepos]); + } + + return slot; +} + +/* ../engine/wad.c:132 */ +lumpinfo_t *W_GetLumpinfo(int wad, char *name, qboolean doerror) +{ + int i; + lumpinfo_t *lump_p; + char clean[16]; + + W_CleanupName(name, clean); + for (i = 0; i < wads[wad].wad_numlumps; i++) + { + lump_p = wads[i].wad_lumps; + if (!Q_strcmp(clean, lump_p->name)) + return lump_p; + } + + if (doerror) + Sys_Error("W_GetLumpinfo: %s not found", name); + + return NULL; +} + +/* ../engine/wad.c:152 */ +void *W_GetLumpName(int wad, char *name) +{ + lumpinfo_t *lump = W_GetLumpinfo(wad, name, TRUE); + if (lump != NULL) + return &wads[wad].wad_base[lump->filepos]; + return NULL; +} + +/* ../engine/wad.c:161 */ +NOXREF void *W_GetLumpNum(int wad, int num) +{ + lumpinfo_t *lump; + if (num < 0 || num > wads[wad].wad_numlumps) + Sys_Error("W_GetLumpNum: bad number: %i", num); + + lump = wads[wad].wad_lumps; + return (void *)&wads[wad].wad_base[lump->filepos]; +} + +/* ../engine/wad.c:173 */ +void W_Shutdown(void) +{ + for (int slot = 0; slot < NUM_WADS; slot++) + { + wadlist_t *wad = &wads[slot]; + if (!wad->loaded) + break; + + memset(wad, 0, sizeof(wadlist_t)); + } +} + +/* ../engine/wad.c:196 */ +void SwapPic(qpic_t *pic) +{ + pic->width = LittleLong(pic->width); + pic->height = LittleLong(pic->height); +} diff --git a/rehlds/engine/wad.h b/rehlds/engine/wad.h new file mode 100644 index 0000000..17b131b --- /dev/null +++ b/rehlds/engine/wad.h @@ -0,0 +1,98 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef WAD_H +#define WAD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + + +/* ../engine/wad.h:21 */ +typedef struct qpic_s +{ + int width; + int height; + byte data[4]; +} qpic_t; + +/* ../engine/wad.h:27 */ +typedef struct wadinfo_s +{ + char identification[4]; + int numlumps; + int infotableofs; +} wadinfo_t; + +/* ../engine/wad.h:34 */ +typedef struct lumpinfo_s +{ + int filepos; + int disksize; + int size; + char type; + char compression; + char pad1; + char pad2; + char name[16]; +} lumpinfo_t; + +/* ../engine/wad.c:9 */ +typedef struct wadlist_s +{ + qboolean loaded; + char wadname[32]; + int wad_numlumps; + lumpinfo_t * wad_lumps; + byte * wad_base; +} wadlist_t; + +typedef struct wadlist_s wadlist_t; + +/* ../engine/wad.h:43 */ +typedef struct lumpinfo_s lumpinfo_t; + +#define NUM_WADS 2 + +#ifdef HOOK_ENGINE +#define wads (*pwads) +#endif + +extern wadlist_t wads[NUM_WADS]; + +void W_CleanupName(char *in, char *out); +int W_LoadWadFile(char *filename); +lumpinfo_t *W_GetLumpinfo(int wad, char *name, qboolean doerror); +void *W_GetLumpName(int wad, char *name); +NOXREF void *W_GetLumpNum(int wad, int num); +void W_Shutdown(void); +void SwapPic(qpic_t *pic); + +#endif // WAD_H diff --git a/rehlds/engine/world.cpp b/rehlds/engine/world.cpp new file mode 100644 index 0000000..0b402ff --- /dev/null +++ b/rehlds/engine/world.cpp @@ -0,0 +1,1154 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +hull_t box_hull; +hull_t beam_hull; +box_clipnodes_t box_clipnodes; +box_planes_t box_planes; +beam_planes_t beam_planes; +areanode_t sv_areanodes[32]; +int sv_numareanodes; + + +/* ../engine/world.c:48 */ +void ClearLink(link_t *l) +{ + l->next = l; + l->prev = l; +} + +/* ../engine/world.c:53 */ +void RemoveLink(link_t *l) +{ + l->next->prev = l->prev; + l->prev->next = l->next; +} + +/* ../engine/world.c:59 */ +void InsertLinkBefore(link_t *l, link_t *before) +{ + l->next = before; + l->prev = before->prev; + l->next->prev = l; + l->prev->next = l; +} + +/* ../engine/world.c:66 */ +NOXREF void InsertLinkAfter(link_t *l, link_t *after) +{ + l->prev = after; + l->next = after->next; + + after->next = l; + l->next->prev = l; +} + +/* ../engine/world.c:94 */ +void SV_InitBoxHull(void) +{ + box_hull.clipnodes = &box_clipnodes[0]; + box_hull.planes = &box_planes[0]; + box_hull.firstclipnode = 0; + box_hull.lastclipnode = 5; + Q_memcpy(&beam_hull, &box_hull, sizeof(beam_hull)); + beam_hull.planes = &beam_planes[0]; + + for (int i = 0; i < 6; i++) + { + int side = i & 1; + box_clipnodes[i].planenum = i; + box_clipnodes[i].children[side] = -1; + box_clipnodes[i].children[side ^ 1] = (i != 5) ? i + 1 : CONTENTS_SOLID; + box_planes[i].type = i >> 1; + beam_planes[i].type = 5; + box_planes[i].normal[i >> 1] = 1.0f; + } +} + +/* ../engine/world.c:135 */ +hull_t *SV_HullForBox(const vec_t *mins, const vec_t *maxs) +{ + box_planes[0].dist = maxs[0]; + box_planes[1].dist = mins[0]; + box_planes[2].dist = maxs[1]; + box_planes[3].dist = mins[1]; + box_planes[4].dist = maxs[2]; + box_planes[5].dist = mins[2]; + return &box_hull; +} + +/* ../engine/world.c:148 */ +NOXREF hull_t *SV_HullForBeam(const vec_t *start, const vec_t *end, const vec_t *size) +{ + vec3_t tmp = { 0, 0, 0 }; + + beam_planes[0].normal[0] = end[0] - start[0]; + beam_planes[0].normal[1] = end[1] - start[1]; + beam_planes[0].normal[2] = end[2] - start[2]; + + VectorNormalize(beam_planes[0].normal); + + beam_planes[1].normal[0] = beam_planes[0].normal[0]; + beam_planes[1].normal[1] = beam_planes[0].normal[1]; + beam_planes[1].normal[2] = beam_planes[0].normal[2]; + + beam_planes[0].dist = _DotProduct((vec_t *)end, beam_planes[0].normal); + beam_planes[1].dist = _DotProduct((vec_t *)start, beam_planes[0].normal); + + if (fabs(beam_planes[0].normal[2]) < 0.9f) + tmp[2] = 1.0f; + else + tmp[0] = 1.0f; + + CrossProduct(beam_planes[0].normal, tmp, beam_planes[2].normal); + VectorNormalize(beam_planes[2].normal); + + beam_planes[3].normal[0] = beam_planes[2].normal[0]; + beam_planes[3].normal[1] = beam_planes[2].normal[1]; + beam_planes[3].normal[2] = beam_planes[2].normal[2]; + + beam_planes[2].dist = (start[0] + beam_planes[2].normal[0]) * beam_planes[2].normal[0] + (start[1] + beam_planes[2].normal[1]) * beam_planes[2].normal[1] + (start[2] + beam_planes[2].normal[2]) * beam_planes[2].normal[2]; + + tmp[0] = start[0] - beam_planes[2].normal[0]; + tmp[1] = start[1] - beam_planes[2].normal[1]; + tmp[2] = start[2] - beam_planes[2].normal[2]; + + beam_planes[3].dist = _DotProduct(tmp, beam_planes[2].normal); + CrossProduct(beam_planes[2].normal, beam_planes[0].normal, beam_planes[4].normal); + VectorNormalize(beam_planes[4].normal); + + beam_planes[5].normal[0] = beam_planes[4].normal[0]; + beam_planes[5].normal[1] = beam_planes[4].normal[1]; + beam_planes[5].normal[2] = beam_planes[4].normal[2]; + + beam_planes[4].dist = _DotProduct((vec_t *)start, beam_planes[4].normal); + beam_planes[5].dist = (start[0] - beam_planes[4].normal[0]) * beam_planes[4].normal[0] + (start[1] - beam_planes[4].normal[1]) * beam_planes[4].normal[1] + (start[2] - beam_planes[4].normal[2]) * beam_planes[4].normal[2]; + beam_planes[0].dist += fabs(beam_planes[0].normal[0] * size[0]) + fabs(beam_planes[0].normal[1] * size[1]) + fabs(beam_planes[0].normal[2] * size[2]); + + beam_planes[1].dist -= (fabs(beam_planes[1].normal[0] * size[0]) + fabs(beam_planes[1].normal[1] * size[1]) + fabs(beam_planes[1].normal[2] * size[2])); + beam_planes[2].dist += fabs(beam_planes[2].normal[0] * size[0]) + fabs(beam_planes[2].normal[1] * size[1]) + fabs(beam_planes[2].normal[2] * size[2]); + beam_planes[3].dist -= (fabs(beam_planes[3].normal[0] * size[0]) + fabs(beam_planes[3].normal[1] * size[1]) + fabs(beam_planes[3].normal[2] * size[2])); + beam_planes[4].dist += fabs(beam_planes[4].normal[0] * size[0]) + fabs(beam_planes[4].normal[1] * size[1]) + fabs(beam_planes[4].normal[2] * size[2]); + beam_planes[5].dist -= (fabs(beam_planes[4].normal[0] * size[0]) + fabs(beam_planes[4].normal[1] * size[1]) + fabs(beam_planes[4].normal[2] * size[2])); + + return &beam_hull; +} + +/* ../engine/world.c:201 */ +struct hull_s *SV_HullForBsp(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset) +{ + model_t *model; + hull_t *hull; + + model = g_psv.models[ent->v.modelindex]; + if (!model) + Sys_Error("Hit a %s with no model (%s)", &pr_strings[ent->v.classname], &pr_strings[ent->v.model]); + + if (model->type) + Sys_Error("Hit a %s with no model (%s)", &pr_strings[ent->v.classname], &pr_strings[ent->v.model]); + + float xSize = maxs[0] - mins[0]; + if (xSize > 8.0f) + { + if (xSize > 36.0f) + { + hull = &model->hulls[2]; + } + else + { + float zSize = maxs[2] - mins[2]; + if (zSize > 36.0f) + hull = &model->hulls[1]; + else + hull = &model->hulls[3]; + } + offset[0] = hull->clip_mins[0] - mins[0]; + offset[1] = hull->clip_mins[1] - mins[1]; + offset[2] = hull->clip_mins[2] - mins[2]; + } + else + { + hull = &model->hulls[0]; + offset[0] = model->hulls[0].clip_mins[0]; + offset[1] = model->hulls[0].clip_mins[1]; + offset[2] = model->hulls[0].clip_mins[2]; + } + + offset[0] = ent->v.origin[0] + offset[0]; + offset[1] = ent->v.origin[1] + offset[1]; + offset[2] = ent->v.origin[2] + offset[2]; + return hull; +} + +/* ../engine/world.c:251 */ +hull_t *SV_HullForEntity(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset) +{ + vec3_t hullmins; + vec3_t hullmaxs; + + if (ent->v.solid == SOLID_BSP) + { + if (ent->v.movetype != MOVETYPE_PUSH && ent->v.movetype != MOVETYPE_PUSHSTEP) + Sys_Error("SOLID_BSP without MOVETYPE_PUSH"); + + return SV_HullForBsp(ent, mins, maxs, offset); + } + + hullmins[0] = ent->v.mins[0] - maxs[0]; + hullmins[1] = ent->v.mins[1] - maxs[1]; + hullmins[2] = ent->v.mins[2] - maxs[2]; + hullmaxs[0] = ent->v.maxs[0] - mins[0]; + hullmaxs[1] = ent->v.maxs[1] - mins[1]; + hullmaxs[2] = ent->v.maxs[2] - mins[2]; + offset[0] = ent->v.origin[0]; + offset[1] = ent->v.origin[1]; + offset[2] = ent->v.origin[2]; + return SV_HullForBox(hullmins, hullmaxs); +} + +/* ../engine/world.c:308 */ +areanode_t *SV_CreateAreaNode(int depth, vec_t *mins, vec_t *maxs) +{ + areanode_t *anode; + vec3_t mins1; + vec3_t maxs2; + vec3_t size; + vec3_t maxs1; + vec3_t mins2; + float fmid; + + anode = &sv_areanodes[sv_numareanodes++]; + ClearLink(&anode->trigger_edicts); + ClearLink(&anode->solid_edicts); + if (depth == 4) + { + anode->axis = -1; + anode->children[0] = NULL; + anode->children[1] = NULL; + return anode; + } + + size[0] = maxs[0] - mins[0]; + size[1] = maxs[1] - mins[1]; + anode->axis = (size[0] <= size[1]) ? 1 : 0; + mins1[0] = mins[0]; + mins1[1] = mins[1]; + mins1[2] = mins[2]; + + mins2[0] = mins[0]; + mins2[1] = mins[1]; + mins2[2] = mins[2]; + + maxs1[0] = maxs[0]; + maxs1[1] = maxs[1]; + maxs1[2] = maxs[2]; + + maxs2[0] = maxs[0]; + maxs2[1] = maxs[1]; + maxs2[2] = maxs[2]; + + fmid = 0.5f * (mins[anode->axis] + maxs[anode->axis]); + mins2[anode->axis] = fmid; + maxs1[anode->axis] = fmid; + + anode->dist = fmid; + anode->children[0] = SV_CreateAreaNode(depth + 1, mins2, maxs2); + anode->children[1] = SV_CreateAreaNode(depth + 1, mins1, maxs1); + + return anode; + +} + +/* ../engine/world.c:353 */ +void SV_ClearWorld(void) +{ + SV_InitBoxHull(); + Q_memset(sv_areanodes, 0, sizeof(sv_areanodes)); + sv_numareanodes = 0; + SV_CreateAreaNode(0, g_psv.worldmodel->mins, g_psv.worldmodel->maxs); +} + +/* ../engine/world.c:369 */ +void SV_UnlinkEdict(edict_t *ent) +{ + if (ent->area.prev) + { + RemoveLink(&ent->area); + ent->area.next = NULL; + ent->area.prev = NULL; + } +} + +/* ../engine/world.c:383 */ +void SV_TouchLinks(edict_t *ent, areanode_t *node) +{ + edict_t *touch; + model_t *pModel; + link_t *next; + + for (link_t *l = node->trigger_edicts.next; l != &node->trigger_edicts; l = next) + { + next = l->next; + touch = (edict_t *)((char *)l - offsetof(edict_t, area)); + if (touch == ent) + continue; + + if (ent->v.groupinfo != 0 && touch->v.groupinfo != 0) + { + if (g_groupop) + { + if (g_groupop == GROUP_OP_NAND && (ent->v.groupinfo & touch->v.groupinfo)) + continue; + } + else + { + if (!(ent->v.groupinfo & touch->v.groupinfo)) + continue; + } + } + + if (touch->v.solid == SOLID_TRIGGER + && ent->v.absmin[0] <= touch->v.absmax[0] + && ent->v.absmin[1] <= touch->v.absmax[1] + && ent->v.absmin[2] <= touch->v.absmax[2] + && ent->v.absmax[0] >= touch->v.absmin[0] + && ent->v.absmax[1] >= touch->v.absmin[1] + && ent->v.absmax[2] >= touch->v.absmin[2]) + { + pModel = g_psv.models[touch->v.modelindex]; + + if (pModel && pModel->type == mod_brush) + { + vec3_t offset; + hull_t *hull = SV_HullForBsp(touch, ent->v.mins, ent->v.maxs, offset); + + vec3_t localPosition; + localPosition[0] = ent->v.origin[0] - offset[0]; + localPosition[1] = ent->v.origin[1] - offset[1]; + localPosition[2] = ent->v.origin[2] - offset[2]; + + int contents = SV_HullPointContents(hull, hull->firstclipnode, localPosition); + if (contents != CONTENTS_SOLID) + continue; + } + + gGlobalVariables.time = (float)g_psv.time; + gEntityInterface.pfnTouch(touch, ent); + } + } + + if (node->axis != -1) + { + if (ent->v.absmax[node->axis] > node->dist) + SV_TouchLinks(ent, node->children[0]); + + if (node->dist > ent->v.absmin[node->axis]) + SV_TouchLinks(ent, node->children[1]); + } +} + +/* ../engine/world.c:467 */ +void SV_FindTouchedLeafs(edict_t *ent, mnode_t *node, int *topnode) +{ + mplane_t *splitplane; + int sides; + + if (node->contents == CONTENTS_SOLID) + return; + + if (node->contents < 0) + { + if (ent->num_leafs < MAX_ENT_LEAFS) + { + mleaf_t *leaf = (mleaf_t *)node; + int leafnum = leaf - g_psv.worldmodel->leafs - 1; + ent->leafnums[ent->num_leafs] = leafnum; + ent->num_leafs++; + } + else + { + ent->num_leafs = MAX_ENT_LEAFS + 1; + } + return; + } + + splitplane = node->plane; + if (splitplane->type >= 3) + { + sides = BoxOnPlaneSide(ent->v.absmin, ent->v.absmax, splitplane); + } + else + { + if (splitplane->dist > ent->v.absmin[splitplane->type]) + { + if (splitplane->dist < ent->v.absmax[splitplane->type]) + { + sides = 3; + } + else + { + sides = 2; + } + } + else + { + sides = 1; + } + } + + if (sides == 3) + { + if (*topnode == -1) + *topnode = node - g_psv.worldmodel->nodes; + } + + if (sides & 1) + SV_FindTouchedLeafs(ent, node->children[0], topnode); + + if (sides & 2) + SV_FindTouchedLeafs(ent, node->children[1], topnode); +} + +/* ../engine/world.c:517 */ +void SV_LinkEdict(edict_t *ent, qboolean touch_triggers) +{ + static int iTouchLinkSemaphore = 0; + areanode_t *node; + int topnode; + + if (ent->area.prev) + SV_UnlinkEdict(ent); + + if (ent == &g_psv.edicts[0] || ent->free) + return; + + gEntityInterface.pfnSetAbsBox(ent); + if (ent->v.movetype == MOVETYPE_FOLLOW && ent->v.aiment) + { + ent->headnode = ent->v.aiment->headnode; + ent->num_leafs = ent->v.aiment->num_leafs; + Q_memcpy(ent->leafnums, ent->v.aiment->leafnums, sizeof(ent->leafnums)); + } + else + { + ent->num_leafs = 0; + ent->headnode = -1; + topnode = -1; + if (ent->v.modelindex) + SV_FindTouchedLeafs(ent, g_psv.worldmodel->nodes, &topnode); + + if (ent->num_leafs > MAX_ENT_LEAFS) + { + ent->num_leafs = 0; + ent->headnode = (int)topnode; + Q_memset(ent->leafnums, -1, sizeof(ent->leafnums)); + } + } + + if (ent->v.solid == SOLID_NOT && ent->v.skin >= -1) + return; + + if (ent->v.solid != SOLID_BSP || g_psv.models[ent->v.modelindex] || Q_strlen(&pr_strings[ent->v.model])) + { + node = sv_areanodes; + while (1) + { + if (node->axis == -1) + break; + + if (ent->v.absmin[node->axis] <= node->dist) + { + if (ent->v.absmax[node->axis] >= node->dist) + break; + node = node->children[1]; + } + else + { + node = node->children[0]; + } + } + + InsertLinkBefore(&ent->area, (ent->v.solid == SOLID_TRIGGER) ? &node->trigger_edicts : &node->solid_edicts); + if (touch_triggers) + { + if (!iTouchLinkSemaphore) + { + iTouchLinkSemaphore = 1; + SV_TouchLinks(ent, sv_areanodes); + iTouchLinkSemaphore = 0; + } + } + } + else + { + Con_DPrintf("Inserted %s with no model\n", &pr_strings[ent->v.classname]); + } +} + +/* ../engine/world.c:630 */ +int SV_HullPointContents(hull_t *hull, int num, const vec_t *p) +{ + dclipnode_t *node; + mplane_t *plane; + float d; + + int i = num; + while (i >= 0) + { + if (hull->firstclipnode > i || hull->lastclipnode < i) + Sys_Error(__FUNCTION__ ": bad node number"); + node = &hull->clipnodes[i]; + plane = &hull->planes[node->planenum]; + if (plane->type > 2) + d = plane->normal[0] * *p + plane->normal[1] * p[1] + plane->normal[2] * p[2] - plane->dist; + else + d = p[plane->type] - plane->dist; + i = node->children[(d >= 0.0f) ? 0 : 1]; + } + + return i; +} + +/* ../engine/world.c:663 */ +int SV_LinkContents(areanode_t *node, const vec_t *pos) +{ + link_t *l; + link_t *next; + edict_t *touch; + model_t *pModel; + hull_t *hull; + vec3_t localPosition; + vec3_t offset; + + for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) + { + next = l->next; + touch = (edict_t *)((char *)l - offsetof(edict_t, area)); + if (!touch->v.solid) + { + if (touch->v.groupinfo) + { + if (g_groupop) + { + if (g_groupop == GROUP_OP_NAND && (touch->v.groupinfo & g_groupmask)) + continue; + } + else + { + if (!(touch->v.groupinfo & g_groupmask)) + continue; + } + } + pModel = g_psv.models[touch->v.modelindex]; + if (pModel + && !pModel->type + && pos[0] <= (double)touch->v.absmax[0] + && pos[1] <= (double)touch->v.absmax[1] + && pos[2] <= (double)touch->v.absmax[2] + && pos[0] >= (double)touch->v.absmin[0] + && pos[1] >= (double)touch->v.absmin[1] + && pos[2] >= (double)touch->v.absmin[2]) + { + int contents = touch->v.skin; + if (contents < -100 || contents > 100) + Con_DPrintf("Invalid contents on trigger field: %s\n", &pr_strings[touch->v.classname]); + hull = SV_HullForBsp(touch, vec3_origin, vec3_origin, offset); + localPosition[0] = pos[0] - offset[0]; + localPosition[1] = pos[1] - offset[1]; + localPosition[2] = pos[2] - offset[2]; + if (SV_HullPointContents(hull, hull->firstclipnode, localPosition) != -1) + return contents; + } + } + } + + + if (node->axis == -1) + return -1; + + if (pos[node->axis] > node->dist) + return SV_LinkContents(node->children[0], pos); + + if (pos[node->axis] < node->dist) + return SV_LinkContents(node->children[1], pos); + + return -1; +} + +/* ../engine/world.c:738 */ +int SV_PointContents(const vec_t *p) +{ + int cont; + int entityContents; + + cont = SV_HullPointContents(g_psv.worldmodel->hulls, 0, p); + if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) + { + cont = CONTENTS_WATER; + } + else + { + if (cont == CONTENTS_SOLID) + return CONTENTS_SOLID; + } + + entityContents = SV_LinkContents(&sv_areanodes[0], p); + return (entityContents != -1) ? entityContents : cont; +} + +/* ../engine/world.c:764 */ +edict_t *SV_TestEntityPosition(edict_t *ent) +{ + trace_t trace; + qboolean monsterClip; + + monsterClip = (ent->v.flags & FL_MONSTERCLIP) ? TRUE : FALSE; + trace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent, monsterClip); + if (trace.startsolid) + { + SV_SetGlobalTrace(&trace); + return trace.ent; + } + + return NULL; +} + +/* ../engine/world.c:804 */ +qboolean SV_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, trace_t *trace) +{ + dclipnode_t *node; + mplane_t *plane; + float t2; + vec3_t mid; + float frac; + float t1; + signed int side; + float midf; + float pdif = p2f - p1f; + + if (num >= 0) + { + if (num < hull->firstclipnode || num > hull->lastclipnode || !hull->planes) + Sys_Error(__FUNCTION__ ": bad node number"); + + node = &hull->clipnodes[num]; + plane = &hull->planes[hull->clipnodes[num].planenum]; + if (plane->type >= 3) + { + t1 = p1[1] * plane->normal[1] + p1[2] * plane->normal[2] + p1[0] * plane->normal[0] - plane->dist; + t2 = p2[1] * plane->normal[1] + p2[2] * plane->normal[2] + plane->normal[0] * p2[0] - plane->dist; + } + else + { + t1 = p1[plane->type] - plane->dist; + t2 = p2[plane->type] - plane->dist; + } + if (t1 >= 0.0f && t2 >= 0.0f) + return SV_RecursiveHullCheck(hull, node->children[0], p1f, p2f, p1, p2, trace); + + if (t1 >= 0.0f) + { + midf = t1 - 0.03125f; + } + else + { + if (t2 < 0.0f) + return SV_RecursiveHullCheck(hull, node->children[1], p1f, p2f, p1, p2, trace); + + midf = t1 + 0.03125f; + } + + midf = midf / (t1 - t2); + if (midf >= 0.0f) + { + if (midf > 1.0f) + midf = 1.0f; + } + else + { + midf = 0.0f; + } + if (((*reinterpret_cast(&midf)) & nanmask) != nanmask) + { + frac = pdif * midf + p1f; + mid[0] = (p2[0] - p1[0]) * midf + p1[0]; + mid[1] = (p2[1] - p1[1]) * midf + p1[1]; + mid[2] = (p2[2] - p1[2]) * midf + p1[2]; + side = (t1 < 0.0f) ? 1 : 0; + if (SV_RecursiveHullCheck(hull, node->children[side], p1f, frac, p1, mid, trace)) + { + if (SV_HullPointContents(hull, node->children[side ^ 1], mid) != CONTENTS_SOLID) + return SV_RecursiveHullCheck(hull, node->children[side ^ 1], frac, p2f, mid, p2, trace); + + if (!trace->allsolid) + { + if (side) + { + trace->plane.normal[0] = vec3_origin[0] - plane->normal[0]; + trace->plane.normal[1] = vec3_origin[1] - plane->normal[1]; + trace->plane.normal[2] = vec3_origin[2] - plane->normal[2]; + trace->plane.dist = -plane->dist; + } + else + { + trace->plane.normal[0] = plane->normal[0]; + trace->plane.normal[1] = plane->normal[1]; + trace->plane.normal[2] = plane->normal[2]; + trace->plane.dist = plane->dist; + } + + while (1) + { + if (SV_HullPointContents(hull, hull->firstclipnode, mid) != CONTENTS_SOLID) + { + trace->fraction = frac; + trace->endpos[0] = mid[0]; + trace->endpos[1] = mid[1]; + trace->endpos[2] = mid[2]; + return FALSE; + } + midf -= 0.1f; + if (midf < 0.0f) + break; + frac = pdif * midf + p1f; + mid[0] = (p2[0] - p1[1]) * midf + p1[0]; + mid[1] = (p2[1] - p1[1]) * midf + p1[1]; + mid[2] = (p2[2] - p1[2]) * midf + p1[2]; + } + trace->fraction = frac; + trace->endpos[0] = mid[0]; + trace->endpos[1] = mid[1]; + trace->endpos[2] = mid[2]; + Con_DPrintf("backup past 0\n"); + return FALSE; + } + } + } + return FALSE; + } + + if (num == CONTENTS_SOLID) + { + trace->startsolid = TRUE; + } + else + { + trace->allsolid = FALSE; + if (num == CONTENTS_EMPTY) + { + trace->inopen = TRUE; + return TRUE; + } + if (num != CONTENTS_TRANSLUCENT) + { + trace->inwater = TRUE; + return TRUE; + } + } + return TRUE; +} + +/* ../engine/world.c:948 */ +void SV_SingleClipMoveToEntity(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, trace_t *trace) +{ + hull_t *hull; + trace_t testtrace; + vec3_t offset; + int rotated; + int closest; + vec3_t end_l; + vec3_t start_l; + int numhulls; + + Q_memset(trace, 0, sizeof(trace_t)); + trace->fraction = 1.0f; + trace->allsolid = TRUE; + trace->endpos[0] = end[0]; + trace->endpos[1] = end[1]; + trace->endpos[2] = end[2]; + if (g_psv.models[ent->v.modelindex]->type == mod_studio) + { + hull = SV_HullForStudioModel(ent, mins, maxs, offset, &numhulls); + } + else + { + hull = SV_HullForEntity(ent, mins, maxs, offset); + numhulls = 1; + } + start_l[0] = start[0] - offset[0]; + start_l[1] = start[1] - offset[1]; + start_l[2] = start[2] - offset[2]; + end_l[0] = end[0] - offset[0]; + end_l[1] = end[1] - offset[1]; + end_l[2] = end[2] - offset[2]; + if (ent->v.solid == SOLID_BSP && (ent->v.angles[0] != 0.0f || ent->v.angles[1] != 0.0f || ent->v.angles[2] != 0.0f)) + { + vec3_t right; + vec3_t forward; + vec3_t up; + vec3_t temp; + + AngleVectors(ent->v.angles, forward, right, up); + + temp[0] = start_l[0]; temp[1] = start_l[1]; temp[2] = start_l[2]; + start_l[0] = forward[2] * temp[2] + forward[1] * temp[1] + forward[0] * temp[0]; + start_l[1] = -(right[0] * temp[0] + right[2] * temp[2] + right[1] * temp[1]); + start_l[2] = up[1] * temp[1] + up[0] * temp[0] + up[2] * temp[2]; + + temp[0] = end_l[0]; temp[1] = end_l[1]; temp[2] = end_l[2]; + end_l[0] = forward[2] * temp[2] + forward[1] * temp[1] + forward[0] * temp[0]; + end_l[1] = -(right[0] * temp[0] + right[2] * temp[2] + right[1] * temp[1]); + end_l[2] = up[1] * temp[1] + up[0] * temp[0] + up[2] * temp[2]; + + rotated = 1; + } + else + { + rotated = 0; + } + + if (numhulls == 1) + { + SV_RecursiveHullCheck(hull, hull->firstclipnode, 0.0f, 1.0f, start_l, end_l, trace); + } + else + { + closest = 0; + for (int i = 0; i < numhulls; i++) + { + Q_memset(&testtrace, 0, sizeof(trace_t)); + testtrace.endpos[0] = end[0]; + testtrace.endpos[1] = end[1]; + testtrace.endpos[2] = end[2]; + testtrace.fraction = 1.0f; + testtrace.allsolid = TRUE; + SV_RecursiveHullCheck(&hull[i], hull[i].firstclipnode, 0.0f, 1.0f, start_l, end_l, &testtrace); + if (i == 0 || testtrace.allsolid || testtrace.startsolid || testtrace.fraction < trace->fraction) + { + int isSolid = trace->startsolid; + memcpy(trace, &testtrace, sizeof(trace_t)); + if (isSolid) + trace->startsolid = TRUE; + closest = i; + } + } + + trace->hitgroup = SV_HitgroupForStudioHull(closest); + } + + if (trace->fraction != 1.0f) + { + if (rotated) + { + vec3_t right; + vec3_t forward; + vec3_t up; + vec3_t temp; + + AngleVectorsTranspose(ent->v.angles, up, right, forward); + temp[0] = trace->plane.normal[0]; + temp[1] = trace->plane.normal[1]; + temp[2] = trace->plane.normal[2]; + + trace->plane.normal[0] = up[2] * temp[2] + up[1] * temp[1] + up[0] * temp[0]; + trace->plane.normal[1] = right[2] * temp[2] + right[1] * temp[1] + right[0] * temp[0]; + trace->plane.normal[2] = forward[2] * temp[2] + forward[1] * temp[1] + forward[0] * temp[0]; + } + + trace->endpos[0] = (end[0] - start[0]) * trace->fraction + start[0]; + trace->endpos[1] = (end[1] - start[1]) * trace->fraction + start[1]; + trace->endpos[2] = (end[2] - start[2]) * trace->fraction + start[2]; + } + + if (trace->fraction < 1.0f || trace->startsolid) + trace->ent = ent; +} + +/* ../engine/world.c:1082 */ +trace_t SV_ClipMoveToEntity(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end) +{ + trace_t goodtrace; + SV_SingleClipMoveToEntity(ent, start, mins, maxs, end, &goodtrace); + + return goodtrace; +} + +/* ../engine/world.c:1148 */ +void SV_ClipToLinks(areanode_t *node, moveclip_t *clip) +{ + link_t *l; + link_t *next; + + for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) + { + next = l->next; + edict_t *touch = (edict_t *)((char *)l - offsetof(edict_t, area)); + if (touch->v.groupinfo && clip->passedict && clip->passedict->v.groupinfo) + { + if (g_groupop) + { + if (g_groupop == GROUP_OP_NAND && (clip->passedict->v.groupinfo & touch->v.groupinfo)) + continue; + } + else + { + if (!(clip->passedict->v.groupinfo & touch->v.groupinfo)) + continue; + } + } + + if (touch->v.solid == SOLID_NOT) + continue; + + if (touch == clip->passedict) + continue; + + if (touch->v.solid == SOLID_TRIGGER) + Sys_Error("Trigger in clipping list"); + + if (gNewDLLFunctions.pfnShouldCollide && !gNewDLLFunctions.pfnShouldCollide(touch, clip->passedict)) + return; + + if (touch->v.solid == SOLID_BSP) + { + if ((touch->v.flags & FL_MONSTERCLIP) && !clip->monsterClipBrush) + continue; + } + else + { + if (clip->type == 1 && touch->v.movetype != MOVETYPE_PUSHSTEP) + continue; + } + + if ((!clip->ignoretrans || !touch->v.rendermode || (touch->v.flags & FL_WORLDBRUSH)) + && clip->boxmins[0] <= touch->v.absmax[0] + && clip->boxmins[1] <= touch->v.absmax[1] + && clip->boxmins[2] <= touch->v.absmax[2] + && clip->boxmaxs[0] >= touch->v.absmin[0] + && clip->boxmaxs[1] >= touch->v.absmin[1] + && clip->boxmaxs[2] >= touch->v.absmin[2] + && (touch->v.solid == SOLID_SLIDEBOX || SV_CheckSphereIntersection(touch, clip->start, clip->end)) + && (!clip->passedict || clip->passedict->v.size[0] == 0.0f || touch->v.size[0] != 0.0f)) + { + if (clip->trace.allsolid) + return; + + if (clip->passedict && (touch->v.owner == clip->passedict || clip->passedict->v.owner == touch)) + continue; + + trace_t trace; + if (touch->v.flags & FL_MONSTER) + trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins2, clip->maxs2, clip->end); + else + trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins, clip->maxs, clip->end); + + if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) + { + int oldStartSolid = clip->trace.startsolid; + trace.ent = touch; + clip->trace = trace; + if (oldStartSolid) + clip->trace.startsolid = TRUE; + } + } + } + + if (node->axis != -1) + { + if (clip->boxmaxs[node->axis] > node->dist) + SV_ClipToLinks(node->children[0], clip); + + if (node->dist > clip->boxmins[node->axis]) + SV_ClipToLinks(node->children[1], clip); + } +} + +/* ../engine/world.c:1267 */ +void SV_ClipToWorldbrush(areanode_t *node, moveclip_t *clip) +{ + link_t *l; + link_t *next; + + for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) + { + next = l->next; + edict_t *touch = (edict_t *)((char *)l - offsetof(edict_t, area)); + + if (touch->v.solid != SOLID_BSP) + continue; + + if (!(touch->v.flags & FL_WORLDBRUSH)) + continue; + + if (clip->boxmins[0] <= touch->v.absmax[0] + && clip->boxmins[1] <= touch->v.absmax[1] + && clip->boxmins[2] <= touch->v.absmax[2] + && clip->boxmaxs[0] >= touch->v.absmin[0] + && clip->boxmaxs[1] >= touch->v.absmin[1] + && clip->boxmaxs[2] >= touch->v.absmin[2]) + { + if (clip->trace.allsolid) + return; + + trace_t trace = SV_ClipMoveToEntity(touch, clip->start, clip->mins, clip->maxs, clip->end); + if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) + { + int oldSolid = clip->trace.startsolid; + trace.ent = touch; + clip->trace = trace; + if (oldSolid) + clip->trace.startsolid = TRUE; + } + } + } + + if (node->axis != -1) + { + if (clip->boxmaxs[node->axis] > node->dist) + SV_ClipToWorldbrush(node->children[0], clip); + + if (node->dist > clip->boxmins[node->axis]) + SV_ClipToWorldbrush(node->children[1], clip); + } +} + +/* ../engine/world.c:1330 */ +void SV_MoveBounds(const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, vec_t *boxmins, vec_t *boxmaxs) +{ + for (int i = 0; i < 3; i++) + { + if (end[i] > start[i]) + { + boxmins[i] = start[i] + mins[i] - 1.0f; + boxmaxs[i] = end[i] + maxs[i] + 1.0f; + } + else + { + boxmins[i] = end[i] + mins[i] - 1.0f; + boxmaxs[i] = start[i] + maxs[i] + 1.0f; + } + } +} + +/* ../engine/world.c:1364 */ +trace_t SV_MoveNoEnts(const vec_t *start, vec_t *mins, vec_t *maxs, const vec_t *end, int type, edict_t *passedict) +{ + moveclip_t clip; + vec3_t worldEndPoint; + float worldFraction; + + Q_memset(&clip, 0, sizeof(clip)); + clip.trace = SV_ClipMoveToEntity(g_psv.edicts, start, mins, maxs, end); + if (clip.trace.fraction != 0.0f) + { + worldEndPoint[0] = clip.trace.endpos[0]; + worldEndPoint[2] = clip.trace.endpos[2]; + worldEndPoint[1] = clip.trace.endpos[1]; + clip.end = worldEndPoint; + + clip.ignoretrans = type >> 8; + worldFraction = clip.trace.fraction; + clip.type = type; + clip.passedict = passedict; + + clip.mins2[0] = mins[0]; + clip.mins2[1] = mins[1]; + clip.mins2[2] = mins[2]; + clip.maxs2[0] = maxs[0]; + clip.maxs2[1] = maxs[1]; + clip.maxs2[2] = maxs[2]; + + clip.trace.fraction = 1.0f; + clip.start = start; + clip.mins = mins; + clip.maxs = maxs; + clip.monsterClipBrush = FALSE; + + SV_MoveBounds(start, clip.mins2, clip.maxs2, worldEndPoint, clip.boxmins, clip.boxmaxs); + SV_ClipToWorldbrush(sv_areanodes, &clip); + + gGlobalVariables.trace_ent = clip.trace.ent; + clip.trace.fraction = worldFraction * clip.trace.fraction; + } + + return clip.trace; +} + +/* ../engine/world.c:1415 */ +trace_t SV_Move(const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, int type, edict_t *passedict, qboolean monsterClipBrush) +{ + moveclip_t clip; + vec3_t worldEndPoint; + float worldFraction; + + Q_memset(&clip, 0, sizeof(clip)); + clip.trace = SV_ClipMoveToEntity(g_psv.edicts, start, mins, maxs, end); + if (clip.trace.fraction != 0.0f) + { + worldEndPoint[0] = clip.trace.endpos[0]; + worldEndPoint[1] = clip.trace.endpos[1]; + worldEndPoint[2] = clip.trace.endpos[2]; + clip.end = worldEndPoint; + worldFraction = clip.trace.fraction; + + clip.type = (unsigned char)type; + clip.ignoretrans = type >> 8; + clip.trace.fraction = 1.0f; + clip.start = start; + clip.mins = mins; + clip.maxs = maxs; + clip.passedict = passedict; + clip.monsterClipBrush = monsterClipBrush; + if (type == 2) + { + for (int i = 0; i < 3; i++) + { + clip.mins2[i] = -15.0f; + clip.maxs2[i] = +15.0f; + } + } + else + { + clip.mins2[0] = mins[0]; + clip.mins2[1] = mins[1]; + clip.mins2[2] = mins[2]; + clip.maxs2[0] = maxs[0]; + clip.maxs2[1] = maxs[1]; + clip.maxs2[2] = maxs[2]; + } + SV_MoveBounds(start, clip.mins2, clip.maxs2, worldEndPoint, clip.boxmins, clip.boxmaxs); + SV_ClipToLinks(sv_areanodes, &clip); + gGlobalVariables.trace_ent = clip.trace.ent; + clip.trace.fraction = worldFraction * clip.trace.fraction; + } + + return clip.trace; +} diff --git a/rehlds/engine/world.h b/rehlds/engine/world.h new file mode 100644 index 0000000..25c3d3e --- /dev/null +++ b/rehlds/engine/world.h @@ -0,0 +1,127 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef WORLD_H +#define WORLD_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "model.h" + + +/* ../engine/world.h:15 */ +typedef struct areanode_s +{ + int axis; + float dist; + struct areanode_s *children[2]; + link_t trigger_edicts; + link_t solid_edicts; +} areanode_t; + +/* ../engine/world.c:20 */ +typedef struct moveclip_s // TODO: Move it to world.cpp someday +{ + vec3_t boxmins; + vec3_t boxmaxs; + const float *mins; + const float *maxs; + vec3_t mins2; + vec3_t maxs2; + const float *start; + const float *end; + trace_t trace; + short int type; + short int ignoretrans; + edict_t *passedict; + qboolean monsterClipBrush; +} moveclip_t; + +typedef dclipnode_t box_clipnodes_t[6]; +typedef mplane_t box_planes_t[6]; +typedef mplane_t beam_planes_t[6]; + +#ifdef HOOK_ENGINE + +#define box_hull (*pbox_hull) +#define beam_hull (*pbeam_hull) +#define box_clipnodes (*pbox_clipnodes) +#define box_planes (*pbox_planes) +#define beam_planes (*pbeam_planes) +#define sv_areanodes (*psv_areanodes) +#define sv_numareanodes (*psv_numareanodes) + +#endif // HOOK_ENGINE + +extern hull_t box_hull; +extern hull_t beam_hull; +extern box_clipnodes_t box_clipnodes; +extern box_planes_t box_planes; +extern beam_planes_t beam_planes; +extern areanode_t sv_areanodes[32]; +extern int sv_numareanodes; +/* +hull_t box_hull; +hull_t beam_hull; +dclipnode_t box_clipnodes[6]; +mplane_t box_planes[6]; +mplane_t beam_planes[6]; +*/ + + +void ClearLink(link_t *l); +void RemoveLink(link_t *l); +void InsertLinkBefore(link_t *l, link_t *before); +NOXREF void InsertLinkAfter(link_t *l, link_t *after); +void SV_InitBoxHull(void); +hull_t *SV_HullForBox(const vec_t *mins, const vec_t *maxs); +NOXREF hull_t *SV_HullForBeam(const vec_t *start, const vec_t *end, const vec_t *size); +struct hull_s *SV_HullForBsp(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset); +hull_t *SV_HullForEntity(edict_t *ent, const vec_t *mins, const vec_t *maxs, vec_t *offset); +areanode_t *SV_CreateAreaNode(int depth, vec_t *mins, vec_t *maxs); +void SV_ClearWorld(void); +void SV_UnlinkEdict(edict_t *ent); +void SV_TouchLinks(edict_t *ent, areanode_t *node); +void SV_FindTouchedLeafs(edict_t *ent, mnode_t *node, int *topnode); +void SV_LinkEdict(edict_t *ent, qboolean touch_triggers); +int SV_HullPointContents(hull_t *hull, int num, const vec_t *p); +int SV_LinkContents(areanode_t *node, const vec_t *pos); +int SV_PointContents(const vec_t *p); +edict_t *SV_TestEntityPosition(edict_t *ent); +qboolean SV_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, trace_t *trace); +void SV_SingleClipMoveToEntity(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, trace_t *trace); +trace_t SV_ClipMoveToEntity(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end); +void SV_ClipToLinks(areanode_t *node, moveclip_t *clip); +void SV_ClipToWorldbrush(areanode_t *node, moveclip_t *clip); +void SV_MoveBounds(const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, vec_t *boxmins, vec_t *boxmaxs); +trace_t SV_MoveNoEnts(const vec_t *start, vec_t *mins, vec_t *maxs, const vec_t *end, int type, edict_t *passedict); +trace_t SV_Move(const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, int type, edict_t *passedict, qboolean monsterClipBrush); + +#endif // WORLD_H diff --git a/rehlds/engine/zone.cpp b/rehlds/engine/zone.cpp new file mode 100644 index 0000000..93af9bd --- /dev/null +++ b/rehlds/engine/zone.cpp @@ -0,0 +1,1205 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifndef Z_Functions_region + +/* +============================================================================== + +ZONE MEMORY ALLOCATION + +There is never any space between memblocks, and there will never be two +contiguous free memblocks. + +The rover can be left pointing at a non-empty block + +The zone calls are pretty much only used for small strings and structures, +all big things are allocated on the hunk. +============================================================================== +*/ + +#define ZONEID 0x001d4a11 +#define MINFRAGMENT 64 + +typedef struct memblock_s +{ + int size; + int tag; + int id; + memblock_t *next; + memblock_t *prev; + int pad; +} memblock_t; + +typedef struct memzone_s +{ + int size; + memblock_t blocklist; + memblock_t *rover; +} memzone_t; + +/* +* Globals initialization +*/ +#ifndef HOOK_ENGINE + +cvar_t mem_dbgfile = { "mem_dbgfile", ".\\mem.txt", 0, 0.0f, NULL }; + +#else //HOOK_ENGINE + +cvar_t mem_dbgfile; + +#endif //HOOK_ENGINE + +memzone_t *mainzone; + +/* ../engine/zone.c:71 */ +void Z_ClearZone(memzone_t *zone, int size) +{ + memblock_t *block = (memblock_t *)&zone[1]; + + zone->blocklist.prev = zone->blocklist.next = zone->rover = block; + zone->blocklist.size = zone->blocklist.id = 0; + zone->blocklist.tag = 1; + + block->prev = block->next = &zone->blocklist; + block->tag = 0; + block->id = ZONEID; + block->size = size - sizeof(memzone_t); +} + +/* ../engine/zone.c:96 */ +void Z_Free(void *ptr) +{ + if (!ptr) + { + Sys_Error(__FUNCTION__ ": NULL pointer"); + } + + memblock_t *block = (memblock_t *)((char *)ptr - sizeof(memblock_t)); + + if (block->id != ZONEID) + { + Sys_Error(__FUNCTION__ ": freed a pointer without ZONEID"); + } + + if (!block->tag) + { + Sys_Error(__FUNCTION__ ": freed a freed pointer"); + } + + block->tag = 0; + + memblock_t *otherblock = block->prev; + + if (!otherblock->tag) + { + otherblock->size += block->size; + otherblock->next = block->next; + block->next->prev = otherblock; + + if (block == mainzone->rover) + { + mainzone->rover = otherblock; + } + + block = otherblock; + } + + otherblock = block->next; + + if (!otherblock->tag) + { + block->size += otherblock->size; + block->next = otherblock->next; + otherblock->next->prev = block; + + if (otherblock == mainzone->rover) + { + mainzone->rover = block; + } + } +} + +/* ../engine/zone.c:139 */ +void *Z_Malloc(int size) +{ + Z_CheckHeap(); + + void *buf = Z_TagMalloc(size, 1); + + if (!buf) + { + Sys_Error(__FUNCTION__ ": failed on allocation of %i bytes", size); + } + + Q_memset(buf, 0, size); + return buf; +} + +/* ../engine/zone.c:152 */ +void *Z_TagMalloc(int size, int tag) +{ + int extra; + memblock_t *start, *rover, *newz, *base; + + if (tag == 0) + { + Sys_Error(__FUNCTION__ ": tried to use a 0 tag"); + } + + size += sizeof(memblock_t); + size += 4; + size = (size + 7) & ~7; + + base = rover = mainzone->rover; + start = base->prev; + + do + { + if (rover == start) + { + return(NULL); + } + + if (rover->tag) + { + base = rover = rover->next; + } + else + { + rover = rover->next; + } + } while (base->tag || base->size < size); + + extra = base->size - size; + + if (extra > MINFRAGMENT) + { + newz = (memblock_t *)((byte *)base + size); + newz->size = extra; + newz->tag = 0; + newz->prev = base; + newz->id = ZONEID; + newz->next = base->next; + newz->next->prev = newz; + base->next = newz; + base->size = size; + } + + base->tag = tag; + mainzone->rover = base->next; + base->id = ZONEID; + + // marker for memory trash testing + *(int *)((byte *)base + base->size - 4) = ZONEID; + + return (void *)((byte *)base + sizeof(memblock_t)); +} + +/* ../engine/zone.c:216 */ +NOXREF void Z_Print(memzone_t *zone) +{ + NOXREFCHECK; + + memblock_t *block; + Con_Printf("zone size: %i location: %p\n", mainzone->size, mainzone); + + for (block = zone->blocklist.next;; block = block->next) + { + Con_Printf("block:%p size:%7i tag:%3i\n", block, block->size, block->tag); + + if (block->next == &zone->blocklist) + { + break; // all blocks have been hit + } + + if ((byte *)block + block->size != (byte *)block->next) + { + Con_Printf("ERROR: block size does not touch the next block\n"); + } + + if (block->next->prev != block) + { + Con_Printf("ERROR: next block doesn't have proper back link\n"); + } + + if (!block->tag && !block->next->tag) + { + Con_Printf("ERROR: two consecutive free blocks\n"); + } + } +} + +/* ../engine/zone.c:244 */ +void Z_CheckHeap(void) +{ + memblock_t *block; + + for (block = mainzone->blocklist.next;; block = block->next) + { + if (block->next == &mainzone->blocklist) + { + break; + } + + if ((byte *)block + block->size != (byte *)block->next) + { + Sys_Error(__FUNCTION__ ": block size does not touch the next block\n"); + } + + if (block->next->prev != block) + { + Sys_Error(__FUNCTION__ ": next block doesn't have proper back link\n"); + } + + if (!block->tag && !block->next->tag) + { + Sys_Error(__FUNCTION__ ": two consecutive free blocks\n"); + } + } +} + +#endif // Z_Functions_region + +#ifndef Hunk_Functions_region + +#define HUNK_NAME_LEN 64 +#define HUNK_SENTINEL 0x1df001ed + +typedef struct hunk_s +{ + int sentinel; + int size; + char name[HUNK_NAME_LEN]; +} hunk_t; + +byte *hunk_base; +int hunk_size; + +int hunk_low_used; +int hunk_high_used; + +qboolean hunk_tempactive; +int hunk_tempmark; + +/* +============== +Hunk_Check + +Run consistency and sentinel trashing checks +============== +*/ + +/* ../engine/zone.c:291 */ +void Hunk_Check(void) +{ + hunk_t *h; + + for (h = (hunk_t *)hunk_base; (byte *)h != (hunk_base + hunk_low_used); h = (hunk_t *)((byte *)h + h->size)) + { + if (h->sentinel != HUNK_SENTINEL) + { + Sys_Error(__FUNCTION__ ": trahsed sentinel"); + } + + if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) + { + Sys_Error(__FUNCTION__ ": bad size"); + } + } +} + +/* +============== +Hunk_Print + +If "all" is specified, every single allocation is printed. +Otherwise, allocations with the same name will be totaled up before printing. +============== +*/ + +/* ../engine/zone.c:316 */ +NOXREF void Hunk_Print(qboolean all) +{ + NOXREFCHECK; + + hunk_t *h, *next, *endlow, *starthigh, *endhigh; + int count, sum; + int totalblocks; + char name[HUNK_NAME_LEN]; + + name[HUNK_NAME_LEN - 1] = 0; + count = 0; + sum = 0; + totalblocks = 0; + + h = (hunk_t *)hunk_base; + endlow = (hunk_t *)(hunk_base + hunk_low_used); + starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); + endhigh = (hunk_t *)(hunk_base + hunk_size); + + Con_Printf(" :%8i total hunk size\n", hunk_size); + Con_Printf("-------------------------\n"); + + while (true) + { + // + // skip to the high hunk if done with low hunk + // + if (h == endlow) + { + Con_Printf("-------------------------\n"); + Con_Printf(" :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used); + Con_Printf("-------------------------\n"); + h = starthigh; + } + + // + // if totally done, break + // + if (h == endhigh) + break; + + // + // run consistancy checks + // + if (h->sentinel != HUNK_SENTINEL) + Sys_Error(__FUNCTION__ ": trahsed sentinal"); + if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) + Sys_Error(__FUNCTION__ ": bad size"); + + next = (hunk_t *)((byte *)h + h->size); + count++; + totalblocks++; + sum += h->size; + + // + // print the single block + // + memcpy(name, h->name, HUNK_NAME_LEN); + if (all) + Con_Printf("%8p :%8i %8s\n", h, h->size, name); + + // + // print the total + // + if (next == endlow || next == endhigh || + strncmp(h->name, next->name, HUNK_NAME_LEN)) + { + if (!all) + Con_Printf(" :%8i %8s (TOTAL)\n", sum, name); + count = 0; + sum = 0; + } + + h = next; + } + + Con_Printf("-------------------------\n"); + Con_Printf("%8i total blocks\n", totalblocks); +} + +/* +=================== +Hunk_AllocName +=================== +*/ + +/* ../engine/zone.c:413 */ +void *Hunk_AllocName(int size, const char *name) +{ + if (size < 0) + { + Sys_Error(__FUNCTION__ ": bad size: %i", size); + } + + int totalsize = ((size + 15) & ~15) + sizeof(hunk_t); + + if (hunk_size - hunk_high_used - hunk_low_used < totalsize) + { + Sys_Error(__FUNCTION__ ": failed on %i bytes", totalsize); + } + + hunk_t *h = (hunk_t *)(hunk_base + hunk_low_used); + + hunk_low_used += totalsize; + Cache_FreeLow(hunk_low_used); + + Q_memset(h, 0, totalsize); + h->size = totalsize; + h->sentinel = HUNK_SENTINEL; + Q_strncpy(h->name, name, HUNK_NAME_LEN - 1); + h->name[HUNK_NAME_LEN - 1] = 0; + + return (void *)(h + 1); +} + +/* ../engine/zone.c:449 */ +void *Hunk_Alloc(int size) +{ + return Hunk_AllocName(size, "unknown"); +} + +/* ../engine/zone.c:454 */ +int Hunk_LowMark(void) +{ + return hunk_low_used; +} + +/* ../engine/zone.c:459 */ +void Hunk_FreeToLowMark(int mark) +{ + if (mark < 0 || mark > hunk_low_used) + { + Sys_Error(__FUNCTION__ ": bad mark %i", mark); + } + + hunk_low_used = mark; +} + +/* ../engine/zone.c:474 */ +int Hunk_HighMark(void) +{ + if (hunk_tempactive) + { + hunk_tempactive = FALSE; + Hunk_FreeToHighMark(hunk_tempmark); + } + + return hunk_high_used; +} + +/* ../engine/zone.c:485 */ +void Hunk_FreeToHighMark(int mark) +{ + if (hunk_tempactive) + { + hunk_tempactive = FALSE; + Hunk_FreeToHighMark(hunk_tempmark); + } + + if (mark < 0 || mark > hunk_high_used) + { + Sys_Error(__FUNCTION__ ": bad mark %i", mark); + } + + hunk_high_used = mark; +} + +/* +=================== +Hunk_HighAllocName +=================== +*/ + +/* ../engine/zone.c:512 */ +void *Hunk_HighAllocName(int size, const char *name) +{ + hunk_t *h; + if (size < 0) + { + Sys_Error(__FUNCTION__ ": bad size: %i", size); + } + + if (hunk_tempactive) + { + Hunk_FreeToHighMark(hunk_tempmark); + hunk_tempactive = FALSE; + } + + size = ((size + 15) & ~15) + sizeof(hunk_t); + + if (hunk_size - hunk_high_used - hunk_low_used < size) + { + Con_Printf(__FUNCTION__ ": failed on %i bytes\n", size); + return 0; + } + + hunk_high_used += size; + Cache_FreeHigh(hunk_high_used); + + h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); + Q_memset(h, 0, size); + + h->size = size; + h->sentinel = HUNK_SENTINEL; + Q_strncpy(h->name, name, HUNK_NAME_LEN - 1); + h->name[HUNK_NAME_LEN - 1] = 0; + + return (void*)(h + 1); +} + +/* +================= +Hunk_TempAlloc + +Return space from the top of the hunk +================= +*/ + +/* ../engine/zone.c:559 */ +void *Hunk_TempAlloc(int size) +{ + void *buf; + + if (hunk_tempactive) + { + Hunk_FreeToHighMark(hunk_tempmark); + hunk_tempactive = 0; + } + + hunk_tempmark = Hunk_HighMark(); + buf = Hunk_HighAllocName((size + 15) & ~15, "temp"); + hunk_tempactive = 1; + + return buf; +} + +#endif // Hunk_Functions_region + +#ifndef Cache_Functions_region + +/* +=============================================================================== + +CACHE MEMORY + +=============================================================================== +*/ + +#define CACHE_NAME_LEN 64 + +typedef struct cache_system_s +{ + int size; + cache_user_t *user; + char name[CACHE_NAME_LEN]; + cache_system_t *prev; + cache_system_t *next; + cache_system_t *lru_prev; + cache_system_t *lru_next; +} cache_system_t; + +cache_system_t cache_head; + +/* +=========== +Cache_Move +=========== +*/ + +/* ../engine/zone.c:607 */ +void Cache_Move(cache_system_t *c) +{ + cache_system_t *newmem = Cache_TryAlloc(c->size, 1); + + if (!newmem) + { + Cache_Free(c->user); + } + else + { + Q_memcpy(newmem + 1, c + 1, c->size - sizeof(cache_system_t)); + newmem->user = c->user; + Q_memcpy(newmem->name, c->name, sizeof(newmem->name)); + Cache_Free(c->user); + newmem->user->data = (void *)(newmem + 1); + } +} + +/* +============ +Cache_FreeLow + +Throw things out until the hunk can be expanded to the given point +============ +*/ + +/* ../engine/zone.c:638 */ +void Cache_FreeLow(int new_low_hunk) +{ + cache_system_t *c; + + while (true) + { + c = cache_head.next; + if (c == &cache_head) + return; // nothing in cache at all + if ((byte *)c >= hunk_base + new_low_hunk) + return; // there is space to grow the hunk + Cache_Move(c); // reclaim the space + } +} + +/* +============ +Cache_FreeHigh + +Throw things out until the hunk can be expanded to the given point +============ +*/ + +/* ../engine/zone.c:660 */ +void Cache_FreeHigh(int new_high_hunk) +{ + cache_system_t *c, *prev; + + prev = NULL; + while (true) + { + c = cache_head.prev; + if (c == &cache_head) + return; // nothing in cache at all + if ((byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk) + return; // there is space to grow the hunk + if (c == prev) + Cache_Free(c->user); // didn't move out of the way + else + { + Cache_Move(c); // try to move it + prev = c; + } + } +} + +/* ../engine/zone.c:682 */ +void Cache_UnlinkLRU(cache_system_t *cs) +{ + if (!cs->lru_next || !cs->lru_prev) + { + Sys_Error(__FUNCTION__ ": NULL link"); + } + + cs->lru_next->lru_prev = cs->lru_prev; + cs->lru_prev->lru_next = cs->lru_next; + cs->lru_next = cs->lru_prev = 0; +} + +/* ../engine/zone.c:693 */ +void Cache_MakeLRU(cache_system_t *cs) +{ + if (cs->lru_next || cs->lru_prev) + { + Sys_Error(__FUNCTION__ ": active link"); + } + + cache_head.lru_next->lru_prev = cs; + cs->lru_next = cache_head.lru_next; + cs->lru_prev = &cache_head; + cache_head.lru_next = cs; +} + +/* +============ +Cache_TryAlloc + +Looks for a free block of memory between the high and low hunk marks +Size should already include the header and padding +============ +*/ + +/* ../engine/zone.c:712 */ +cache_system_t *Cache_TryAlloc(int size, qboolean nobottom) +{ + cache_system_t *cs; + cache_system_t *newmem; + + if (!nobottom && cache_head.prev == &cache_head) + { + if (hunk_size - hunk_low_used - hunk_high_used < size) + { + Sys_Error(__FUNCTION__ ": %i is greater then free hunk", size); + } + + newmem = (cache_system_t *)(hunk_base + hunk_low_used); + Q_memset(newmem, 0, sizeof(cache_system_t)); + newmem->size = size; + cache_head.next = cache_head.prev = newmem; + newmem->next = newmem->prev = &cache_head; + + Cache_MakeLRU(newmem); + return newmem; + } + + cs = cache_head.next; + newmem = (cache_system_t *)(hunk_base + hunk_low_used); + + do + { + if ((!nobottom || cs != cache_head.next) && (signed int)((char *)cs - (char *)newmem) >= size) + { + Q_memset(newmem, 0, sizeof(cache_system_t)); + + newmem->size = size; + newmem->next = cs; + newmem->prev = cs->prev; + + cs->prev->next = newmem; + cs->prev = newmem; + + Cache_MakeLRU(newmem); + return newmem; + } + + newmem = (cache_system_t *)((char *)cs + cs->size); + cs = cs->next; + } while (cs != &cache_head); + + if ((int)(hunk_size + hunk_base - hunk_high_used - (byte *)newmem) < size) + { + return 0; + } + + Q_memset(newmem, 0, sizeof(cache_system_t)); + + newmem->size = size; + newmem->next = &cache_head; + newmem->prev = cache_head.prev; + + cache_head.prev->next = newmem; + cache_head.prev = newmem; + + Cache_MakeLRU(newmem); + return newmem; +} + +/* +============ +Cache_Flush + +Throw everything out, so new data will be demand cached +============ +*/ + +/* ../engine/zone.c:793 */ +void Cache_Force_Flush(void) +{ + cache_system_t *i; + + for (i = cache_head.next; cache_head.next != &cache_head; i = cache_head.next) + { + Cache_Free(i->user); + } +} + +/* ../engine/zone.c:806 */ +void Cache_Flush(void) +{ + if (g_pcl.maxclients <= 1 || allow_cheats) + { + Cache_Force_Flush(); + } + else + { + Con_Printf("Server must enable sv_cheats to activate the flush command in multiplayer games.\n"); + } +} + +/* +============ +CacheSystemCompare + +Compares the names of two cache_system_t structs. +Used with qsort() +============ +*/ + +/* ../engine/zone.c:827 */ +NOXREF int CacheSystemCompare(const void *ppcs1, const void *ppcs2) +{ + NOXREFCHECK; + + cache_system_t *pcs1 = (cache_system_t *)ppcs1; + cache_system_t *pcs2 = (cache_system_t *)ppcs2; + + return Q_stricmp(pcs1->name, pcs2->name); +} + +/* +============ +Cache_Print + +============ +*/ + +/* ../engine/zone.c:842 */ +NOXREF void Cache_Print(void) +{ + NOXREFCHECK; + + cache_system_t *cd; + + for (cd = cache_head.next; cd != &cache_head; cd = cd->next) + { + Con_Printf("%8i : %s\n", cd->size, cd->name); + } +} + +/* +============ +ComparePath1 + +compares the first directory of two paths... +(so "foo/bar" will match "foo/fred" +============ +*/ + +/* ../engine/zone.c:883 */ +NOXREF int ComparePath1(char *path1, char *path2) +{ + NOXREFCHECK; + while (*path1 != '/' && *path1 != '\\' && *path1) + { + if (*path1 != *path2) + return 0; + else + { + path1++; + path2++; + } + } + return 1; +} + +/* +============ +CommatizeNumber + +takes a number, and creates a string of that with commas in the +appropriate places. +============ +*/ + +/* ../engine/zone.c:906 */ +NOXREF char *CommatizeNumber(int num, char *pout) +{ + NOXREFCHECK; + //this is probably more complex than it needs to be. + int len = 0; + int i; + char outbuf[50]; + memset(outbuf, 0, 50); + while (num) + { + char tempbuf[50]; + int temp = num % 1000; + num = num / 1000; + strcpy(tempbuf, outbuf); + + Q_snprintf(outbuf, sizeof(outbuf), ",%03i%s", temp, tempbuf); + } + + len = Q_strlen(outbuf); + + for (i = 0; i < len; i++) //find first significant digit + if (outbuf[i] != '0' && outbuf[i] != ',') + break; + + if (i == len) + strcpy(pout, "0"); + else + strcpy(pout, &outbuf[i]); //copy from i to get rid of the first comma and leading zeros + + return pout; +} + +/* +============ +Cache_Report + +============ +*/ + +/* ../engine/zone.c:946 */ +NOXREF void Cache_Report(void) +{ + NOXREFCHECK; + Con_DPrintf("%4.1f megabyte data cache\n", (hunk_size - hunk_low_used - hunk_high_used) / (float)(1024 * 1024)); +} + +/* +============ +Cache_Compact + +============ +*/ + +/* ../engine/zone.c:957 */ +NOXREF void Cache_Compact(void) +{ + NOXREFCHECK; +} + +/* +============ +Cache_Init + +============ +*/ + +/* ../engine/zone.c:967 */ +void Cache_Init(void) +{ + cache_head.next = cache_head.prev = &cache_head; + cache_head.lru_next = cache_head.lru_prev = &cache_head; + + Cmd_AddCommand("flush", Cache_Flush); +} + +/* +============== +Cache_Free + +Frees the memory and removes it from the LRU list +============== +*/ + +/* ../engine/zone.c:982 */ +void Cache_Free(cache_user_t *c) +{ + if (!c->data) + { + Sys_Error(__FUNCTION__ ": not allocated"); + } + + cache_system_t *cs = ((cache_system_t *)c->data - 1); + + cs->prev->next = cs->next; + cs->next->prev = cs->prev; + c->data = cs->prev = cs->next = 0; + + Cache_UnlinkLRU(cs); +} + +/* ../engine/zone.c:1000 */ +NOXREF int Cache_TotalUsed(void) +{ + NOXREFCHECK; + + cache_system_t *cd; + int Total = 0; + for (cd = cache_head.next; cd != &cache_head; cd = cd->next) + Total += cd->size; + + return Total; +} + +/* +============== +Cache_Check +============== +*/ + +/* ../engine/zone.c:1018 */ +void *Cache_Check(cache_user_t *c) +{ + cache_system_t *cs; + + if (c->data) + { + cs = (cache_system_t *)((char *)c->data - sizeof(cache_system_t)); + + Cache_UnlinkLRU((cache_system_t *)c->data - 1); + Cache_MakeLRU(cs); + } + + return c->data; +} + +/* +============== +Cache_Alloc +============== +*/ + +/* ../engine/zone.c:1040 */ +void *Cache_Alloc(cache_user_t *c, int size, char *name) +{ + cache_system_t *cs; + + if (c->data) + { + Sys_Error(__FUNCTION__ ": already allocated"); + } + + if (size <= 0) + { + Sys_Error(__FUNCTION__ ": size %i", size); + } + + while (true) + { + cs = Cache_TryAlloc((size + sizeof(cache_system_t) + 15) & ~15, 0); + + if (cs) + { + Q_strncpy(cs->name, name, CACHE_NAME_LEN - 1); + cs->name[CACHE_NAME_LEN - 1] = 0; + c->data = cs + 1; + cs->user = c; + + break; + } + + if (cache_head.lru_prev == &cache_head) + { + Sys_Error(__FUNCTION__ ": out of memory"); + } + + Cache_Free(cache_head.lru_prev->user); + } + + return Cache_Check(c); +} + +/* +======================== +Memory_Init +======================== +*/ + +/* ../engine/zone.c:1262 */ +void Memory_Init(void *buf, int size) +{ + int zonesize = ZONE_DYNAMIC_SIZE; + + hunk_base = (byte *)buf; + hunk_size = size; + hunk_low_used = 0; + hunk_high_used = 0; + + Cache_Init(); + + int p = COM_CheckParm("-zone"); + + if (p) + { + if (p < com_argc - 1) + { + zonesize = Q_atoi(com_argv[p + 1]) * 1024; + } + else + { + Sys_Error(__FUNCTION__ ": you must specify a size in KB after -zone"); + } + } + + mainzone = ((memzone_t *)Hunk_AllocName(zonesize, "zone")); + Z_ClearZone(mainzone, zonesize); +} + +/* ../engine/zone.c:1299 */ +NOXREF void Cache_Print_Models_And_Totals(void) +{ + char buf[50]; + cache_system_t *cd; + cache_system_t *sortarray[512]; + int32 i = 0; + int32 j = 0; + int32 totalbytes = 0; + FileHandle_t file; + + file = FS_Open(mem_dbgfile.string, "a"); + if (!file) + return; + + Q_memset(sortarray, 0, sizeof(cache_system_t *) * 512); + + //pack names into the array. + for (cd = cache_head.next; cd != &cache_head; cd = cd->next) + { + if (strstr(cd->name,".mdl")) + sortarray[i++] = cd; + } + + qsort(sortarray, i, sizeof(cache_system_t *), CacheSystemCompare); + FS_FPrintf(file, "\nCACHED MODELS:\n"); + + //now process the sorted list. + for (j = 0; j < i; j++) + { + FS_FPrintf(file, "\t%16.16s : %s\n", CommatizeNumber(sortarray[j]->size, buf), sortarray[j]->name); + totalbytes += sortarray[j]->size; + } + + FS_FPrintf(file,"Total bytes in cache used by models: %s\n", CommatizeNumber(totalbytes, buf)); + FS_Close(file); +} + +#define MAX_SFX 1024 + +/* ../engine/zone.c:1367 */ +NOXREF void Cache_Print_Sounds_And_Totals(void) +{ + char buf[50]; + cache_system_t *cd; + cache_system_t *sortarray[1024]; + int32 i = 0; + int32 j = 0; + int32 totalsndbytes = 0; + FileHandle_t file; + int subtot = 0; + + file = FS_Open(mem_dbgfile.string, "a"); + if (!file) + return; + + Q_memset(sortarray, 0, sizeof(cache_system_t *) * MAX_SFX); + + //pack names into the array. + for (cd = cache_head.next; cd != &cache_head; cd = cd->next) + { + if (strstr(cd->name,".wav")) + sortarray[i++] = cd; + } + + qsort(sortarray, i, sizeof(cache_system_t *), CacheSystemCompare); + FS_FPrintf(file, "\nCACHED SOUNDS:\n"); + + //now process the sorted list. (totals by directory) + for (j = 0; j < i; j++) + { + FS_FPrintf(file, "\t%16.16s : %s\n", CommatizeNumber(sortarray[j]->size, buf), sortarray[j]->name); + totalsndbytes += sortarray[j]->size; + + if ((j + 1) == i || ComparePath1(sortarray[j]->name, sortarray[j + 1]->name) == 0) + { + char pathbuf[512]; + Sys_SplitPath(sortarray[j]->name, NULL, pathbuf, NULL, NULL); + FS_FPrintf(file, "\tTotal Bytes used in \"%s\": %s\n", pathbuf, CommatizeNumber(totalsndbytes - subtot, buf)); + subtot = totalsndbytes; + } + } + FS_FPrintf(file, "Total bytes in cache used by sound: %s\n", CommatizeNumber(totalsndbytes, buf)); + FS_Close(file); +} + +#endif // Cache_Functions_region diff --git a/rehlds/engine/zone.h b/rehlds/engine/zone.h new file mode 100644 index 0000000..1c8695b --- /dev/null +++ b/rehlds/engine/zone.h @@ -0,0 +1,110 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef ZONE_H +#define ZONE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" + +#define ZONE_DYNAMIC_SIZE 0x20000 + +typedef struct memblock_s memblock_t; +typedef struct memzone_s memzone_t; +typedef struct hunk_s hunk_t; +typedef struct cache_user_s cache_user_t; +typedef struct cache_system_s cache_system_t; + +#ifdef HOOK_ENGINE + +#define mem_dbgfile (*pmem_dbgfile) +#define mainzone (*pmainzone) +#define hunk_base (*phunk_base) +#define hunk_size (*phunk_size) +#define hunk_low_used (*phunk_low_used) +#define hunk_high_used (*phunk_high_used) +#define hunk_tempactive (*phunk_tempactive) +#define hunk_tempmark (*phunk_tempmark) +#define cache_head (*pcache_head) + +#endif // HOOK_ENGINE + +extern cvar_t mem_dbgfile; +extern memzone_t *mainzone; +extern byte *hunk_base; +extern int hunk_size; +extern int hunk_low_used; +extern int hunk_high_used; +extern qboolean hunk_tempactive; +extern int hunk_tempmark; +extern cache_system_t cache_head; + +void Z_ClearZone(memzone_t *zone, int size); +void Z_Free(void *ptr); +void *Z_Malloc(int size); +void *Z_TagMalloc(int size, int tag); +NOXREF void Z_Print(memzone_t *zone); +void Z_CheckHeap(void); + +void Hunk_Check(void); +NOXREF void Hunk_Print(qboolean all); +void *Hunk_AllocName(int size, const char *name); +void *Hunk_Alloc(int size); +int Hunk_LowMark(void); +void Hunk_FreeToLowMark(int mark); +int Hunk_HighMark(void); +void Hunk_FreeToHighMark(int mark); +void *Hunk_HighAllocName(int size, const char *name); +void *Hunk_TempAlloc(int size); + +void Cache_Move(cache_system_t *c); +void Cache_FreeLow(int new_low_hunk); +void Cache_FreeHigh(int new_high_hunk); +void Cache_UnlinkLRU(cache_system_t *cs); +void Cache_MakeLRU(cache_system_t *cs); +cache_system_t *Cache_TryAlloc(int size, qboolean nobottom); +void Cache_Force_Flush(void); +void Cache_Flush(void); +NOXREF int CacheSystemCompare(const void *ppcs1, const void *ppcs2); +NOXREF void Cache_Print(void); +NOXREF int ComparePath1(char *path1, char *path2); +NOXREF char *CommatizeNumber(int num, char *pout); +NOXREF void Cache_Report(void); +NOXREF void Cache_Compact(void); +void Cache_Init(void); +void Cache_Free(cache_user_t *c); +NOXREF int Cache_TotalUsed(void); +void *Cache_Check(cache_user_t *c); +void *Cache_Alloc(cache_user_t *c, int size, char *name); +void Memory_Init(void *buf, int size); +NOXREF NOBODY void Cache_Print_Models_And_Totals(void); +NOXREF NOBODY void Cache_Print_Sounds_And_Totals(void); + +#endif // ZONE_H diff --git a/rehlds/hookers/6132_hooker.cpp b/rehlds/hookers/6132_hooker.cpp new file mode 100644 index 0000000..d0b2205 --- /dev/null +++ b/rehlds/hookers/6132_hooker.cpp @@ -0,0 +1,2549 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +template +size_t mfunc_ptr_cast(MFUNC f) { + auto x = f; + size_t addr = (size_t &)x; + return addr; +} + +// Offset where engine assumed be loaded to ajust hooks offsets. NULL for the Linux to trigger symbols searching. +#ifdef _WIN32 +extern const size_t g_BaseOffset = 0x01D00000; +#else +extern const size_t g_BaseOffset = NULL; +#endif + + +//#define Common_MSG_region +//#define Common_SZ_region +//#define Common_COM_region +//#define Delta_region +//#define Main_region +//#define Zone_region +//#define FileSystem_Internal_region +//#define FileSystem_region +//#define Unicode_StrTools_region +//#define Cmd_region +//#define Cvar_region +//#define Info_region +//#define SysDll_region +//#define Sys_Dll2_region +//#define CModel_region +//#define Model_region +//#define Sv_Log_region +//#define Cl_Null_region +//#define Snd_Null_region +//#define Sv_Steam3_region +//#define Host_region +//#define Host_Cmd_region +//#define Pmove_region +//#define Pmovetst_region +//#define Pr_Edict_region +//#define Pr_Cmds_region +//#define Mathlib_region +//#define World_region +//#define Sv_Phys_region +//#define Sv_Move_region +//#define Sv_pmove_region +//#define R_Studio_region +//#define Net_ws_region +//#define Net_chan_region +//#define Hashpak_region +//#define Sv_user_region +//#define Wad_region +//#define Textures_region +//#define Tmessage_region +//#define Vid_null_region +//#define L_studio_region +//#define Crc_region +//#define Sv_RemoteAccess_region +//#define Com_custom +//#define Sv_upld +//#define Decals +//#define IpratelimitWrapper_region +//#define Sys_engine +//#define Sys_linuxwind + +//#define Function_References_region +//#define Data_References_region + + +void* malloc_wrapper(size_t size) { + void* res = malloc(size); + //Rehlds_Debug_logAlloc(size, res); + return res; +} + +void* realloc_wrapper(void* orig, size_t newSize) { + void* res = realloc(orig, newSize); + //Rehlds_Debug_logRealloc(newSize, orig, res); + return res; +} + +void free_wrapper(void* mem) { + //Rehlds_Debug_logFree(mem); + free(mem); +} + +void* calloc_wrapper(size_t count, size_t size) { + void* res = calloc(count, size); + //Rehlds_Debug_logAlloc(size * count, res); + return res; +} + +void* __nh_malloc_wrapper(size_t sz, int unk) { + void* res = malloc(sz); + //Rehlds_Debug_logAlloc(sz, res); + return res; +} + + +FunctionHook g_FunctionHooks[] = +{ + // DO NOT DISABLE, other functions depends on memory allocation routines +#ifndef Mem_region + + { 0x01D50AB0, "Mem_Malloc", (size_t)&Mem_Malloc }, + { 0x01D50AD0, "Mem_ZeroMalloc", (size_t)&Mem_ZeroMalloc }, + { 0x01D50B00, "Mem_Realloc", (size_t)&Mem_Realloc }, + { 0x01D50B20, "Mem_Calloc", (size_t)&Mem_Calloc }, + { 0x01D50B40, "Mem_Strdup", (size_t)&Mem_Strdup }, + { 0x01D50B60, "Mem_Free", (size_t)&Mem_Free }, + +#ifdef _WIN32 + { 0x01DFE945, "_malloca", (size_t)&malloc_wrapper }, + { 0x01DFEA7F, "realloc", (size_t)&realloc_wrapper }, + { 0x01DFE35D, "_frea", (size_t)&free_wrapper }, + { 0x01DFF016, "calloc", (size_t)&calloc_wrapper }, + { 0x01DFE957, "__nh_malloc", (size_t)&__nh_malloc_wrapper }, + +#endif //_WIN32 + +#endif // Mem_region + +#ifndef Common_MSG_region + +#ifdef Q_functions + + //{ 0x, "Q_memset", (size_t)&Q_memset }, + //{ 0x, "Q_memcpy", (size_t)&Q_memcpy }, + //{ 0x, "Q_memcmp", (size_t)&Q_memcmp }, + { 0x01D28AF0, "Q_strcpy", (size_t)&Q_strcpy }, + //{ 0x, "Q_strncpy", (size_t)&Q_strncpy }, + { 0x01D28B50, "Q_strlen", (size_t)&Q_strlen }, + //{ 0x, "Q_strrchr", (size_t)&Q_strrchr }, + //{ 0x, "Q_strcat", (size_t)&Q_strcat }, + //{ 0x, "Q_strcmp", (size_t)&Q_strcmp }, + //{ 0x, "Q_strncmp", (size_t)&Q_strncmp }, + //{ 0x, "Q_strncasecmp", (size_t)&Q_strncasecmp }, + //{ 0x, "Q_strcasecmp", (size_t)&Q_strcasecmp }, + //{ 0x, "Q_stricmp", (size_t)&Q_stricmp }, + //{ 0x, "Q_strnicmp", (size_t)&Q_strnicmp }, + //{ 0x, "Q_atoi", (size_t)&Q_atoi }, + //{ 0x, "Q_atof", (size_t)&Q_atof }, + //{ 0x, "Q_strlwr", (size_t)&Q_strlwr }, + //{ 0x, "Q_FileNameCmp", (size_t)&Q_FileNameCmp }, + //{ 0x, "Q_strstr", (size_t)&Q_strstr }, + //{ 0x, "Q_strtoull", (size_t)&Q_strtoull }, + +#endif // Q_functions + + { 0x01D29290, "MSG_WriteChar", (size_t)&MSG_WriteChar }, + { 0x01D292B0, "MSG_WriteByte", (size_t)&MSG_WriteByte }, + { 0x01D292D0, "MSG_WriteShort", (size_t)&MSG_WriteShort }, + { 0x01D292F0, "MSG_WriteWord", (size_t)&MSG_WriteWord }, + { 0x01D29310, "MSG_WriteLong", (size_t)&MSG_WriteLong }, + { 0x01D29340, "MSG_WriteFloat", (size_t)&MSG_WriteFloat }, + { 0x01D29370, "MSG_WriteString", (size_t)&MSG_WriteString }, + { 0x01D293B0, "MSG_WriteBuf", (size_t)&MSG_WriteBuf }, + { 0x01D293D0, "MSG_WriteAngle", (size_t)&MSG_WriteAngle }, + { 0x01D29420, "MSG_WriteHiresAngle", (size_t)&MSG_WriteHiresAngle }, + { 0x01D29470, "MSG_WriteUsercmd", (size_t)&MSG_WriteUsercmd }, + { 0x01D294D0, "MSG_WriteOneBit", (size_t)&MSG_WriteOneBit }, + { 0x01D29550, "MSG_StartBitWriting", (size_t)&MSG_StartBitWriting }, + { 0x01D29580, "MSG_IsBitWriting", (size_t)&MSG_IsBitWriting }, // NOXREF + { 0x01D29590, "MSG_EndBitWriting", (size_t)&MSG_EndBitWriting }, + { 0x01D295E0, "MSG_WriteBits", (size_t)&MSG_WriteBits }, + { 0x01D29700, "MSG_WriteSBits", (size_t)&MSG_WriteSBits }, + { 0x01D29750, "MSG_WriteBitString", (size_t)&MSG_WriteBitString }, + { 0x01D29790, "MSG_WriteBitData", (size_t)&MSG_WriteBitData }, + { 0x01D297C0, "MSG_WriteBitAngle", (size_t)&MSG_WriteBitAngle }, + { 0x01D29850, "MSG_ReadBitAngle", (size_t)&MSG_ReadBitAngle }, + { 0x01D298A0, "MSG_CurrentBit", (size_t)&MSG_CurrentBit }, + { 0x01D298D0, "MSG_IsBitReading", (size_t)&MSG_IsBitReading }, // NOXREF + { 0x01D298E0, "MSG_StartBitReading", (size_t)&MSG_StartBitReading }, + { 0x01D29930, "MSG_EndBitReading", (size_t)&MSG_EndBitReading }, + { 0x01D29970, "MSG_ReadOneBit", (size_t)&MSG_ReadOneBit }, + { 0x01D29A00, "MSG_ReadBits", (size_t)&MSG_ReadBits }, + { 0x01D29B00, "MSG_PeekBits", (size_t)&MSG_PeekBits }, // NOXREF + { 0x01D29B40, "MSG_ReadSBits", (size_t)&MSG_ReadSBits }, + { 0x01D29B70, "MSG_ReadBitString", (size_t)&MSG_ReadBitString }, // NOXREF + { 0x01D29BB0, "MSG_ReadBitData", (size_t)&MSG_ReadBitData }, + { 0x01D29BE0, "MSG_ReadBitCoord", (size_t)&MSG_ReadBitCoord }, // NOXREF + { 0x01D29C70, "MSG_WriteBitCoord", (size_t)&MSG_WriteBitCoord }, + { 0x01D29D00, "MSG_ReadBitVec3Coord", (size_t)&MSG_ReadBitVec3Coord }, // NOXREF + { 0x01D29D50, "MSG_WriteBitVec3Coord", (size_t)&MSG_WriteBitVec3Coord }, + { 0x01D29E30, "MSG_ReadCoord", (size_t)&MSG_ReadCoord }, // NOXREF + { 0x01D29E60, "MSG_WriteCoord", (size_t)&MSG_WriteCoord }, + { 0x01D29E80, "MSG_ReadVec3Coord", (size_t)&MSG_ReadVec3Coord }, // NOXREF + { 0x01D29EC0, "MSG_WriteVec3Coord", (size_t)&MSG_WriteVec3Coord }, // NOXREF + { 0x01D29F00, "MSG_BeginReading", (size_t)&MSG_BeginReading }, + { 0x01D29F10, "MSG_ReadChar", (size_t)&MSG_ReadChar }, + { 0x01D29F50, "MSG_ReadByte", (size_t)&MSG_ReadByte }, + { 0x01D29F90, "MSG_ReadShort", (size_t)&MSG_ReadShort }, + { 0x01D29FE0, "MSG_ReadWord", (size_t)&MSG_ReadWord }, // NOXREF + { 0x01D2A030, "MSG_ReadLong", (size_t)&MSG_ReadLong }, + { 0x01D2A090, "MSG_ReadFloat", (size_t)&MSG_ReadFloat }, + { 0x01D2A0E0, "MSG_ReadBuf", (size_t)&MSG_ReadBuf }, + { 0x01D2A130, "MSG_ReadString", (size_t)&MSG_ReadString }, + { 0x01D2A170, "MSG_ReadStringLine", (size_t)&MSG_ReadStringLine }, + { 0x01D2A1B0, "MSG_ReadAngle", (size_t)&MSG_ReadAngle }, // NOXREF + { 0x01D2A1E0, "MSG_ReadHiresAngle", (size_t)&MSG_ReadHiresAngle }, // NOXREF + { 0x01D2A210, "MSG_ReadUsercmd", (size_t)&MSG_ReadUsercmd }, + +#endif // Common_MSG_region + +#ifndef Common_SZ_region + + { 0x01D2A260, "SZ_Alloc", (size_t)&SZ_Alloc }, + { 0x01D2A2A0, "SZ_Clear", (size_t)&SZ_Clear }, + { 0x01D2A2C0, "SZ_GetSpace", (size_t)&SZ_GetSpace }, + { 0x01D2A380, "SZ_Write", (size_t)&SZ_Write }, + { 0x01D2A3B0, "SZ_Print", (size_t)&SZ_Print }, + +#endif // Common_SZ_region + +#ifndef Common_COM_region + + { 0x01D08E50, "build_number", (size_t)&build_number }, + { 0x01D289E0, "Info_Serverinfo", (size_t)&Info_Serverinfo }, + { 0x01D28FF0, "COM_Nibble", (size_t)&COM_Nibble }, + { 0x01D29030, "COM_HexConvert", (size_t)&COM_HexConvert }, + //{ 0x01D29080, "COM_BinPrintf", (size_t)&COM_BinPrintf }, // NOXREF + { 0x01D29100, "COM_ExplainDisconnection", (size_t)&COM_ExplainDisconnection }, + { 0x01D29170, "COM_ExtendedExplainDisconnection", (size_t)&COM_ExtendedExplainDisconnection }, // NOXREF + { 0x01D2A410, "COM_SkipPath", (size_t)&COM_SkipPath }, // NOXREF + { 0x01D2A440, "COM_StripExtension", (size_t)&COM_StripExtension }, + { 0x01D2A4A0, "COM_FileExtension", (size_t)&COM_FileExtension }, + { 0x01D2A4F0, "COM_FileBase", (size_t)&COM_FileBase }, + { 0x01D2A580, "COM_DefaultExtension", (size_t)&COM_DefaultExtension }, + { 0x01D2A5D0, "COM_UngetToken", (size_t)&COM_UngetToken }, + { 0x01D2A5E0, "COM_Parse", (size_t)&COM_Parse }, + { 0x01D2A730, "COM_ParseLine", (size_t)&COM_ParseLine }, + { 0x01D2A7A0, "COM_TokenWaiting", (size_t)&COM_TokenWaiting }, // NOXREF + { 0x01D2A830, "COM_CheckParm", (size_t)&COM_CheckParm }, + { 0x01D2A880, "COM_InitArgv", (size_t)&COM_InitArgv }, + { 0x01D2A960, "COM_Init", (size_t)&COM_Init }, + { 0x01D2AA00, "va", (size_t)&va }, + { 0x01D2AA40, "vstr", (size_t)&vstr }, // NOXREF + { 0x01D2AAA0, "memsearch", (size_t)&memsearch }, // NOXREF + { 0x01D2AAD0, "COM_WriteFile", (size_t)&COM_WriteFile }, // NOXREF + { 0x01D2AB70, "COM_FixSlashes", (size_t)&COM_FixSlashes }, + { 0x01D2AB90, "COM_CreatePath", (size_t)&COM_CreatePath }, + { 0x01D2ABD0, "COM_CopyFile", (size_t)&COM_CopyFile }, // NOXREF + { 0x01D2AC70, "COM_ExpandFilename", (size_t)&COM_ExpandFilename }, // NOXREF + { 0x01D2ACD0, "COM_FileSize", (size_t)&COM_FileSize }, + { 0x01D2AD10, "COM_LoadFile", (size_t)&COM_LoadFile }, + { 0x01D2AE70, "COM_FreeFile", (size_t)&COM_FreeFile }, + { 0x01D2AEA0, "COM_CopyFileChunk", (size_t)&COM_CopyFileChunk }, + //{ 0x01D2AF40, "COM_LoadFileLimit", (size_t)&COM_LoadFileLimit }, // NOXREF + { 0x01D2B020, "COM_LoadHunkFile", (size_t)&COM_LoadHunkFile }, + { 0x01D2B040, "COM_LoadTempFile", (size_t)&COM_LoadTempFile }, + { 0x01D2B060, "COM_LoadCacheFile", (size_t)&COM_LoadCacheFile }, + { 0x01D2B080, "COM_LoadStackFile", (size_t)&COM_LoadStackFile }, // NOXREF + { 0x01D2B0B0, "COM_Shutdown", (size_t)&COM_Shutdown }, + { 0x01D2B0C0, "COM_AddAppDirectory", (size_t)&COM_AddAppDirectory }, // NOXREF + { 0x01D2B0E0, "COM_AddDefaultDir", (size_t)&COM_AddDefaultDir }, + { 0x01D2B100, "COM_StripTrailingSlash", (size_t)&COM_StripTrailingSlash }, + { 0x01D2B130, "COM_ParseDirectoryFromCmd", (size_t)&COM_ParseDirectoryFromCmd }, + { 0x01D2B1C0, "COM_SetupDirectories", (size_t)&COM_SetupDirectories }, + //{ 0x01D2B3D0, "COM_CheckPrintMap", (size_t)&COM_CheckPrintMap }, // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out + { 0x01D2B250, "COM_ListMaps", (size_t)&COM_ListMaps }, + { 0x01D2B410, "COM_Log", (size_t)&COM_Log }, + { 0x01D2B480, "COM_LoadFileForMe", (size_t)&COM_LoadFileForMe }, + { 0x01D2B4A0, "COM_CompareFileTime", (size_t)&COM_CompareFileTime }, + { 0x01D2B500, "COM_GetGameDir", (size_t)&COM_GetGameDir }, + { 0x01D2B530, "COM_EntsForPlayerSlots", (size_t)&COM_EntsForPlayerSlots }, + { 0x01D2B590, "COM_NormalizeAngles", (size_t)&COM_NormalizeAngles }, + { 0x01D2B610, "COM_Munge", (size_t)&COM_Munge }, + { 0x01D2B6A0, "COM_UnMunge", (size_t)&COM_UnMunge }, + { 0x01D2B730, "COM_Munge2", (size_t)&COM_Munge2 }, + { 0x01D2B7C0, "COM_UnMunge2", (size_t)&COM_UnMunge2 }, + { 0x01D2B850, "COM_Munge3", (size_t)&COM_Munge3 }, + { 0x01D2B8E0, "COM_UnMunge3", (size_t)&COM_UnMunge3 }, // NOXREF + { 0x01D2B970, "COM_GetApproxWavePlayLength", (size_t)&COM_GetApproxWavePlayLength }, + +#endif // Common_COM_region + +#ifndef Delta_region + + { 0x01D351D0, "DELTA_FindField", (size_t)&DELTA_FindField }, + { 0x01D35240, "DELTA_FindFieldIndex", (size_t)&DELTA_FindFieldIndex }, + { 0x01D352A0, "DELTA_SetField", (size_t)&DELTA_SetField }, + { 0x01D352C0, "DELTA_UnsetField", (size_t)&DELTA_UnsetField }, + { 0x01D352E0, "DELTA_SetFieldByIndex", (size_t)&DELTA_SetFieldByIndex }, + { 0x01D35300, "DELTA_UnsetFieldByIndex", (size_t)&DELTA_UnsetFieldByIndex }, + { 0x01D35320, "DELTA_ClearFlags", (size_t)&DELTA_ClearFlags }, + { 0x01D35340, "DELTA_TestDelta", (size_t)&DELTA_TestDelta }, + { 0x01D355B0, "DELTA_CountSendFields", (size_t)&DELTA_CountSendFields }, + { 0x01D355E0, "DELTA_MarkSendFields", (size_t)&DELTA_MarkSendFields }, + { 0x01D35830, "DELTA_SetSendFlagBits", (size_t)&DELTA_SetSendFlagBits }, + { 0x01D358B0, "DELTA_WriteMarkedFields", (size_t)&DELTA_WriteMarkedFields }, + { 0x01D35C10, "DELTA_CheckDelta", (size_t)&DELTA_CheckDelta }, + { 0x01D35C40, "DELTA_WriteDelta", (size_t)&DELTA_WriteDelta }, + { 0x01D35C80, "_DELTA_WriteDelta", (size_t)&_DELTA_WriteDelta }, + { 0x01D35D00, "DELTA_ParseDelta", (size_t)&DELTA_ParseDelta }, + + { 0x01D36420, "DELTA_AddEncoder", (size_t)&DELTA_AddEncoder }, + { 0x01D36460, "DELTA_ClearEncoders", (size_t)&DELTA_ClearEncoders }, + { 0x01D364A0, "DELTA_LookupEncoder", (size_t)&DELTA_LookupEncoder }, + { 0x01D364E0, "DELTA_CountLinks", (size_t)&DELTA_CountLinks }, + { 0x01D36500, "DELTA_ReverseLinks", (size_t)&DELTA_ReverseLinks }, + { 0x01D36520, "DELTA_ClearLinks", (size_t)&DELTA_ClearLinks }, + { 0x01D36550, "DELTA_BuildFromLinks", (size_t)&DELTA_BuildFromLinks }, + { 0x01D365F0, "DELTA_FindOffset", (size_t)&DELTA_FindOffset }, + { 0x01D36640, "DELTA_ParseType", (size_t)&DELTA_ParseType }, + { 0x01D36800, "DELTA_ParseField", (size_t)&DELTA_ParseField }, + { 0x01D36A10, "DELTA_FreeDescription", (size_t)&DELTA_FreeDescription }, + { 0x01D36A50, "DELTA_AddDefinition", (size_t)&DELTA_AddDefinition }, + { 0x01D36AB0, "DELTA_ClearDefinitions", (size_t)&DELTA_ClearDefinitions }, + { 0x01D36AF0, "DELTA_FindDefinition", (size_t)&DELTA_FindDefinition }, + { 0x01D36B40, "DELTA_SkipDescription", (size_t)&DELTA_SkipDescription }, + { 0x01D36BA0, "DELTA_ParseOneField", (size_t)&DELTA_ParseOneField }, + { 0x01D36C50, "DELTA_ParseDescription", (size_t)&DELTA_ParseDescription }, + { 0x01D36EA0, "DELTA_Load", (size_t)&DELTA_Load }, + { 0x01D36EF0, "DELTA_RegisterDescription", (size_t)&DELTA_RegisterDescription }, + { 0x01D36F30, "DELTA_ClearRegistrations", (size_t)&DELTA_ClearRegistrations }, + { 0x01D36FC0, "DELTA_ClearStats", (size_t)&DELTA_ClearStats }, + { 0x01D36FF0, "DELTA_ClearStats_f", (size_t)&DELTA_ClearStats_f }, + { 0x01D36F80, "DELTA_LookupRegistration", (size_t)&DELTA_LookupRegistration }, + { 0x01D37020, "DELTA_PrintStats", (size_t)&DELTA_PrintStats }, + { 0x01D37090, "DELTA_DumpStats_f", (size_t)&DELTA_DumpStats_f }, + { 0x01D370C0, "DELTA_Init", (size_t)&DELTA_Init }, + { 0x01D37160, "DELTA_Shutdown", (size_t)&DELTA_Shutdown }, + +#endif // Delta_region + +#ifndef Sv_Main_region + + { 0x01D87E40, "SV_LookupDelta", (size_t)&SV_LookupDelta }, + { 0x01D87E90, "SV_DownloadingModules", (size_t)&SV_DownloadingModules }, // NOXREF + { 0x01D87F70, "SV_GatherStatistics", (size_t)&SV_GatherStatistics }, + { 0x01D88190, "SV_DeallocateDynamicData", (size_t)&SV_DeallocateDynamicData }, + { 0x01D881D0, "SV_ReallocateDynamicData", (size_t)&SV_ReallocateDynamicData }, + { 0x01D88250, "SV_AllocClientFrames", (size_t)&SV_AllocClientFrames }, + { 0x01D882B0, "SV_IsPlayerIndex", (size_t)&SV_IsPlayerIndex_wrapped }, + { 0x01D882D0, "SV_ClearPacketEntities", (size_t)&SV_ClearPacketEntities }, + { 0x01D88310, "SV_AllocPacketEntities", (size_t)&SV_AllocPacketEntities }, + { 0x01D88370, "SV_ClearFrames", (size_t)&SV_ClearFrames }, + { 0x01D883E0, "SV_Serverinfo_f", (size_t)&SV_Serverinfo_f }, + { 0x01D884C0, "SV_Localinfo_f", (size_t)&SV_Localinfo_f }, + { 0x01D88550, "SV_User_f", (size_t)&SV_User_f }, + { 0x01D88640, "SV_Users_f", (size_t)&SV_Users_f }, + { 0x01D88700, "SV_CountPlayers", (size_t)&SV_CountPlayers }, + { 0x01D88740, "SV_CountProxies", (size_t)&SV_CountProxies }, + { 0x01D88790, "SV_FindModelNumbers", (size_t)&SV_FindModelNumbers }, + { 0x01D887D0, "SV_StartParticle", (size_t)&SV_StartParticle }, + { 0x01D88880, "SV_StartSound", (size_t)&SV_StartSound }, + { 0x01D88960, "SV_BuildSoundMsg", (size_t)&SV_BuildSoundMsg }, + { 0x01D88BD0, "SV_HashString", (size_t)&SV_HashString }, + { 0x01D88C10, "SV_LookupSoundIndex", (size_t)&SV_LookupSoundIndex }, + { 0x01D88CD0, "SV_BuildHashedSoundLookupTable", (size_t)&SV_BuildHashedSoundLookupTable }, + { 0x01D88D20, "SV_AddSampleToHashedLookupTable", (size_t)&SV_AddSampleToHashedLookupTable }, + { 0x01D88DA0, "SV_ValidClientMulticast", (size_t)&SV_ValidClientMulticast }, + { 0x01D88E40, "SV_Multicast", (size_t)&SV_Multicast }, + { 0x01D88FA0, "SV_WriteMovevarsToClient", (size_t)&SV_WriteMovevarsToClient }, + { 0x01D89110, "SV_WriteDeltaDescriptionsToClient", (size_t)&SV_WriteDeltaDescriptionsToClient }, + { 0x01D891B0, "SV_SetMoveVars", (size_t)&SV_SetMoveVars }, + { 0x01D892F0, "SV_QueryMovevarsChanged", (size_t)&SV_QueryMovevarsChanged }, + { 0x01D89590, "SV_SendServerinfo", (size_t)&SV_SendServerinfo }, + { 0x01D897C0, "SV_SendResources", (size_t)&SV_SendResources }, + { 0x01D89920, "SV_WriteClientdataToMessage", (size_t)&SV_WriteClientdataToMessage }, + { 0x01D89BF0, "SV_WriteSpawn", (size_t)&SV_WriteSpawn }, + { 0x01D89F10, "SV_SendUserReg", (size_t)&SV_SendUserReg }, + { 0x01D89F80, "SV_New_f", (size_t)&SV_New_f }, + { 0x01D8A210, "SV_SendRes_f", (size_t)&SV_SendRes_f }, + { 0x01D8A2C0, "SV_Spawn_f", (size_t)&SV_Spawn_f }, + { 0x01D8A3F0, "SV_CheckUpdateRate", (size_t)&SV_CheckUpdateRate }, + { 0x01D8A510, "SV_RejectConnection", (size_t)&SV_RejectConnection }, + { 0x01D8A5A0, "SV_RejectConnectionForPassword", (size_t)&SV_RejectConnectionForPassword }, + { 0x01D8A610, "SV_GetFragmentSize", (size_t)&SV_GetFragmentSize }, + { 0x01D8A680, "SV_FilterUser", (size_t)&SV_FilterUser }, + { 0x01D8A760, "SV_CheckProtocol", (size_t)&SV_CheckProtocol }, + { 0x01D8A7E0, "SV_CheckChallenge", (size_t)&SV_CheckChallenge }, + { 0x01D8A8D0, "SV_CheckIPRestrictions", (size_t)&SV_CheckIPRestrictions }, + { 0x01D8A980, "SV_CheckIPConnectionReuse", (size_t)&SV_CheckIPConnectionReuse }, + { 0x01D8AA40, "SV_FinishCertificateCheck", (size_t)&SV_FinishCertificateCheck }, + { 0x01D8AB10, "SV_CheckKeyInfo", (size_t)&SV_CheckKeyInfo }, + { 0x01D8AC30, "SV_CheckForDuplicateSteamID", (size_t)&SV_CheckForDuplicateSteamID }, + { 0x01D8ACE0, "SV_CheckForDuplicateNames", (size_t)&SV_CheckForDuplicateNames }, + { 0x01D8AE10, "SV_CheckUserInfo", (size_t)&SV_CheckUserInfo }, + { 0x01D8B080, "SV_FindEmptySlot", (size_t)&SV_FindEmptySlot }, + { 0x01D8B100, "SV_ConnectClient", (size_t)&SV_ConnectClient }, + { 0x01D8B8E0, "SVC_Ping", (size_t)&SVC_Ping }, + { 0x01D8B930, "SVC_GetChallenge", (size_t)&SVC_GetChallenge }, + { 0x01D8BB20, "SVC_ServiceChallenge", (size_t)&SVC_ServiceChallenge }, + { 0x01D8BCB0, "SV_ResetModInfo", (size_t)&SV_ResetModInfo }, + //{ 0x01D8BE40, "SV_GetFakeClientCount", (size_t)&SV_GetFakeClientCount },//NOXREF + //{ 0x01D8BE70, "SV_GetModInfo", (size_t)&SV_GetModInfo }, //NOXREF + //{ 0x01D8BF40, "RequireValidChallenge", (size_t)&RequireValidChallenge }, //NOXREF + //{ 0x01D8BF60, "ValidInfoChallenge", (size_t)&ValidInfoChallenge }, //NOXREF + //{ 0x01D8BFB0, "GetChallengeNr", (size_t)&GetChallengeNr }, //NOXREF + //{ 0x01D8C0C0, "CheckChallengeNr", (size_t)&CheckChallengeNr }, //NOXREF + //{ 0x01D8C180, "ReplyServerChallenge", (size_t)&ReplyServerChallenge }, //NOXREF + //{ 0x01D8C200, "ValidChallenge", (size_t)&ValidChallenge }, //NOXREF + //{ 0x01D8C260, "SVC_InfoString", (size_t)&SVC_InfoString }, //NOXREF + //{ 0x01D8C720, "SVC_Info", (size_t)&SVC_Info }, //NOXREF + //{ 0x01D8CA40, "SVC_PlayerInfo", (size_t)&SVC_PlayerInfo }, //NOXREF + //{ 0x01D8CBA0, "SVC_RuleInfo", (size_t)&SVC_RuleInfo }, //NOXREF + { 0x01D8CCC0, "SVC_GameDllQuery", (size_t)&SVC_GameDllQuery }, + { 0x01D8CD70, "SV_FlushRedirect", (size_t)&SV_FlushRedirect }, + { 0x01D8CE70, "SV_BeginRedirect", (size_t)&SV_BeginRedirect }, + { 0x01D8CEA0, "SV_EndRedirect", (size_t)&SV_EndRedirect }, + { 0x01D8CEB0, "SV_ResetRcon_f", (size_t)&SV_ResetRcon_f }, + { 0x01D8CED0, "SV_AddFailedRcon", (size_t)&SV_AddFailedRcon }, + { 0x01D8D1F0, "SV_CheckRconFailure", (size_t)&SV_CheckRconFailure }, + { 0x01D8D250, "SV_Rcon_Validate", (size_t)&SV_Rcon_Validate }, + { 0x01D8D370, "SV_Rcon", (size_t)&SV_Rcon }, + { 0x01D8D560, "SV_ConnectionlessPacket", (size_t)&SV_ConnectionlessPacket }, + { 0x01D8D750, "SV_CheckRate", (size_t)&SV_CheckRate }, + { 0x01D8D810, "SV_ProcessFile", (size_t)&SV_ProcessFile }, + { 0x01D8D960, "SV_FilterPacket", (size_t)&SV_FilterPacket }, + { 0x01D8DA30, "SV_SendBan", (size_t)&SV_SendBan }, + { 0x01D8DAB0, "SV_ReadPackets", (size_t)&SV_ReadPackets }, + //{ 0x, "ntohl", (size_t)&ntohl }, + //{ 0x, "htons", (size_t)&htons }, + { 0x01D8DCC0, "SV_CheckTimeouts", (size_t)&SV_CheckTimeouts }, + { 0x01D8DD50, "SV_CalcPing", (size_t)&SV_CalcPing }, + { 0x01D8DE20, "SV_FullClientUpdate", (size_t)&SV_FullClientUpdate }, + { 0x01D8DEF0, "SV_EmitEvents", (size_t)&SV_EmitEvents }, + { 0x01D8E0F0, "SV_AddToFatPVS", (size_t)&SV_AddToFatPVS }, + { 0x01D8E1B0, "SV_FatPVS", (size_t)&SV_FatPVS }, + { 0x01D8E200, "SV_AddToFatPAS", (size_t)&SV_AddToFatPAS }, + { 0x01D8E2D0, "SV_FatPAS", (size_t)&SV_FatPAS }, + { 0x01D8E320, "SV_PointLeafnum", (size_t)&SV_PointLeafnum }, + //{ 0x, "TRACE_DELTA", (size_t)&TRACE_DELTA }, //NOXREF + { 0x01D8E370, "SV_SetCallback", (size_t)&SV_SetCallback }, + { 0x01D8E3C0, "SV_SetNewInfo", (size_t)&SV_SetNewInfo }, + { 0x01D8E3E0, "SV_WriteDeltaHeader", (size_t)&SV_WriteDeltaHeader }, + { 0x01D8E4E0, "SV_InvokeCallback", (size_t)&SV_InvokeCallback }, + { 0x01D8E520, "SV_FindBestBaseline", (size_t)&SV_FindBestBaseline }, + { 0x01D8E650, "SV_CreatePacketEntities", (size_t)&SV_CreatePacketEntities }, + { 0x01D8E9A0, "SV_EmitPacketEntities", (size_t)&SV_EmitPacketEntities }, + { 0x01D8E9E0, "SV_ShouldUpdatePing", (size_t)&SV_ShouldUpdatePing }, + //{ 0x01D8EA40, "SV_HasEventsInQueue", (size_t)&SV_HasEventsInQueue }, //NOXREF + { 0x01D8EA70, "SV_GetNetInfo", (size_t)&SV_GetNetInfo }, + { 0x01D8EB00, "SV_CheckVisibility", (size_t)&SV_CheckVisibility }, + { 0x01D8EBF0, "SV_EmitPings", (size_t)&SV_EmitPings }, + { 0x01D8EC90, "SV_WriteEntitiesToClient", (size_t)&SV_WriteEntitiesToClient }, + { 0x01D8EE90, "SV_CleanupEnts", (size_t)&SV_CleanupEnts }, + { 0x01D8EEC0, "SV_SendClientDatagram", (size_t)&SV_SendClientDatagram }, + { 0x01D8EFC0, "SV_UpdateToReliableMessages", (size_t)&SV_UpdateToReliableMessages }, + { 0x01D8F230, "SV_SkipUpdates", (size_t)&SV_SkipUpdates }, + { 0x01D8F280, "SV_SendClientMessages", (size_t)&SV_SendClientMessages }, + { 0x01D8F470, "SV_ExtractFromUserinfo", (size_t)&SV_ExtractFromUserinfo }, + { 0x01D8F870, "SV_ModelIndex", (size_t)&SV_ModelIndex }, + { 0x01D8F8E0, "SV_AddResource", (size_t)&SV_AddResource }, + { 0x01D8F950, "SV_CreateGenericResources", (size_t)&SV_CreateGenericResources }, + { 0x01D8FC30, "SV_CreateResourceList", (size_t)&SV_CreateResourceList }, + { 0x01D8FDC0, "SV_ClearCaches", (size_t)&SV_ClearCaches }, + { 0x01D8FE00, "SV_PropagateCustomizations", (size_t)&SV_PropagateCustomizations }, + { 0x01D8FF00, "SV_WriteVoiceCodec", (size_t)&SV_WriteVoiceCodec }, + { 0x01D8FF30, "SV_CreateBaseline", (size_t)&SV_CreateBaseline }, + { 0x01D90170, "SV_BroadcastCommand", (size_t)&SV_BroadcastCommand }, + { 0x01D90260, "SV_BuildReconnect", (size_t)&SV_BuildReconnect }, + //{ 0x01D90280, "SV_ReconnectAllClients", (size_t)&SV_ReconnectAllClients }, //NOXREF + { 0x01D903D0, "SetCStrikeFlags", (size_t)&SetCStrikeFlags }, + { 0x01D904E0, "SV_ActivateServer", (size_t)&SV_ActivateServer }, + { 0x01D90790, "SV_ServerShutdown", (size_t)&SV_ServerShutdown }, + { 0x01D907C0, "SV_SpawnServer", (size_t)&SV_SpawnServer }, + { 0x01D90E70, "SV_LoadEntities", (size_t)&SV_LoadEntities }, + { 0x01D90E90, "SV_ClearEntities", (size_t)&SV_ClearEntities }, + { 0x01D90ED0, "RegUserMsg", (size_t)&RegUserMsg }, + { 0x01D90F80, "StringToFilter", (size_t)&StringToFilter }, + { 0x01D91020, "SV_StringToUserID", (size_t)&SV_StringToUserID }, + { 0x01D910C0, "SV_BanId_f", (size_t)&SV_BanId_f }, + { 0x01D915C0, "Host_Kick_f", (size_t)&Host_Kick_f }, + { 0x01D91990, "SV_RemoveId_f", (size_t)&SV_RemoveId_f }, + { 0x01D91B90, "SV_WriteId_f", (size_t)&SV_WriteId_f }, + { 0x01D91C60, "SV_ListId_f", (size_t)&SV_ListId_f }, + { 0x01D91D00, "SV_AddIP_f", (size_t)&SV_AddIP_f }, + { 0x01D91F00, "SV_RemoveIP_f", (size_t)&SV_RemoveIP_f }, + { 0x01D91FD0, "SV_ListIP_f", (size_t)&SV_ListIP_f }, + { 0x01D920B0, "SV_WriteIP_f", (size_t)&SV_WriteIP_f }, + { 0x01D92190, "SV_KickPlayer", (size_t)&SV_KickPlayer }, + { 0x01D92300, "SV_InactivateClients", (size_t)&SV_InactivateClients }, + { 0x01D923A0, "SV_FailDownload", (size_t)&SV_FailDownload }, + { 0x01D923E0, "Q_stristr", (size_t)&Q_stristr }, + { 0x01D92480, "IsSafeFileToDownload", (size_t)&IsSafeFileToDownload }, + { 0x01D92710, "SV_BeginFileDownload_f", (size_t)&SV_BeginFileDownload_f }, + { 0x01D92940, "SV_SetMaxclients", (size_t)&SV_SetMaxclients }, + { 0x01D92B00, "SV_HandleRconPacket", (size_t)&SV_HandleRconPacket }, + { 0x01D92B70, "SV_CheckCmdTimes", (size_t)&SV_CheckCmdTimes }, + { 0x01D92C60, "SV_CheckForRcon", (size_t)&SV_CheckForRcon }, + { 0x01D92CC0, "SV_IsSimulating", (size_t)&SV_IsSimulating }, + { 0x01D92D00, "SV_CheckMapDifferences", (size_t)&SV_CheckMapDifferences }, + { 0x01D92D80, "SV_Frame", (size_t)&SV_Frame }, + { 0x01D92E00, "SV_Drop_f", (size_t)&SV_Drop_f }, + { 0x01D92E40, "SV_RegisterDelta", (size_t)&SV_RegisterDelta }, + { 0x01D92EC0, "SV_InitDeltas", (size_t)&SV_InitDeltas }, + { 0x01D93010, "SV_InitEncoders", (size_t)&SV_InitEncoders }, + { 0x01D93050, "SV_Init", (size_t)&SV_Init }, + { 0x01D93600, "SV_Shutdown", (size_t)&SV_Shutdown }, + { 0x01D93650, "SV_CompareUserID", (size_t)&SV_CompareUserID }, + { 0x01D936D0, "SV_GetIDString", (size_t)&SV_GetIDString }, + { 0x01D938E0, "SV_GetClientIDString", (size_t)&SV_GetClientIDString }, + { 0x01D93950, "GetGameAppID", (size_t)&GetGameAppID }, + { 0x01D939C0, "IsGameSubscribed", (size_t)&IsGameSubscribed }, + { 0x01D93A10, "BIsValveGame", (size_t)&BIsValveGame }, //NOXREF + +#endif // Sv_Main_region + +#ifndef Zone_region + + { 0x01DBB120, "Z_ClearZone", (size_t)&Z_ClearZone }, + { 0x01DBB170, "Z_Free", (size_t)&Z_Free }, + { 0x01DBB220, "Z_Malloc", (size_t)&Z_Malloc }, + { 0x01DBB260, "Z_TagMalloc", (size_t)&Z_TagMalloc }, + { 0x01DBB310, "Z_Print", (size_t)&Z_Print }, // NOXREF + { 0x01DBB3C0, "Z_CheckHeap", (size_t)&Z_CheckHeap }, + + { 0x01DBB440, "Hunk_Check", (size_t)&Hunk_Check }, + { 0x01DBB4B0, "Hunk_Print", (size_t)&Hunk_Print }, // NOXREF + { 0x01DBB6B0, "Hunk_AllocName", (size_t)&Hunk_AllocName }, + { 0x01DBB750, "Hunk_Alloc", (size_t)&Hunk_Alloc }, + { 0x01DBB770, "Hunk_LowMark", (size_t)&Hunk_LowMark }, + { 0x01DBB780, "Hunk_FreeToLowMark", (size_t)&Hunk_FreeToLowMark }, + { 0x01DBB7B0, "Hunk_HighMark", (size_t)&Hunk_HighMark }, + { 0x01DBB7E0, "Hunk_FreeToHighMark", (size_t)&Hunk_FreeToHighMark }, + { 0x01DBB830, "Hunk_HighAllocName", (size_t)&Hunk_HighAllocName }, + { 0x01DBB900, "Hunk_TempAlloc", (size_t)&Hunk_TempAlloc }, + + { 0x01DBB960, "Cache_Move", (size_t)&Cache_Move }, + { 0x01DBB9D0, "Cache_FreeLow", (size_t)&Cache_FreeLow }, + { 0x01DBBA00, "Cache_FreeHigh", (size_t)&Cache_FreeHigh }, + { 0x01DBBA60, "Cache_UnlinkLRU", (size_t)&Cache_UnlinkLRU }, + { 0x01DBBAA0, "Cache_MakeLRU", (size_t)&Cache_MakeLRU }, + { 0x01DBBAF0, "Cache_TryAlloc", (size_t)&Cache_TryAlloc }, + { 0x01DBBC30, "Cache_Force_Flush", (size_t)&Cache_Force_Flush }, + { 0x01DBBC60, "Cache_Flush", (size_t)&Cache_Flush }, + { 0x01DBBD60, "CacheSystemCompare", (size_t)&CacheSystemCompare }, // NOXREF + { 0x01DBBC90, "Cache_Print", (size_t)&Cache_Print }, // NOXREF + //{ 0x, "ComparePath1", (size_t)&ComparePath1 }, // NOXREF // not yet located on windows + //{ 0x, "CommatizeNumber", (size_t)&CommatizeNumber }, // NOXREF // not yet located on windows + //{ 0x, "Cache_Report", (size_t)&Cache_Report }, // NOXREF // not yet located on windows + //{ 0x, "Cache_Compact", (size_t)&Cache_Compact }, // NOXREF // not yet located on windows + { 0x01DBBED0, "Cache_Init", (size_t)&Cache_Init }, + { 0x01DBBF00, "Cache_Free", (size_t)&Cache_Free }, + { 0x01DBBF50, "Cache_TotalUsed", (size_t)&Cache_TotalUsed }, // NOXREF + { 0x01DBBF70, "Cache_Check", (size_t)&Cache_Check }, + { 0x01DBBFA0, "Cache_Alloc", (size_t)&Cache_Alloc }, + { 0x01DBC040, "Memory_Init", (size_t)&Memory_Init }, + //{ 0x01DBC0E0, "Cache_Print_Sounds_And_Totals", (size_t)&Cache_Print_Models_And_Totals }, // NOXREF + //{ 0x01DBC1F0, "Cache_Print_Sounds_And_Totals", (size_t)&Cache_Print_Sounds_And_Totals }, // NOXREF + +#endif // Zone_region + +#ifndef FileSystem_Internal_region + + { 0x01D3E2E0, "FS_RemoveAllSearchPaths", (size_t)&FS_RemoveAllSearchPaths }, // NOXREF + { 0x01D3E2F0, "FS_AddSearchPath", (size_t)&FS_AddSearchPath }, + { 0x01D3E310, "FS_RemoveSearchPath", (size_t)&FS_RemoveSearchPath }, // NOXREF + { 0x01D3E330, "FS_RemoveFile", (size_t)&FS_RemoveFile }, + { 0x01D3E350, "FS_CreateDirHierarchy", (size_t)&FS_CreateDirHierarchy }, + { 0x01D3E370, "FS_FileExists", (size_t)&FS_FileExists }, + { 0x01D3E390, "FS_IsDirectory", (size_t)&FS_IsDirectory }, // NOXREF + { 0x01D3E3B0, "FS_Open", (size_t)&FS_Open }, + { 0x01D3E3D0, "FS_OpenPathID", (size_t)&FS_OpenPathID }, + { 0x01D3E3F0, "FS_Close", (size_t)&FS_Close }, + { 0x01D3E410, "FS_Seek", (size_t)&FS_Seek }, + { 0x01D3E430, "FS_Tell", (size_t)&FS_Tell }, + { 0x01D3E450, "FS_Size", (size_t)&FS_Size }, + { 0x01D3E470, "FS_FileSize", (size_t)&FS_FileSize }, + { 0x01D3E490, "FS_GetFileTime", (size_t)&FS_GetFileTime }, + { 0x01D3E4B0, "FS_FileTimeToString", (size_t)&FS_FileTimeToString }, // NOXREF + { 0x01D3E4D0, "FS_IsOk", (size_t)&FS_IsOk }, + { 0x01D3E4F0, "FS_Flush", (size_t)&FS_Flush }, + { 0x01D3E510, "FS_EndOfFile", (size_t)&FS_EndOfFile }, + { 0x01D3E530, "FS_Read", (size_t)&FS_Read }, + { 0x01D3E550, "FS_Write", (size_t)&FS_Write }, + { 0x01D3E570, "FS_ReadLine", (size_t)&FS_ReadLine }, + { 0x01D3E590, "FS_FPrintf", (size_t)&FS_FPrintf }, + { 0x01D3E5E0, "FS_FindFirst", (size_t)&FS_FindFirst }, + { 0x01D3E600, "FS_FindNext", (size_t)&FS_FindNext }, + { 0x01D3E620, "FS_FindIsDirectory", (size_t)&FS_FindIsDirectory }, // NOXREF + { 0x01D3E640, "FS_FindClose", (size_t)&FS_FindClose }, + { 0x01D3E660, "FS_GetLocalCopy", (size_t)&FS_GetLocalCopy }, + { 0x01D3E680, "FS_GetLocalPath", (size_t)&FS_GetLocalPath }, + { 0x01D3E6A0, "FS_ParseFile", (size_t)&FS_ParseFile }, // NOXREF + { 0x01D3E6E0, "FS_FullPathToRelativePath", (size_t)&FS_FullPathToRelativePath }, // NOXREF + { 0x01D3E700, "FS_GetCurrentDirectory", (size_t)&FS_GetCurrentDirectory }, // NOXREF + { 0x01D3E720, "FS_PrintOpenedFiles", (size_t)&FS_PrintOpenedFiles }, // NOXREF + { 0x01D3E730, "FS_SetWarningFunc", (size_t)&FS_SetWarningFunc }, // NOXREF + { 0x01D3E750, "FS_SetWarningLevel", (size_t)&FS_SetWarningLevel }, // NOXREF + { 0x01D3E770, "FS_GetCharacter", (size_t)&FS_GetCharacter }, // NOXREF + { 0x01D3E790, "FS_LogLevelLoadStarted", (size_t)&FS_LogLevelLoadStarted }, + { 0x01D3E7B0, "FS_LogLevelLoadFinished", (size_t)&FS_LogLevelLoadFinished }, + { 0x01D3E7D0, "FS_SetVBuf", (size_t)&FS_SetVBuf }, + { 0x01D3E800, "FS_GetInterfaceVersion", (size_t)&FS_GetInterfaceVersion }, + { 0x01D3E820, "FS_GetReadBuffer", (size_t)&FS_GetReadBuffer }, + { 0x01D3E840, "FS_ReleaseReadBuffer", (size_t)&FS_ReleaseReadBuffer }, + { 0x01D3E860, "FS_Unlink", (size_t)&FS_Unlink }, + { 0x01D3E8A0, "FS_Rename", (size_t)&FS_Rename }, + { 0x01D3E940, "FS_LoadLibrary", (size_t)&FS_LoadLibrary }, + +#endif // FileSystem_Internal_region + +#ifndef FileSystem_region + + { 0x01D3D340, "GetBaseDirectory", (size_t)&GetBaseDirectory }, + { 0x01D3D355, "_Z20GetFileSystemFactoryv", (size_t)&GetFileSystemFactory }, // NOXREF + //{ 0x01D3E250, "FileSystem_LoadDLL", (size_t)&FileSystem_LoadDLL }, // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out + //{ 0x01D3E2C0, "FileSystem_UnloadDLL", (size_t)&FileSystem_UnloadDLL }, // Totally not exists on Linux (it is inlined), but present and used on Windows, anyway just commented it out + { 0x01D3D360, "BEnabledHDAddon", (size_t)&BEnabledHDAddon }, + { 0x01D3D390, "BEnableAddonsFolder", (size_t)&BEnableAddonsFolder }, + + { 0x01D3D3C0, "Host_SetHDModels_f", (size_t)&Host_SetHDModels_f }, + { 0x01D3D440, "Host_SetAddonsFolder_f", (size_t)&Host_SetAddonsFolder_f }, + { 0x01D3D4C0, "Host_SetVideoLevel_f", (size_t)&Host_SetVideoLevel_f }, + { 0x01D3D510, "Host_GetVideoLevel", (size_t)&Host_GetVideoLevel }, + + { 0x01D3D530, "_Z26CheckLiblistForFallbackDirPKcbS0_b", (size_t)&CheckLiblistForFallbackDir }, + { 0x01D3DA60, "FileSystem_SetGameDirectory", (size_t)&FileSystem_SetGameDirectory }, + { 0x01D3E130, "FileSystem_AddFallbackGameDir", (size_t)&FileSystem_AddFallbackGameDir }, + { 0x01D3E200, "_Z15FileSystem_InitPcPv", (size_t)&FileSystem_Init }, + { 0x01D3E2B0, "_Z19FileSystem_Shutdownv", (size_t)&FileSystem_Shutdown }, + +#endif // FileSystem_region + +#ifndef Unicode_StrTools_region + + { 0x01DA8F00, "_Z16Q_IsValidUChar32w", (size_t)&Q_IsValidUChar32 }, + { 0x01DA97D0, "_Z15Q_UTF8ToUChar32PKcRwRb", (size_t)&Q_UTF8ToUChar32 }, + { 0x01DA9910, "Q_UnicodeValidate", (size_t)&Q_UnicodeValidate }, + { 0x01DA99A0, "Q_UnicodeAdvance", (size_t)&Q_UnicodeAdvance }, + { 0x01DA9EA0, "Q_UnicodeRepair", (size_t)&Q_UnicodeRepair }, + { 0x01DA9E70, "V_UTF8ToUChar32", (size_t)&V_UTF8ToUChar32 }, + +#endif // Unicode_StrTools_region + +#ifndef Cmd_region + + { 0x01D26CD0, "Cmd_Wait_f", (size_t)&Cmd_Wait_f }, + { 0x01D26CE0, "Cbuf_Init", (size_t)&Cbuf_Init }, + { 0x01D26D00, "Cbuf_AddText", (size_t)&Cbuf_AddText }, + { 0x01D26D50, "Cbuf_InsertText", (size_t)&Cbuf_InsertText }, + { 0x01D26DE0, "Cbuf_InsertTextLines", (size_t)&Cbuf_InsertTextLines }, + { 0x01D26E80, "Cbuf_Execute", (size_t)&Cbuf_Execute }, + { 0x01D26F60, "Cmd_StuffCmds_f", (size_t)&Cmd_StuffCmds_f }, + { 0x01D270F0, "Cmd_Exec_f", (size_t)&Cmd_Exec_f }, + { 0x01D273A0, "Cmd_Echo_f", (size_t)&Cmd_Echo_f }, + { 0x01D273E0, "CopyString", (size_t)&CopyString }, + { 0x01D27410, "Cmd_Alias_f", (size_t)&Cmd_Alias_f }, + { 0x01D276A0, "Cmd_GetFirstCmd", (size_t)&Cmd_GetFirstCmd }, + { 0x01D276B0, "Cmd_Init", (size_t)&Cmd_Init }, + { 0x01D27720, "Cmd_Shutdown", (size_t)&Cmd_Shutdown }, + { 0x01D27750, "Cmd_Argc", (size_t)&Cmd_Argc }, + { 0x01D27760, "Cmd_Argv", (size_t)&Cmd_Argv }, + { 0x01D27790, "Cmd_Args", (size_t)&Cmd_Args }, + { 0x01D277A0, "Cmd_TokenizeString", (size_t)&Cmd_TokenizeString }, + { 0x01D27880, "Cmd_FindCmd", (size_t)&Cmd_FindCmd }, // NOXREF + { 0x01D278C0, "Cmd_FindCmdPrev", (size_t)&Cmd_FindCmdPrev }, // NOXREF + { 0x01D27900, "Cmd_AddCommand", (size_t)&Cmd_AddCommand }, + { 0x01D27A10, "Cmd_AddMallocCommand", (size_t)&Cmd_AddMallocCommand }, + { 0x01D27AB0, "Cmd_AddHUDCommand", (size_t)&Cmd_AddHUDCommand }, // NOXREF + { 0x01D27AD0, "Cmd_AddWrapperCommand", (size_t)&Cmd_AddWrapperCommand }, // NOXREF + { 0x01D27AF0, "Cmd_AddGameCommand", (size_t)&Cmd_AddGameCommand }, + { 0x01D27B10, "Cmd_RemoveMallocedCmds", (size_t)&Cmd_RemoveMallocedCmds }, + { 0x01D27B50, "Cmd_RemoveHudCmds", (size_t)&Cmd_RemoveHudCmds }, // NOXREF + { 0x01D27B60, "Cmd_RemoveGameCmds", (size_t)&Cmd_RemoveGameCmds }, + { 0x01D27B70, "Cmd_RemoveWrapperCmds", (size_t)&Cmd_RemoveWrapperCmds }, + { 0x01D27B80, "Cmd_Exists", (size_t)&Cmd_Exists }, + { 0x01D27BC0, "Cmd_CompleteCommand", (size_t)&Cmd_CompleteCommand }, // NOXREF + { 0x01D27D10, "Cmd_ExecuteString", (size_t)&Cmd_ExecuteString }, + { 0x01D27DF0, "Cmd_ForwardToServerInternal", (size_t)&Cmd_ForwardToServerInternal }, + { 0x01D27F40, "Cmd_ForwardToServer", (size_t)&Cmd_ForwardToServer }, + { 0x01D27F90, "Cmd_ForwardToServerUnreliable", (size_t)&Cmd_ForwardToServerUnreliable }, + { 0x01D27FA0, "Cmd_CheckParm", (size_t)&Cmd_CheckParm }, // NOXREF + { 0x01D28000, "Cmd_CmdList_f", (size_t)&Cmd_CmdList_f }, + +#endif // Cmd_region + +#ifndef Cvar_region + + { 0x01D2D760, "Cvar_Init", (size_t)&Cvar_Init }, + { 0x01D2D770, "Cvar_Shutdown", (size_t)&Cvar_Shutdown }, + { 0x01D2D780, "Cvar_FindVar", (size_t)&Cvar_FindVar }, + { 0x01D2D7C0, "Cvar_FindPrevVar", (size_t)&Cvar_FindPrevVar }, // NOXREF + { 0x01D2D800, "Cvar_VariableValue", (size_t)&Cvar_VariableValue }, + { 0x01D2D830, "Cvar_VariableInt", (size_t)&Cvar_VariableInt }, // NOXREF + { 0x01D2D860, "Cvar_VariableString", (size_t)&Cvar_VariableString }, + { 0x01D2D880, "Cvar_CompleteVariable", (size_t)&Cvar_CompleteVariable }, // NOXREF + { 0x01D2D9C0, "Cvar_DirectSet", (size_t)&Cvar_DirectSet }, + { 0x01D2DC30, "Cvar_Set", (size_t)&Cvar_Set }, + { 0x01D2DC70, "Cvar_SetValue", (size_t)&Cvar_SetValue }, + { 0x01D2DD20, "Cvar_RegisterVariable", (size_t)&Cvar_RegisterVariable }, + { 0x01D2DE10, "Cvar_RemoveHudCvars", (size_t)&Cvar_RemoveHudCvars }, // NOXREF + { 0x01D2DE70, "Cvar_IsMultipleTokens", (size_t)&Cvar_IsMultipleTokens }, + { 0x01D2DED0, "Cvar_Command", (size_t)&Cvar_Command }, + { 0x01D2DFA0, "Cvar_WriteVariables", (size_t)&Cvar_WriteVariables }, // NOXREF + { 0x01D2DFE0, "Cmd_CvarListPrintCvar", (size_t)&Cmd_CvarListPrintCvar }, + { 0x01D2E0F0, "Cmd_CvarList_f", (size_t)&Cmd_CvarList_f }, + { 0x01D2E330, "Cvar_CountServerVariables", (size_t)&Cvar_CountServerVariables }, // NOXREF + { 0x01D2E350, "Cvar_UnlinkExternals", (size_t)&Cvar_UnlinkExternals }, + { 0x01D2E380, "Cvar_CmdInit", (size_t)&Cvar_CmdInit }, + +#endif // Cvar_region + +#ifndef Info_region + + { 0x01D4B610, "Info_ValueForKey", (size_t)&Info_ValueForKey }, + { 0x01D4B6E0, "Info_RemoveKey", (size_t)&Info_RemoveKey }, + { 0x01D4B7D0, "Info_RemovePrefixedKeys", (size_t)&Info_RemovePrefixedKeys }, + { 0x01D4B860, "Info_IsKeyImportant", (size_t)&Info_IsKeyImportant }, + { 0x01D4B980, "Info_FindLargestKey", (size_t)&Info_FindLargestKey }, + { 0x01D4BA80, "Info_SetValueForStarKey", (size_t)&Info_SetValueForStarKey }, + { 0x01D4BCF0, "Info_SetValueForKey", (size_t)&Info_SetValueForKey }, + { 0x01D4BD30, "Info_Print", (size_t)&Info_Print }, + { 0x01D4BE10, "Info_IsValid", (size_t)&Info_IsValid }, + +#endif // Info_region + +#ifndef SysDll_region + + //{ 0x, "Sys_PageIn", (size_t)&Sys_PageIn }, + { 0x01D9ECF0, "Sys_FindFirst", (size_t)&Sys_FindFirst }, + { 0x01D9ED50, "Sys_FindFirstPathID", (size_t)&Sys_FindFirstPathID }, + { 0x01D9ED90, "Sys_FindNext", (size_t)&Sys_FindNext }, + { 0x01D9EDC0, "Sys_FindClose", (size_t)&Sys_FindClose }, + //{ 0x01D9EDE0, "glob_match_after_star", (size_t)&glob_match_after_star }, + //{ 0x01D9EF50, "glob_match", (size_t)&glob_match }, + //{ 0x01D9EFD0, "Sys_MakeCodeWriteable", (size_t)&Sys_MakeCodeWriteable }, + //{ 0x, "Sys_SetFPCW", (size_t)&Sys_SetFPCW }, + //{ 0x, "Sys_PushFPCW_SetHigh", (size_t)&Sys_PushFPCW_SetHigh }, + //{ 0x, "Sys_PopFPCW", (size_t)&Sys_PopFPCW }, + //{ 0x, "MaskExceptions", (size_t)&MaskExceptions }, + //{ 0x, "Sys_Init", (size_t)&Sys_Init }, // NOXREF + //{ 0x, "Sys_Sleep", (size_t)&Sys_Sleep }, + //{ 0x, "Sys_DebugOutStraight", (size_t)&Sys_DebugOutStraight }, + //{ 0x01D9F0E0, "Sys_Error", (size_t)&Sys_Error }, + //{ 0x01D9F1F0, "Sys_Warning", (size_t)&Sys_Warning }, + { 0x01D9F230, "Sys_Printf", (size_t)&Sys_Printf }, + { 0x01D9F4A0, "Sys_Quit", (size_t)&Sys_Quit }, + { 0x01D9F2A0, "Sys_FloatTime", (size_t)&Sys_FloatTime }, + { 0x01D9F460, "Dispatch_Substate", (size_t)&Dispatch_Substate }, + { 0x01D9F470, "GameSetSubState", (size_t)&GameSetSubState }, + { 0x01D9F4A0, "GameSetState", (size_t)&GameSetState }, + //{ 0x, "GameSetBackground", (size_t)&GameSetBackground }, + { 0x01D9F7B0, "Voice_GetClientListening", (size_t)&Voice_GetClientListening }, + { 0x01D9F810, "Voice_SetClientListening", (size_t)&Voice_SetClientListening }, + { 0x01D9F890, "GetDispatch", (size_t)&GetDispatch }, + { 0x01D9F8D0, "FindAddressInTable", (size_t)&FindAddressInTable }, + { 0x01D9F910, "FindNameInTable", (size_t)&FindNameInTable }, + //{ 0x, "ConvertNameToLocalPlatform", (size_t)&ConvertNameToLocalPlatform }, + { 0x01D9FAA0, "FunctionFromName", (size_t)&FunctionFromName }, + { 0x01D9FB00, "NameForFunction", (size_t)&NameForFunction }, + { 0x01D9FB50, "GetEntityInit", (size_t)&GetEntityInit }, + { 0x01D9FB70, "GetIOFunction", (size_t)&GetIOFunction }, + { 0x01D9FB90, "DLL_SetModKey", (size_t)&DLL_SetModKey }, + { 0x01D9FE50, "LoadEntityDLLs", (size_t)&LoadEntityDLLs }, + { 0x01DA02D0, "LoadThisDll", (size_t)&LoadThisDll }, + { 0x01DA0390, "ReleaseEntityDlls", (size_t)&ReleaseEntityDlls }, + //{ 0x01DA0410, "EngineFprintf", (size_t)&EngineFprintf }, + { 0x01DA0420, "AlertMessage", (size_t)&AlertMessage }, + //{ 0x01DA0640, "Sys_SplitPath", (size_t)&Sys_SplitPath }, + { 0x01D2BD90, "Con_Debug_f", (size_t)&Con_Debug_f }, + { 0x01D2BDD0, "Con_Init", (size_t)&Con_Init }, + { 0x01D2BFC0, "Con_DebugLog", (size_t)&Con_DebugLog }, + { 0x01D2C020, "Con_Printf", (size_t)&Con_Printf }, + { 0x01D2C1E0, "Con_SafePrintf", (size_t)&Con_SafePrintf }, + { 0x01D2C140, "Con_DPrintf", (size_t)&Con_DPrintf }, + +#ifdef _WIN32 + { 0x01DA0A70, "Sys_InitHardwareTimer", (size_t)&Sys_InitHardwareTimer }, +#endif //_WIN32 + +#endif // SysDll_region + +#ifndef Sys_Dll2_region + + { 0x01DA0670, "GetCurrentSteamAppName", (size_t)&GetCurrentSteamAppName }, + //{ 0x01DA0760, "SetRateRegistrySetting", (size_t)&SetRateRegistrySetting }, // NOXREF + //{ 0x01DA0780, "GetRateRegistrySetting", (size_t)&GetRateRegistrySetting }, // NOXREF + { 0x01DA07A0, "F", (size_t)&F }, + { 0x01DA0820, "Sys_GetCDKey", (size_t)&Sys_GetCDKey }, + //{ 0x01DA0930, "_Z19Legacy_ErrorMessageiPKc", (size_t)&Legacy_ErrorMessage }, // NOXREF + { 0x01DA0940, "_Z17Legacy_Sys_PrintfPcz", (size_t)&Legacy_Sys_Printf }, + //{ 0x01DA0980, "_Z30Legacy_MP3subsys_Suspend_Audiov", (size_t)&Legacy_MP3subsys_Suspend_Audio }, // NOXREF + //{ 0x01DA0990, "_Z29Legacy_MP3subsys_Resume_Audiov", (size_t)&Legacy_MP3subsys_Resume_Audio }, // NOXREF +#ifndef _WIN32 + { 0x0, "_Z19Sys_SetupLegacyAPIsv", (size_t)&Sys_SetupLegacyAPIs }, +#endif + //{ 0x01DA09C0, "_Z11Sys_IsWin95v", (size_t)&Sys_IsWin95 }, // NOXREF + //{ 0x01DA09D0, "_Z11Sys_IsWin98v", (size_t)&Sys_IsWin98 }, // NOXREF +#ifdef _WIN32 + //{ 0x, "_Z18Sys_CheckOSVersionv", (size_t)&Sys_CheckOSVersion }, // NOXREF +#endif + //{ 0x, "Sys_Init", (size_t)&Sys_Init }, // NOXREF + //{ 0x, "Sys_Shutdown", (size_t)&Sys_Shutdown }, // NOXREF + { 0x01DA0B70, "_Z12Sys_InitArgvPc", (size_t)&Sys_InitArgv }, + //{ 0x, "Sys_ShutdownArgv", (size_t)&Sys_ShutdownArgv }, // NOXREF + { 0x01DA0C20, "_Z14Sys_InitMemoryv", (size_t)&Sys_InitMemory }, + { 0x01DA0D50, "Sys_ShutdownMemory", (size_t)&Sys_ShutdownMemory }, + { 0x01DA0D70, "_Z25Sys_InitLauncherInterfacev", (size_t)&Sys_InitLauncherInterface }, + //{ 0x, "Sys_ShutdownLauncherInterface", (size_t)&Sys_ShutdownLauncherInterface }, // NOXREF + { 0x01DA0DA0, "_Z22Sys_InitAuthenticationv", (size_t)&Sys_InitAuthentication }, + //{ 0x, "Sys_ShutdownAuthentication", (size_t)&Sys_ShutdownAuthentication }, // NOXREF + { 0x01DA0DC0, "_Z21Sys_ShowProgressTicksPc", (size_t)&Sys_ShowProgressTicks }, + { 0x01DA0ED0, "_Z12Sys_InitGamePcS_Pvi", (size_t)&Sys_InitGame }, + { 0x01DA0FE0, "_Z16Sys_ShutdownGamev", (size_t)&Sys_ShutdownGame }, + { 0x01DA1060, "_Z13ClearIOStatesv", (size_t)&ClearIOStates }, + //{ 0x01DA13E0, "_Z22BuildMapCycleListHintsPPc", (size_t)&BuildMapCycleListHints }, // NOXREF + + { 0x01DA16B0, "_ZN19CDedicatedServerAPI4InitEPcS0_PFP14IBaseInterfacePKcPiES7_", mfunc_ptr_cast(&CDedicatedServerAPI::Init_noVirt) }, + { 0x01DA1800, "_ZN19CDedicatedServerAPI8ShutdownEv", mfunc_ptr_cast(&CDedicatedServerAPI::Shutdown_noVirt) }, + { 0x01DA1860, "_ZN19CDedicatedServerAPI8RunFrameEv", mfunc_ptr_cast(&CDedicatedServerAPI::RunFrame_noVirt) }, + { 0x01DA1880, "_ZN19CDedicatedServerAPI14AddConsoleTextEPc", mfunc_ptr_cast(&CDedicatedServerAPI::AddConsoleText_noVirt) }, + { 0x01DA18A0, "_ZN19CDedicatedServerAPI12UpdateStatusEPfPiS1_Pc", mfunc_ptr_cast(&CDedicatedServerAPI::UpdateStatus_noVirt) }, + +#endif // Sys_Dll2_region + +#ifndef CModel_region + + { 0x01D281B0, "Mod_Init", (size_t)&Mod_Init }, + { 0x01D281D0, "Mod_DecompressVis", (size_t)&Mod_DecompressVis }, + { 0x01D28210, "Mod_LeafPVS", (size_t)&Mod_LeafPVS }, + { 0x01D28270, "CM_DecompressPVS", (size_t)&CM_DecompressPVS }, + { 0x01D282E0, "CM_LeafPVS", (size_t)&CM_LeafPVS }, + { 0x01D28310, "CM_LeafPAS", (size_t)&CM_LeafPAS }, + { 0x01D28340, "CM_FreePAS", (size_t)&CM_FreePAS }, + { 0x01D28380, "CM_CalcPAS", (size_t)&CM_CalcPAS }, + { 0x01D28580, "CM_HeadnodeVisible", (size_t)&CM_HeadnodeVisible }, + +#endif // CModel_region + +#ifndef Model_region + + { 0x01D50B80, "SW_Mod_Init", (size_t)&SW_Mod_Init }, + { 0x01D50B90, "Mod_Extradata", (size_t)&Mod_Extradata }, + { 0x01D50BF0, "Mod_PointInLeaf", (size_t)&Mod_PointInLeaf }, + { 0x01D50C80, "Mod_ClearAll", (size_t)&Mod_ClearAll }, + { 0x01D50CC0, "Mod_FillInCRCInfo", (size_t)&Mod_FillInCRCInfo }, + { 0x01D50CE0, "Mod_FindName", (size_t)&Mod_FindName }, + //{ 0x01D50DF0, "Mod_ValidateCRC", (size_t)&Mod_ValidateCRC }, // NOXREF + //{ 0x01D50E50, "Mod_NeedCRC", (size_t)&Mod_NeedCRC }, // NOXREF + { 0x01D50E90, "Mod_LoadModel", (size_t)&Mod_LoadModel }, + //{ 0x01D51100, "Mod_MarkClient", (size_t)&Mod_MarkClient }, // NOXREF + { 0x01D51110, "Mod_ForName", (size_t)&Mod_ForName }, + { 0x01D51150, "Mod_AdInit", (size_t)&Mod_AdInit }, + { 0x01D511F0, "Mod_AdSwap", (size_t)&Mod_AdSwap }, + { 0x01D51280, "Mod_LoadTextures", (size_t)&Mod_LoadTextures }, + { 0x01D517C0, "Mod_LoadLighting", (size_t)&Mod_LoadLighting }, + { 0x01D51810, "Mod_LoadVisibility", (size_t)&Mod_LoadVisibility }, + { 0x01D51860, "Mod_LoadEntities", (size_t)&Mod_LoadEntities }, + { 0x01D51930, "Mod_LoadVertexes", (size_t)&Mod_LoadVertexes }, + { 0x01D519E0, "Mod_LoadSubmodels", (size_t)&Mod_LoadSubmodels }, + { 0x01D51B10, "Mod_LoadEdges", (size_t)&Mod_LoadEdges }, + { 0x01D51BA0, "Mod_LoadTexinfo", (size_t)&Mod_LoadTexinfo }, + { 0x01D51D60, "CalcSurfaceExtents", (size_t)&CalcSurfaceExtents }, + { 0x01D51F10, "Mod_LoadFaces", (size_t)&Mod_LoadFaces }, + { 0x01D52140, "Mod_SetParent", (size_t)&Mod_SetParent }, + { 0x01D52180, "Mod_LoadNodes", (size_t)&Mod_LoadNodes }, + { 0x01D52330, "Mod_LoadLeafs", (size_t)&Mod_LoadLeafs }, + { 0x01D52490, "Mod_LoadClipnodes", (size_t)&Mod_LoadClipnodes }, + { 0x01D52630, "Mod_MakeHull0", (size_t)&Mod_MakeHull0 }, + { 0x01D52720, "Mod_LoadMarksurfaces", (size_t)&Mod_LoadMarksurfaces }, + { 0x01D527E0, "Mod_LoadSurfedges", (size_t)&Mod_LoadSurfedges }, + { 0x01D52860, "Mod_LoadPlanes", (size_t)&Mod_LoadPlanes }, + { 0x01D52970, "RadiusFromBounds", (size_t)&RadiusFromBounds }, + { 0x01D52A00, "Mod_LoadBrushModel", (size_t)&Mod_LoadBrushModel }, + //{ 0x01D52C30, "Mod_LoadAliasFrame", (size_t)&Mod_LoadAliasFrame }, + //{ 0x01D52CE0, "Mod_LoadAliasGroup", (size_t)&Mod_LoadAliasGroup }, + //{ 0x01D52DF0, "Mod_LoadAliasSkin", (size_t)&Mod_LoadAliasSkin }, + //{ 0x01D52E60, "Mod_LoadAliasSkinGroup", (size_t)&Mod_LoadAliasSkinGroup }, + //{ 0x01D52F40, "Mod_LoadAliasModel", (size_t)&Mod_LoadAliasModel }, + { 0x01D53410, "Mod_LoadSpriteFrame", (size_t)&Mod_LoadSpriteFrame }, + { 0x01D53510, "Mod_LoadSpriteGroup", (size_t)&Mod_LoadSpriteGroup }, + { 0x01D535E0, "Mod_LoadSpriteModel", (size_t)&Mod_LoadSpriteModel }, + //{ 0x01D53800, "Mod_UnloadSpriteTextures", (size_t)&Mod_UnloadSpriteTextures }, + { 0x01D53820, "Mod_Print", (size_t)&Mod_Print }, + //{ 0x01D538A0, "Mod_ChangeGame", (size_t)&Mod_ChangeGame }, + +#endif // Model_region + +#ifndef Sv_Log_region + + { 0x01D873D0, "Log_Printf", (size_t)&Log_Printf }, + { 0x01D875A0, "Log_PrintServerVars", (size_t)&Log_PrintServerVars }, + { 0x01D87600, "Log_Close", (size_t)&Log_Close }, + { 0x01D87630, "Log_Open", (size_t)&Log_Open }, + { 0x01D87850, "SV_SetLogAddress_f", (size_t)&SV_SetLogAddress_f }, + { 0x01D87990, "SV_AddLogAddress_f", (size_t)&SV_AddLogAddress_f }, + { 0x01D87BC0, "SV_DelLogAddress_f", (size_t)&SV_DelLogAddress_f }, + +#endif // Sv_Log_region + +#ifndef Cl_Null_region + + //{ 0x, "CL_RecordHUDCommand", (size_t)&CL_RecordHUDCommand }, + //{ 0x, "R_DecalRemoveAll", (size_t)&R_DecalRemoveAll }, + //{ 0x, "CL_CheckForResend", (size_t)&CL_CheckForResend }, + //{ 0x, "CL_CheckFile", (size_t)&CL_CheckFile }, + //{ 0x01D17350, "CL_ClearClientState", (size_t)&CL_ClearClientState }, + //{ 0x, "CL_Connect_f", (size_t)&CL_Connect_f }, + //{ 0x, "CL_DecayLights", (size_t)&CL_DecayLights }, + //{ 0x01D17490, "CL_Disconnect", (size_t)&CL_Disconnect }, + //{ 0x01D17660, "CL_Disconnect_f", (size_t)&CL_Disconnect_f }, + //{ 0x, "CL_EmitEntities", (size_t)&CL_EmitEntities }, + //{ 0x, "CL_InitClosest", (size_t)&CL_InitClosest }, + //{ 0x, "CL_Init", (size_t)&CL_Init }, + { 0x01D131E0, "CL_Particle", (size_t)&CL_Particle }, + //{ 0x, "CL_PredictMove", (size_t)&CL_PredictMove }, + //{ 0x, "CL_PrintLogos", (size_t)&CL_PrintLogos }, + //{ 0x, "CL_ReadPackets", (size_t)&CL_ReadPackets }, + //{ 0x, "CL_RequestMissingResources", (size_t)&CL_RequestMissingResources }, + //{ 0x, "CL_Move", (size_t)&CL_Move }, + //{ 0x, "CL_SendConnectPacket", (size_t)&CL_SendConnectPacket }, + //{ 0x01D0FABD, "CL_StopPlayback", (size_t)&CL_StopPlayback }, + //{ 0x, "CL_UpdateSoundFade", (size_t)&CL_UpdateSoundFade }, + //{ 0x, "CL_AdjustClock", (size_t)&CL_AdjustClock }, + //{ 0x01D48910, "CL_Save", (size_t)&CL_Save }, + //{ 0x01D19650, "CL_HudMessage", (size_t)&CL_HudMessage }, + + //{ 0x, "Key_WriteBindings", (size_t)&Key_WriteBindings }, + //{ 0x, "ClientDLL_UpdateClientData", (size_t)&ClientDLL_UpdateClientData }, + //{ 0x, "ClientDLL_HudVidInit", (size_t)&ClientDLL_HudVidInit }, + //{ 0x, "Chase_Init", (size_t)&Chase_Init }, + //{ 0x, "Key_Init", (size_t)&Key_Init }, + //{ 0x, "ClientDLL_Init", (size_t)&ClientDLL_Init }, + //{ 0x, "Con_Shutdown", (size_t)&Con_Shutdown }, + //{ 0x, "DispatchDirectUserMsg", (size_t)&DispatchDirectUserMsg }, + //{ 0x, "CL_ShutDownUsrMessages", (size_t)&CL_ShutDownUsrMessages }, + //{ 0x, "CL_ShutDownClientStatic", (size_t)&CL_ShutDownClientStatic }, + + //{ 0x, "ClientDLL_MoveClient", (size_t)&ClientDLL_MoveClient }, + + //{ 0x, "CL_Shutdown", (size_t)&CL_Shutdown }, + + //{ 0x, "ClientDLL_Frame", (size_t)&ClientDLL_Frame }, + //{ 0x, "ClientDLL_CAM_Think", (size_t)&ClientDLL_CAM_Think }, + //{ 0x, "CL_InitEventSystem", (size_t)&CL_InitEventSystem }, + //{ 0x, "CL_CheckClientState", (size_t)&CL_CheckClientState }, + //{ 0x, "CL_RedoPrediction", (size_t)&CL_RedoPrediction }, + //{ 0x, "CL_SetLastUpdate", (size_t)&CL_SetLastUpdate }, + + //{ 0x, "Con_NPrintf", (size_t)&Con_NPrintf }, + //{ 0x01D805A0, "Sequence_OnLevelLoad", (size_t)&Sequence_OnLevelLoad }, + //{ 0x01D1CDD0, "CL_WriteMessageHistory", (size_t)&CL_WriteMessageHistory }, + //{ 0x, "CL_MoveSpectatorCamera", (size_t)&CL_MoveSpectatorCamera }, + //{ 0x, "CL_AddVoiceToDatagram", (size_t)&CL_AddVoiceToDatagram }, + //{ 0x, "CL_VoiceIdle", (size_t)&CL_VoiceIdle }, + //{ 0x, "PollDInputDevices", (size_t)&PollDInputDevices }, + //{ 0x, "CL_KeepConnectionActive", (size_t)&CL_KeepConnectionActive }, + //{ 0x, "CL_UpdateModuleC", (size_t)&CL_UpdateModuleC }, + //{ 0x, "VGuiWrap2_IsInCareerMatch", (size_t)&VGuiWrap2_IsInCareerMatch }, + //{ 0x, "VguiWrap2_GetCareerUI", (size_t)&VguiWrap2_GetCareerUI }, + //{ 0x, "VGuiWrap2_GetLocalizedStringLength", (size_t)&VGuiWrap2_GetLocalizedStringLength }, + //{ 0x01D07630, "VGuiWrap2_LoadingStarted", (size_t)&VGuiWrap2_LoadingStarted }, + + //{ 0x, "ConstructTutorMessageDecayBuffer", (size_t)&ConstructTutorMessageDecayBuffer }, + //{ 0x, "ProcessTutorMessageDecayBuffer", (size_t)&ProcessTutorMessageDecayBuffer }, + //{ 0x, "GetTimesTutorMessageShown", (size_t)&GetTimesTutorMessageShown }, + //{ 0x, "RegisterTutorMessageShown", (size_t)&RegisterTutorMessageShown }, + //{ 0x, "ResetTutorMessageDecayData", (size_t)&ResetTutorMessageDecayData }, + //{ 0x01D83340, "SetCareerAudioState", (size_t)&SetCareerAudioState }, + +#endif // Cl_Null_region + +#ifndef Snd_Null_region + + //{ 0x0, "S_Init", (size_t)&S_Init }, + //{ 0x0, "S_AmbientOff", (size_t)&S_AmbientOff }, + //{ 0x0, "S_AmbientOn", (size_t)&S_AmbientOn }, + //{ 0x0, "S_Shutdown", (size_t)&S_Shutdown }, + //{ 0x0, "S_TouchSound", (size_t)&S_TouchSound }, + //{ 0x0, "S_ClearBuffer", (size_t)&S_ClearBuffer }, + //{ 0x0, "S_StartStaticSound", (size_t)&S_StartStaticSound }, + //{ 0x0, "S_StartDynamicSound", (size_t)&S_StartDynamicSound }, + //{ 0x0, "S_StopSound", (size_t)&S_StopSound }, + //{ 0x0, "S_PrecacheSound", (size_t)&S_PrecacheSound }, + //{ 0x0, "S_ClearPrecache", (size_t)&S_ClearPrecache }, + //{ 0x0, "S_Update", (size_t)&S_Update }, + //{ 0x0, "S_StopAllSounds", (size_t)&S_StopAllSounds }, + //{ 0x0, "S_BeginPrecaching", (size_t)&S_BeginPrecaching }, + //{ 0x0, "S_EndPrecaching", (size_t)&S_EndPrecaching }, + //{ 0x0, "S_ExtraUpdate", (size_t)&S_ExtraUpdate }, + //{ 0x0, "S_LocalSound", (size_t)&S_LocalSound }, + //{ 0x0, "S_BlockSound", (size_t)&S_BlockSound }, + //{ 0x0, "S_PrintStats", (size_t)&S_PrintStats }, + //{ 0x0, "Voice_RecordStart", (size_t)&Voice_RecordStart }, + //{ 0x0, "Voice_IsRecording", (size_t)&Voice_IsRecording }, + //{ 0x0, "Voice_RegisterCvars", (size_t)&Voice_RegisterCvars }, + //{ 0x01DB65D0, "Voice_Deinit", (size_t)&Voice_Deinit }, + //{ 0x0, "Voice_Idle", (size_t)&Voice_Idle }, + //{ 0x0, "Voice_RecordStop", (size_t)&Voice_RecordStop }, + +#endif // Snd_Null_region + +#ifndef Sv_Steam3_region + + { 0x01D994C0, "_ZN13CSteam3Server19NotifyClientConnectEP8client_sPKvj", (size_t)*(void **)&pNotifyClientConnect }, + { 0x01D98B20, "_ZN13CSteam3Server14OnLogonFailureEP27SteamServerConnectFailure_t", mfunc_ptr_cast(&CSteam3Server::OnLogonFailure) }, + { 0x01D99A10, "_ZN13CSteam3Server24SendUpdatedServerDetailsEv", mfunc_ptr_cast(&CSteam3Server::SendUpdatedServerDetails) }, + { 0x01D98A70, "_ZN13CSteam3Server14OnLogonSuccessEP23SteamServersConnected_t", mfunc_ptr_cast(&CSteam3Server::OnLogonSuccess) }, + { 0x01D98A40, "_ZN13CSteam3Server18OnGSPolicyResponseEP18GSPolicyResponse_t", mfunc_ptr_cast(&CSteam3Server::OnGSPolicyResponse) }, + { 0x01D98AE0, "_ZN13CSteam3Server10GetSteamIDEv", mfunc_ptr_cast(&CSteam3Server::GetSteamID) }, + { 0x01D98F10, "_ZN13CSteam3Server21ClientFindFromSteamIDER8CSteamID", mfunc_ptr_cast(&CSteam3Server::ClientFindFromSteamID) }, + { 0x01D98DF0, "_ZN13CSteam3Server17OnGSClientApproveEP17GSClientApprove_t", mfunc_ptr_cast(&CSteam3Server::OnGSClientApprove) }, + { 0x01D99660, "_ZN13CSteam3Server22NotifyClientDisconnectEP8client_s", mfunc_ptr_cast(&CSteam3Server::NotifyClientDisconnect) }, + { 0x01D98BC0, "_ZN13CSteam3Server20OnGSClientDenyHelperEP8client_s11EDenyReasonPKc", mfunc_ptr_cast(&CSteam3Server::OnGSClientDenyHelper) }, + { 0x01D98B90, "_ZN13CSteam3Server14OnGSClientDenyEP14GSClientDeny_t", mfunc_ptr_cast(&CSteam3Server::OnGSClientDeny) }, + { 0x01D98DC0, "_ZN13CSteam3Server14OnGSClientKickEP14GSClientKick_t", mfunc_ptr_cast(&CSteam3Server::OnGSClientKick) }, + { 0x01D996B0, "_ZN13CSteam3Server19NotifyOfLevelChangeEb", mfunc_ptr_cast(&CSteam3Server::NotifyOfLevelChange) }, + { 0x01D99110, "_ZN13CSteam3Server8ActivateEv", mfunc_ptr_cast(&CSteam3Server::Activate) }, + { 0x01D99770, "_ZN13CSteam3Server8RunFrameEv", mfunc_ptr_cast(&CSteam3Server::RunFrame) }, + { 0x01D99600, "_ZN13CSteam3Server16NotifyBotConnectEP8client_s", mfunc_ptr_cast(&CSteam3Server::NotifyBotConnect) }, + + { 0x01D99550, "ISteamGameServer_CreateUnauthenticatedUserConnection", (size_t)&ISteamGameServer_CreateUnauthenticatedUserConnection }, + { 0x01D99590, "ISteamGameServer_BUpdateUserData", (size_t)&ISteamGameServer_BUpdateUserData }, + { 0x01D995D0, "ISteamApps_BIsSubscribedApp", (size_t)&ISteamApps_BIsSubscribedApp }, + { 0x01D99AB0, "Steam_GetCommunityName", (size_t)&Steam_GetCommunityName }, + { 0x01D99CA0, "Steam_NotifyClientConnect", (size_t)&Steam_NotifyClientConnect }, + { 0x01D99CD0, "Steam_NotifyBotConnect", (size_t)&Steam_NotifyBotConnect }, + { 0x01D99D00, "Steam_NotifyClientDisconnect", (size_t)&Steam_NotifyClientDisconnect }, + { 0x01D99D20, "Steam_NotifyOfLevelChange", (size_t)&Steam_NotifyOfLevelChange }, + { 0x01D99D40, "Steam_Shutdown", (size_t)&Steam_Shutdown }, + { 0x01D99D70, "Steam_Activate", (size_t)&Steam_Activate }, + { 0x01D99DC0, "Steam_RunFrame", (size_t)&Steam_RunFrame }, + { 0x01D99DE0, "Steam_SetCVar", (size_t)&Steam_SetCVar }, + { 0x01D99E10, "Steam_ClientRunFrame", (size_t)&Steam_ClientRunFrame }, + { 0x01D99E20, "Steam_InitClient", (size_t)&Steam_InitClient }, + { 0x01D99E30, "Steam_GSInitiateGameConnection", (size_t)&Steam_GSInitiateGameConnection }, + { 0x01D99E70, "Steam_GSTerminateGameConnection", (size_t)&Steam_GSTerminateGameConnection }, + { 0x01D99E90, "Steam_ShutdownClient", (size_t)&Steam_ShutdownClient }, + { 0x01D99EA0, "Steam_GSGetSteamID", (size_t)&Steam_GSGetSteamID }, + { 0x01D99EB0, "Steam_GSBSecure", (size_t)&Steam_GSBSecure }, + { 0x01D99ED0, "Steam_GSBLoggedOn", (size_t)&Steam_GSBLoggedOn }, + { 0x01D99F00, "Steam_GSBSecurePreference", (size_t)&Steam_GSBSecurePreference }, + { 0x01D99F10, "Steam_Steam3IDtoSteam2", (size_t)&Steam_Steam3IDtoSteam2 }, + { 0x01D99F50, "Steam_StringToSteamID", (size_t)&Steam_StringToSteamID }, + { 0x01D99FD0, "Steam_GetGSUniverse", (size_t)&Steam_GetGSUniverse }, + { 0x01D9A020, "Steam3Server", (size_t)&Steam3Server }, + { 0x01D9A1D0, "Steam3Client", (size_t)&Steam3Client }, + { 0x01D9A1E0, "Master_SetMaster_f", (size_t)&Master_SetMaster_f }, + { 0x01D9A2D0, "Steam_HandleIncomingPacket", (size_t)&Steam_HandleIncomingPacket }, + +#endif // Sv_Steam3_region + +#ifndef Host_region + + { 0x01D43A00, "Host_EndGame", (size_t)&Host_EndGame }, + { 0x01D43AC0, "Host_Error", (size_t)&Host_Error }, + { 0x01D43BA0, "Host_InitLocal", (size_t)&Host_InitLocal }, + { 0x01D43C90, "Info_WriteVars", (size_t)&Info_WriteVars }, // NOXREF + { 0x01D43D70, "Host_WriteConfiguration", (size_t)&Host_WriteConfiguration }, // NOXREF + { 0x01D43FA0, "Host_WriteCustomConfig", (size_t)&Host_WriteCustomConfig }, + { 0x01D44190, "SV_ClientPrintf", (size_t)&SV_ClientPrintf }, + { 0x01D441F0, "SV_BroadcastPrintf", (size_t)&SV_BroadcastPrintf }, + { 0x01D442A0, "Host_ClientCommands", (size_t)&Host_ClientCommands }, + { 0x01D44310, "SV_DropClient", (size_t)&SV_DropClient }, + { 0x01D44510, "Host_ClearClients", (size_t)&Host_ClearClients }, + { 0x01D446B0, "Host_ShutdownServer", (size_t)&Host_ShutdownServer }, + { 0x01D447F0, "SV_ClearClientStates", (size_t)&SV_ClearClientStates }, + { 0x01D44830, "Host_CheckDyanmicStructures", (size_t)&Host_CheckDyanmicStructures }, + { 0x01D44880, "Host_ClearMemory", (size_t)&Host_ClearMemory }, + { 0x01D44900, "Host_FilterTime", (size_t)&Host_FilterTime }, + { 0x01D44B50, "Master_IsLanGame", (size_t)&Master_IsLanGame }, + { 0x01D44B70, "Master_Heartbeat_f", (size_t)&Master_Heartbeat_f }, + { 0x01D44B80, "Host_ComputeFPS", (size_t)&Host_ComputeFPS }, + { 0x01D44BB0, "Host_GetHostInfo", (size_t)&Host_GetHostInfo }, + { 0x01D44C80, "Host_Speeds", (size_t)&Host_Speeds }, + { 0x01D44DC0, "Host_UpdateScreen", (size_t)&Host_UpdateScreen }, + { 0x01D44EB0, "Host_UpdateSounds", (size_t)&Host_UpdateSounds }, + { 0x01D44F30, "Host_CheckConnectionFailure", (size_t)&Host_CheckConnectionFailure }, + { 0x01D44F90, "_Host_Frame", (size_t)&_Host_Frame }, + { 0x01D45150, "Host_Frame", (size_t)&Host_Frame }, + { 0x01D45290, "CheckGore", (size_t)&CheckGore }, + { 0x01D45450, "Host_IsSinglePlayerGame", (size_t)&Host_IsSinglePlayerGame }, + { 0x01D45470, "Host_IsServerActive", (size_t)&Host_IsServerActive }, + { 0x01D45480, "Host_Version", (size_t)&Host_Version }, + { 0x01D456A0, "Host_Init", (size_t)&Host_Init }, + { 0x01D459A0, "Host_Shutdown", (size_t)&Host_Shutdown }, + +#endif // Host_region + +#ifndef Host_Cmd_region + + { 0x01D45AF0, "SV_GetPlayerHulls", (size_t)&SV_GetPlayerHulls }, + { 0x01D45B20, "Host_InitializeGameDLL", (size_t)&Host_InitializeGameDLL }, + { 0x01D45BA0, "Host_Motd_f", (size_t)&Host_Motd_f }, + { 0x01D45D00, "Host_Motd_Write_f", (size_t)&Host_Motd_Write_f }, + { 0x01D45E70, "Host_GetStartTime", (size_t)&Host_GetStartTime }, + { 0x01D45E80, "Host_UpdateStats", (size_t)&Host_UpdateStats }, // UNTESTED Linux + { 0x01D45FB0, "GetStatsString", (size_t)&GetStatsString }, + { 0x01D460B0, "Host_Stats_f", (size_t)&Host_Stats_f }, + { 0x01D460F0, "Host_Quit_f", (size_t)&Host_Quit_f }, + { 0x01D46140, "Host_Quit_Restart_f", (size_t)&Host_Quit_Restart_f }, + { 0x01D46250, "Host_Status_Printf", (size_t)&Host_Status_Printf }, + { 0x01D462F0, "Host_Status_f", (size_t)&Host_Status_f }, + { 0x01D467B0, "Host_Status_Formatted_f", (size_t)&Host_Status_Formatted_f }, + { 0x01D46EC0, "Host_Ping_f", (size_t)&Host_Ping_f }, + { 0x01D46F30, "Host_Map", (size_t)&Host_Map }, + { 0x01D470D0, "Host_Map_f", (size_t)&Host_Map_f }, + { 0x01D473B0, "Host_Career_f", (size_t)&Host_Career_f }, + { 0x01D473D0, "Host_Maps_f", (size_t)&Host_Maps_f }, + { 0x01D47410, "Host_Changelevel_f", (size_t)&Host_Changelevel_f }, + { 0x01D47510, "Host_FindRecentSave", (size_t)&Host_FindRecentSave }, + { 0x01D47600, "Host_Restart_f", (size_t)&Host_Restart_f }, + { 0x01D47690, "Host_Reload_f", (size_t)&Host_Reload_f }, + { 0x01D47710, "Host_Reconnect_f", (size_t)&Host_Reconnect_f }, + { 0x01D477E0, "Host_SaveGameDirectory", (size_t)&Host_SaveGameDirectory }, + { 0x01D47810, "Host_SavegameComment", (size_t)&Host_SavegameComment }, + { 0x01D478B0, "Host_SaveAgeList", (size_t)&Host_SaveAgeList }, + { 0x01D479B0, "Host_ValidSave", (size_t)&Host_ValidSave }, + { 0x01D47A70, "SaveInit", (size_t)&SaveInit }, + { 0x01D47B80, "SaveExit", (size_t)&SaveExit }, + { 0x01D47BC0, "SaveGameSlot", (size_t)&SaveGameSlot }, + { 0x01D47E70, "Host_Savegame_f", (size_t)&Host_Savegame_f }, + { 0x01D47F60, "Host_AutoSave_f", (size_t)&Host_AutoSave_f }, + { 0x01D47FF0, "SaveGame", (size_t)&SaveGame }, + { 0x01D48020, "SaveReadHeader", (size_t)&SaveReadHeader }, + { 0x01D481A0, "SaveReadComment", (size_t)&SaveReadComment }, // NOXREF + { 0x01D481D0, "Host_Loadgame_f", (size_t)&Host_Loadgame_f }, + { 0x01D48220, "LoadGame", (size_t)&LoadGame }, + { 0x01D48250, "Host_Load", (size_t)&Host_Load }, + { 0x01D484C0, "SaveGamestate", (size_t)&SaveGamestate }, + { 0x01D48A00, "EntityInit", (size_t)&EntityInit }, + { 0x01D48A50, "LoadSaveData", (size_t)&LoadSaveData }, + { 0x01D48C70, "ParseSaveTables", (size_t)&ParseSaveTables }, + { 0x01D48DC0, "EntityPatchWrite", (size_t)&EntityPatchWrite }, + { 0x01D48EB0, "EntityPatchRead", (size_t)&EntityPatchRead }, + { 0x01D48F60, "LoadGamestate", (size_t)&LoadGamestate }, + { 0x01D491D0, "EntryInTable", (size_t)&EntryInTable }, + { 0x01D49220, "LandmarkOrigin", (size_t)&LandmarkOrigin }, + { 0x01D49290, "EntityInSolid", (size_t)&EntityInSolid }, + { 0x01D49320, "CreateEntityList", (size_t)&CreateEntityList }, + { 0x01D49570, "LoadAdjacentEntities", (size_t)&LoadAdjacentEntities }, + { 0x01D49730, "FileSize", (size_t)&FileSize }, + { 0x01D49750, "FileCopy", (size_t)&FileCopy }, + { 0x01D497B0, "DirectoryCopy", (size_t)&DirectoryCopy }, + { 0x01D49880, "DirectoryExtract", (size_t)&DirectoryExtract }, + { 0x01D49930, "DirectoryCount", (size_t)&DirectoryCount }, + { 0x01D49970, "Host_ClearSaveDirectory", (size_t)&Host_ClearSaveDirectory }, + { 0x01D49AB0, "Host_ClearGameState", (size_t)&Host_ClearGameState }, + { 0x01D49AD0, "Host_Changelevel2_f", (size_t)&Host_Changelevel2_f }, + { 0x01D49CB0, "Host_Version_f", (size_t)&Host_Version_f }, + { 0x01D49CE0, "Host_FullInfo_f", (size_t)&Host_FullInfo_f }, + { 0x01D49E00, "Host_KillVoice_f", (size_t)&Host_KillVoice_f }, // NOXREF + { 0x01D49E10, "Host_SetInfo_f", (size_t)&Host_SetInfo_f }, + { 0x01D49EB0, "Host_Say", (size_t)&Host_Say }, + { 0x01D4A060, "Host_Say_f", (size_t)&Host_Say_f }, + { 0x01D4A070, "Host_Say_Team_f", (size_t)&Host_Say_Team_f }, + { 0x01D4A080, "Host_Tell_f", (size_t)&Host_Tell_f }, + { 0x01D4A230, "Host_Kill_f", (size_t)&Host_Kill_f }, + { 0x01D4A280, "Host_TogglePause_f", (size_t)&Host_TogglePause_f }, + { 0x01D4A320, "Host_Pause_f", (size_t)&Host_Pause_f }, + { 0x01D4A380, "Host_Unpause_f", (size_t)&Host_Unpause_f }, + { 0x01D4A620, "Host_Interp_f", (size_t)&Host_Interp_f }, + { 0x01D4A650, "Host_NextDemo", (size_t)&Host_NextDemo }, + { 0x01D4A700, "Host_Startdemos_f", (size_t)&Host_Startdemos_f }, + { 0x01D4A7C0, "Host_Demos_f", (size_t)&Host_Demos_f }, + { 0x01D4A7F0, "Host_Stopdemo_f", (size_t)&Host_Stopdemo_f }, + { 0x01D4A810, "Host_EndSection", (size_t)&Host_EndSection }, // NOXREF + { 0x01D4A910, "Host_Soundfade_f", (size_t)&Host_Soundfade_f }, + { 0x01D4AA10, "Host_KillServer_f", (size_t)&Host_KillServer_f }, + { 0x01D4AA50, "Host_VoiceRecordStart_f", (size_t)&Host_VoiceRecordStart_f }, + { 0x01D4AAA0, "Host_VoiceRecordStop_f", (size_t)&Host_VoiceRecordStop_f }, + { 0x01D4AC90, "Host_Crash_f", (size_t)&Host_Crash_f }, // NOXREF + { 0x01D4ACA0, "Host_InitCommands", (size_t)&Host_InitCommands }, + { 0x01D4B060, "SV_CheckBlendingInterface", (size_t)&SV_CheckBlendingInterface }, + { 0x01D4B0D0, "SV_CheckSaveGameCommentInterface", (size_t)&SV_CheckSaveGameCommentInterface }, + +#endif // Host_Cmd_region + +#ifndef Pmove_region + + { 0x01D5B490, "PM_AddToTouched", (size_t)&PM_AddToTouched }, + { 0x01D5B530, "PM_StuckTouch", (size_t)&PM_StuckTouch }, + { 0x01D5B590, "PM_Init", (size_t)&PM_Init }, + +#endif // Pmove_region + +#ifndef Pmovetst_region + + { 0x01D5B8F0, "PM_TraceModel", (size_t)&PM_TraceModel }, + { 0x01D5B990, "PM_GetModelBounds", (size_t)&PM_GetModelBounds }, + { 0x01D5B9C0, "PM_GetModelType", (size_t)&PM_GetModelType }, + { 0x01D5B9D0, "PM_InitBoxHull", (size_t)&PM_InitBoxHull }, + { 0x01D5BA60, "PM_HullForBox", (size_t)&PM_HullForBox }, + { 0x01D5BAB0, "PM_HullPointContents", (size_t)&PM_HullPointContents }, + { 0x01D5BB50, "PM_LinkContents", (size_t)&PM_LinkContents }, + { 0x01D5BC10, "PM_PointContents", (size_t)&PM_PointContents }, + { 0x01D5BCA0, "PM_WaterEntity", (size_t)&PM_WaterEntity }, + { 0x01D5BD10, "PM_TruePointContents", (size_t)&PM_TruePointContents }, + { 0x01D5BD40, "PM_HullForStudioModel", (size_t)&PM_HullForStudioModel }, + { 0x01D5BDF0, "PM_HullForBsp", (size_t)&PM_HullForBsp }, + { 0x01D5BEA0, "_PM_TestPlayerPosition", (size_t)&_PM_TestPlayerPosition }, + { 0x01D5C190, "PM_TestPlayerPosition", (size_t)&PM_TestPlayerPosition }, + { 0x01D5C1B0, "PM_TestPlayerPositionEx", (size_t)&PM_TestPlayerPositionEx }, + { 0x01D5C1D0, "_PM_PlayerTrace", (size_t)&_PM_PlayerTrace }, + { 0x01D5C890, "PM_PlayerTrace", (size_t)&PM_PlayerTrace }, + { 0x01D5C8F0, "PM_PlayerTraceEx", (size_t)&PM_PlayerTraceEx }, + { 0x01D5C9C8, "PM_TraceLine", (size_t)&PM_TraceLine }, + { 0x01D5CA60, "PM_TraceLineEx", (size_t)&PM_TraceLineEx }, + { 0x01D5CB20, "PM_RecursiveHullCheck", (size_t)&PM_RecursiveHullCheck }, + +#endif // Pmovetst_region + +#ifndef Pr_Edict_region + + { 0x01D61510, "ED_ClearEdict", (size_t)&ED_ClearEdict }, + { 0x01D61550, "ED_Alloc", (size_t)&ED_Alloc }, + { 0x01D61610, "ED_Free", (size_t)&ED_Free }, + { 0x01D616D0, "ED_Count", (size_t)&ED_Count }, // NOXREF + { 0x01D61770, "ED_NewString", (size_t)&ED_NewString }, + { 0x01D617D0, "ED_ParseEdict", (size_t)&ED_ParseEdict }, + { 0x01D61A70, "ED_LoadFromFile", (size_t)&ED_LoadFromFile }, + { 0x01D61B80, "PR_Init", (size_t)&PR_Init }, // NOXREF + { 0x01D61B90, "EDICT_NUM", (size_t)&EDICT_NUM }, + { 0x01D61BD0, "NUM_FOR_EDICT", (size_t)&NUM_FOR_EDICT }, + { 0x01D61C10, "SuckOutClassname", (size_t)&SuckOutClassname }, + { 0x01D61CD0, "ReleaseEntityDLLFields", (size_t)&ReleaseEntityDLLFields }, + { 0x01D61CF0, "InitEntityDLLFields", (size_t)&InitEntityDLLFields }, + { 0x01D61D00, "PvAllocEntPrivateData", (size_t)&PvAllocEntPrivateData }, + { 0x01D61D30, "PvEntPrivateData", (size_t)&PvEntPrivateData }, + { 0x01D61D50, "FreeEntPrivateData", (size_t)&FreeEntPrivateData }, + { 0x01D61D90, "FreeAllEntPrivateData", (size_t)&FreeAllEntPrivateData }, + { 0x01D61DD0, "PEntityOfEntOffset", (size_t)&PEntityOfEntOffset }, + { 0x01D61DE0, "EntOffsetOfPEntity", (size_t)&EntOffsetOfPEntity }, + { 0x01D61DF0, "IndexOfEdict", (size_t)&IndexOfEdict }, + { 0x01D61E40, "PEntityOfEntIndex", (size_t)&PEntityOfEntIndex }, + { 0x01D61E80, "SzFromIndex", (size_t)&SzFromIndex }, + { 0x01D61E90, "GetVarsOfEnt", (size_t)&GetVarsOfEnt }, + { 0x01D61EA0, "FindEntityByVars", (size_t)&FindEntityByVars }, + { 0x01D61EE0, "CVarGetFloat", (size_t)&CVarGetFloat }, + { 0x01D61F00, "CVarGetString", (size_t)&CVarGetString }, + { 0x01D61F20, "CVarGetPointer", (size_t)&CVarGetPointer }, + { 0x01D61F40, "CVarSetFloat", (size_t)&CVarSetFloat }, + { 0x01D61F60, "CVarSetString", (size_t)&CVarSetString }, + { 0x01D61F80, "CVarRegister", (size_t)&CVarRegister }, + { 0x01D61FA0, "AllocEngineString", (size_t)&AllocEngineString }, + { 0x01D61FC0, "SaveSpawnParms", (size_t)&SaveSpawnParms }, + { 0x01D61FF0, "GetModelPtr", (size_t)&GetModelPtr }, + +#endif // Pr_Edict_region + +#ifndef Pr_Cmds_region + + { 0x01D5CF00, "PF_makevectors_I", (size_t)&PF_makevectors_I }, + { 0x01D5CF20, "PF_Time", (size_t)&PF_Time }, + { 0x01D5CF40, "PF_setorigin_I", (size_t)&PF_setorigin_I }, + { 0x01D5CF80, "SetMinMaxSize", (size_t)&SetMinMaxSize }, + { 0x01D5D030, "PF_setsize_I", (size_t)&PF_setsize_I }, + { 0x01D5D050, "PF_setmodel_I", (size_t)&PF_setmodel_I }, + { 0x01D5D0F0, "PF_modelindex", (size_t)&PF_modelindex }, + { 0x01D5D110, "ModelFrames", (size_t)&ModelFrames }, + { 0x01D5D150, "PF_bprint", (size_t)&PF_bprint }, + { 0x01D5D170, "PF_sprint", (size_t)&PF_sprint }, + { 0x01D5D1D0, "ServerPrint", (size_t)&ServerPrint }, + { 0x01D5D1F0, "ClientPrintf", (size_t)&ClientPrintf }, + { 0x01D5D2A0, "PF_vectoyaw_I", (size_t)&PF_vectoyaw_I }, + { 0x01D5D330, "PF_vectoangles_I", (size_t)&PF_vectoangles_I }, + { 0x01D5D350, "PF_particle_I", (size_t)&PF_particle_I }, + { 0x01D5D380, "PF_ambientsound_I", (size_t)&PF_ambientsound_I }, + { 0x01D5D4C0, "PF_sound_I", (size_t)&PF_sound_I }, + { 0x01D5D5A0, "PF_traceline_Shared", (size_t)&PF_traceline_Shared }, + { 0x01D5D600, "PF_traceline_DLL", (size_t)&PF_traceline_DLL }, + { 0x01D5D6C0, "TraceHull", (size_t)&TraceHull }, + { 0x01D5D770, "TraceSphere", (size_t)&TraceSphere }, + { 0x01D5D780, "TraceModel", (size_t)&TraceModel }, + { 0x01D5D890, "SurfaceAtPoint", (size_t)&SurfaceAtPoint }, + { 0x01D5DA90, "TraceTexture", (size_t)&TraceTexture }, + { 0x01D5DCA0, "PF_TraceToss_Shared", (size_t)&PF_TraceToss_Shared }, + { 0x01D5DCE0, "SV_SetGlobalTrace", (size_t)&SV_SetGlobalTrace }, + { 0x01D5DD80, "PF_TraceToss_DLL", (size_t)&PF_TraceToss_DLL }, + { 0x01D5DE40, "TraceMonsterHull", (size_t)&TraceMonsterHull }, + { 0x01D5DF10, "PF_newcheckclient", (size_t)&PF_newcheckclient }, + { 0x01D5DFF0, "PF_checkclient_I", (size_t)&PF_checkclient_I }, + { 0x01D5E110, "PVSNode", (size_t)&PVSNode }, + { 0x01D5E1D0, "PVSMark", (size_t)&PVSMark }, + { 0x01D5E250, "PVSFindEntities", (size_t)&PVSFindEntities }, + { 0x01D5E360, "ValidCmd", (size_t)&ValidCmd }, + { 0x01D5E390, "PF_stuffcmd_I", (size_t)&PF_stuffcmd_I }, + { 0x01D5E450, "PF_localcmd_I", (size_t)&PF_localcmd_I }, + { 0x01D5E480, "PF_localexec_I", (size_t)&PF_localexec_I }, + { 0x01D5E490, "FindEntityInSphere", (size_t)&FindEntityInSphere }, + { 0x01D5E5C0, "PF_Spawn_I", (size_t)&PF_Spawn_I }, + { 0x01D5E5D0, "CreateNamedEntity", (size_t)&CreateNamedEntity }, + { 0x01D5E640, "PF_Remove_I", (size_t)&PF_Remove_I }, + { 0x01D5E920, "PF_find_Shared", (size_t)&PF_find_Shared }, + { 0x01D5E660, "iGetIndex", (size_t)&iGetIndex }, + { 0x01D5E8C0, "FindEntityByString", (size_t)&FindEntityByString }, + { 0x01D5E9B0, "GetEntityIllum", (size_t)&GetEntityIllum }, + { 0x01D5EA50, "PR_IsEmptyString", (size_t)&PR_IsEmptyString }, + { 0x01D5EA60, "PF_precache_sound_I", (size_t)&PF_precache_sound_I }, + { 0x01D5EB50, "EV_Precache", (size_t)&EV_Precache }, + { 0x01D5ECD0, "EV_PlayReliableEvent", (size_t)&EV_PlayReliableEvent }, + { 0x01D5EE10, "EV_Playback", (size_t)&EV_Playback }, + { 0x01D5F190, "EV_SV_Playback", (size_t)&EV_SV_Playback }, + { 0x01D5F210, "PF_precache_model_I", (size_t)&PF_precache_model_I }, + { 0x01D5F310, "PF_precache_generic_I", (size_t)&PF_precache_generic_I }, + { 0x01D5F3E0, "PF_IsMapValid_I", (size_t)&PF_IsMapValid_I }, + { 0x01D5F430, "PF_NumberOfEntities_I", (size_t)&PF_NumberOfEntities_I }, + { 0x01D5F460, "PF_GetInfoKeyBuffer_I", (size_t)&PF_GetInfoKeyBuffer_I }, + { 0x01D5F4B0, "PF_InfoKeyValue_I", (size_t)&PF_InfoKeyValue_I }, + { 0x01D5F4D0, "PF_SetKeyValue_I", (size_t)&PF_SetKeyValue_I }, + { 0x01D5F530, "PF_RemoveKey_I", (size_t)&PF_RemoveKey_I }, + { 0x01D5F550, "PF_SetClientKeyValue_I", (size_t)&PF_SetClientKeyValue_I }, + { 0x01D5F5E0, "PF_walkmove_I", (size_t)&PF_walkmove_I }, + { 0x01D5F690, "PF_droptofloor_I", (size_t)&PF_droptofloor_I }, + { 0x01D5F780, "PF_DecalIndex", (size_t)&PF_DecalIndex }, + { 0x01D5F7D0, "PF_lightstyle_I", (size_t)&PF_lightstyle_I }, + { 0x01D5F860, "PF_checkbottom_I", (size_t)&PF_checkbottom_I }, + { 0x01D5F880, "PF_pointcontents_I", (size_t)&PF_pointcontents_I }, + { 0x01D5F8A0, "PF_aim_I", (size_t)&PF_aim_I }, + { 0x01D5FB60, "PF_changeyaw_I", (size_t)&PF_changeyaw_I }, + { 0x01D5FC50, "PF_changepitch_I", (size_t)&PF_changepitch_I }, + { 0x01D5FD40, "PF_setview_I", (size_t)&PF_setview_I }, + { 0x01D5FDC0, "PF_crosshairangle_I", (size_t)&PF_crosshairangle_I }, + { 0x01D5FEC0, "PF_CreateFakeClient_I", (size_t)&PF_CreateFakeClient_I }, + { 0x01D60070, "PF_RunPlayerMove_I", (size_t)&PF_RunPlayerMove_I }, + { 0x01D60180, "WriteDest_Parm", (size_t)&WriteDest_Parm }, + { 0x01D60260, "PF_MessageBegin_I", (size_t)&PF_MessageBegin_I }, + { 0x01D60350, "PF_MessageEnd_I", (size_t)&PF_MessageEnd_I }, + { 0x01D605E0, "PF_WriteByte_I", (size_t)&PF_WriteByte_I }, + { 0x01D60610, "PF_WriteChar_I", (size_t)&PF_WriteChar_I }, + { 0x01D60640, "PF_WriteShort_I", (size_t)&PF_WriteShort_I }, + { 0x01D60670, "PF_WriteLong_I", (size_t)&PF_WriteLong_I }, + { 0x01D606A0, "PF_WriteAngle_I", (size_t)&PF_WriteAngle_I }, + { 0x01D606D0, "PF_WriteCoord_I", (size_t)&PF_WriteCoord_I }, + { 0x01D60710, "PF_WriteString_I", (size_t)&PF_WriteString_I }, + { 0x01D60740, "PF_WriteEntity_I", (size_t)&PF_WriteEntity_I }, + { 0x01D60770, "PF_makestatic_I", (size_t)&PF_makestatic_I }, + { 0x01D608C0, "PF_StaticDecal", (size_t)&PF_StaticDecal }, + { 0x01D60940, "PF_setspawnparms_I", (size_t)&PF_setspawnparms_I }, + { 0x01D60970, "PF_changelevel_I", (size_t)&PF_changelevel_I }, + { 0x01D609D0, "SeedRandomNumberGenerator", (size_t)&SeedRandomNumberGenerator }, + { 0x01D60A10, "ran1", (size_t)&ran1 }, + { 0x01D60AE0, "fran1", (size_t)&fran1 }, + { 0x01D60B30, "RandomFloat", (size_t)&RandomFloat }, + { 0x01D60B60, "RandomLong", (size_t)&RandomLong }, + { 0x01D60BC0, "PF_FadeVolume", (size_t)&PF_FadeVolume }, + { 0x01D60C60, "PF_SetClientMaxspeed", (size_t)&PF_SetClientMaxspeed }, + { 0x01D60CA0, "PF_GetPlayerUserId", (size_t)&PF_GetPlayerUserId }, + { 0x01D60CF0, "PF_GetPlayerWONId", (size_t)&PF_GetPlayerWONId }, + { 0x01D60D00, "PF_GetPlayerAuthId", (size_t)&PF_GetPlayerAuthId }, + { 0x01D60E00, "PF_BuildSoundMsg_I", (size_t)&PF_BuildSoundMsg_I }, + { 0x01D60E50, "PF_IsDedicatedServer", (size_t)&PF_IsDedicatedServer }, + { 0x01D60E60, "PF_GetPhysicsInfoString", (size_t)&PF_GetPhysicsInfoString }, + { 0x01D60EB0, "PF_GetPhysicsKeyValue", (size_t)&PF_GetPhysicsKeyValue }, + { 0x01D60F10, "PF_SetPhysicsKeyValue", (size_t)&PF_SetPhysicsKeyValue }, + { 0x01D60F70, "PF_GetCurrentPlayer", (size_t)&PF_GetCurrentPlayer }, + { 0x01D60FB0, "PF_CanSkipPlayer", (size_t)&PF_CanSkipPlayer }, + { 0x01D61000, "PF_SetGroupMask", (size_t)&PF_SetGroupMask }, + { 0x01D61020, "PF_CreateInstancedBaseline", (size_t)&PF_CreateInstancedBaseline }, + { 0x01D61070, "PF_Cvar_DirectSet", (size_t)&PF_Cvar_DirectSet }, + { 0x01D61090, "PF_ForceUnmodified", (size_t)&PF_ForceUnmodified }, + { 0x01D611B0, "PF_GetPlayerStats", (size_t)&PF_GetPlayerStats }, + //{ 0x01D61230, "QueryClientCvarValueCmd", (size_t)&QueryClientCvarValueCmd }, //NOXREF + //{ 0x01D612D0, "QueryClientCvarValueCmd2", (size_t)&QueryClientCvarValueCmd2 }, //NOXREF + { 0x01D61390, "QueryClientCvarValue", (size_t)&QueryClientCvarValue }, + { 0x01D61410, "QueryClientCvarValue2", (size_t)&QueryClientCvarValue2 }, + { 0x01D614A0, "hudCheckParm", (size_t)&hudCheckParm }, + { 0x01D614F0, "EngCheckParm", (size_t)&EngCheckParm }, + +#endif // Pr_Cmds_region + +#ifndef Mathlib_region + + { 0x01D4F570, "anglemod", (size_t)&anglemod }, + //{ 0x, "BOPS_Error", (size_t)&BOPS_Error }, + { 0x01DBEE44, "BoxOnPlaneSide", (size_t)&BoxOnPlaneSide }, + //{ 0x, "InvertMatrix", (size_t)&InvertMatrix }, + { 0x01D4FD10, "AngleVectors", (size_t)&AngleVectors }, + { 0x01D4FE70, "AngleVectorsTranspose", (size_t)&AngleVectorsTranspose }, + { 0x01D4FF90, "AngleMatrix", (size_t)&AngleMatrix }, + //{ 0x, "AngleIMatrix", (size_t)&AngleIMatrix }, + //{ 0x, "NormalizeAngles", (size_t)&NormalizeAngles }, + //{ 0x, "InterpolateAngles", (size_t)&InterpolateAngles }, + { 0x01D502C0, "VectorTransform", (size_t)&VectorTransform }, + { 0x01D50320, "VectorCompare", (size_t)&VectorCompare }, + { 0x01D50350, "VectorMA", (size_t)&VectorMA }, + //{ 0x, "_DotProduct", (size_t)&_DotProduct }, + //{ 0x, "_VectorSubtract", (size_t)&_VectorSubtract }, + //{ 0x, "_VectorAdd", (size_t)&_VectorAdd }, + //{ 0x, "_VectorCopy", (size_t)&_VectorCopy }, + { 0x01D50420, "CrossProduct", (size_t)&CrossProduct }, + { 0x01D50460, "Length", (size_t)&Length }, + { 0x01D504A0, "VectorNormalize", (size_t)&VectorNormalize }, + //{ 0x, "VectorInverse", (size_t)&VectorInverse }, + { 0x01D50550, "VectorScale", (size_t)&VectorScale }, + //{ 0x, "Q_log2", (size_t)&Q_log2 }, + //{ 0x, "VectorMatrix", (size_t)&VectorMatrix }, + { 0x01D50640, "VectorAngles", (size_t)&VectorAngles }, + //{ 0x, "R_ConcatRotations", (size_t)&R_ConcatRotations }, + { 0x01D50850, "R_ConcatTransforms", (size_t)&R_ConcatTransforms }, + //{ 0x, "FloorDivMod", (size_t)&FloorDivMod }, + //{ 0x, "GreatestCommonDivisor", (size_t)&GreatestCommonDivisor }, + //{ 0x, "Invert24To16", (size_t)&Invert24To16 }, + +#endif // Mathlib_region + +#ifndef World_region + + { 0x01DB9050, "ClearLink", (size_t)&ClearLink }, + { 0x01DB9060, "RemoveLink", (size_t)&RemoveLink }, + { 0x01DB9080, "InsertLinkBefore", (size_t)&InsertLinkBefore }, + //{ 0x01DB90A0, "InsertLinkAfter", (size_t)&InsertLinkAfter }, //NOXREF + { 0x01DB90C0, "SV_InitBoxHull", (size_t)&SV_InitBoxHull }, + { 0x01DB9180, "SV_HullForBox", (size_t)&SV_HullForBox }, + //{ 0x01DB91D0, "SV_HullForBeam", (size_t)&SV_HullForBeam }, //NOXREF + { 0x01DB9640, "SV_HullForBsp", (size_t)&SV_HullForBsp }, + { 0x01DB9780, "SV_HullForEntity", (size_t)&SV_HullForEntity }, + { 0x01DB9850, "SV_CreateAreaNode", (size_t)&SV_CreateAreaNode }, + { 0x01DB9970, "SV_ClearWorld", (size_t)&SV_ClearWorld }, + { 0x01DB99B0, "SV_UnlinkEdict", (size_t)&SV_UnlinkEdict }, + { 0x01DB99E0, "SV_TouchLinks", (size_t)&SV_TouchLinks }, + { 0x01DB9BC0, "SV_FindTouchedLeafs", (size_t)&SV_FindTouchedLeafs }, + { 0x01DB9CF0, "SV_LinkEdict", (size_t)&SV_LinkEdict }, + { 0x01DC0614, "SV_HullPointContents", (size_t)&SV_HullPointContents }, + { 0x01DB9EB0, "SV_LinkContents", (size_t)&SV_LinkContents }, + { 0x01DBA0A0, "SV_PointContents", (size_t)&SV_PointContents }, + { 0x01DBA0F0, "SV_TestEntityPosition", (size_t)&SV_TestEntityPosition }, + { 0x01DBA160, "SV_RecursiveHullCheck", (size_t)&SV_RecursiveHullCheck }, + { 0x01DBA550, "SV_SingleClipMoveToEntity", (size_t)&SV_SingleClipMoveToEntity }, + { 0x01DBA950, "SV_ClipMoveToEntity", (size_t)&SV_ClipMoveToEntity }, + { 0x01DBA990, "SV_ClipToLinks", (size_t)&SV_ClipToLinks }, + { 0x01DBAC60, "SV_ClipToWorldbrush", (size_t)&SV_ClipToWorldbrush }, + { 0x01DBAE00, "SV_MoveBounds", (size_t)&SV_MoveBounds }, + { 0x01DBAE80, "SV_MoveNoEnts", (size_t)&SV_MoveNoEnts }, + { 0x01DBAFC0, "SV_Move", (size_t)&SV_Move }, + +#endif // World_region + +#ifndef Sv_Phys_region + + //{ 0x01D94A90, "SV_CheckAllEnts", (size_t)&SV_CheckAllEnts }, //NOXREF + { 0x01D94B00, "SV_CheckVelocity", (size_t)&SV_CheckVelocity }, + { 0x01D94C00, "SV_RunThink", (size_t)&SV_RunThink }, + { 0x01D94CB0, "SV_Impact", (size_t)&SV_Impact }, + { 0x01D94D50, "ClipVelocity", (size_t)&ClipVelocity }, + { 0x01D94E10, "SV_FlyMove", (size_t)&SV_FlyMove }, + { 0x01D952F0, "SV_AddGravity", (size_t)&SV_AddGravity }, + //{ 0x01D95370, "SV_AddCorrectGravity", (size_t)&SV_AddCorrectGravity }, //NOXREF + //{ 0x01D953F0, "SV_FixupGravityVelocity", (size_t)&SV_FixupGravityVelocity }, //NOXREF + { 0x01D95450, "SV_PushEntity", (size_t)&SV_PushEntity }, + { 0x01D95550, "SV_PushMove", (size_t)&SV_PushMove }, + { 0x01D958F0, "SV_PushRotate", (size_t)&SV_PushRotate }, + { 0x01D95F00, "SV_Physics_Pusher", (size_t)&SV_Physics_Pusher }, + { 0x01D960F0, "SV_CheckWater", (size_t)&SV_CheckWater }, + { 0x01D96290, "SV_RecursiveWaterLevel", (size_t)&SV_RecursiveWaterLevel }, + { 0x01D96310, "SV_Submerged", (size_t)&SV_Submerged }, + { 0x01D96410, "SV_Physics_None", (size_t)&SV_Physics_None }, + { 0x01D96430, "SV_Physics_Follow", (size_t)&SV_Physics_Follow }, + { 0x01D964F0, "SV_Physics_Noclip", (size_t)&SV_Physics_Noclip }, + { 0x01D96560, "SV_CheckWaterTransition", (size_t)&SV_CheckWaterTransition }, + { 0x01D96740, "SV_Physics_Toss", (size_t)&SV_Physics_Toss }, + { 0x01D96B20, "PF_WaterMove", (size_t)&PF_WaterMove }, + { 0x01D96E70, "SV_Physics_Step", (size_t)&SV_Physics_Step }, + { 0x01D97240, "SV_Physics", (size_t)&SV_Physics }, + { 0x01D97480, "SV_Trace_Toss", (size_t)&SV_Trace_Toss }, + +#endif // Sv_Phys_region + +#ifndef Sv_Move_region + + { 0x01D93A40, "SV_CheckBottom", (size_t)&SV_CheckBottom }, + { 0x01D93CB0, "SV_movetest", (size_t)&SV_movetest }, + { 0x01D93ED0, "SV_movestep", (size_t)&SV_movestep }, + { 0x01D94250, "SV_StepDirection", (size_t)&SV_StepDirection }, + { 0x01D942D0, "SV_FlyDirection", (size_t)&SV_FlyDirection }, + { 0x01D94310, "SV_FixCheckBottom", (size_t)&SV_FixCheckBottom }, + //{ 0x01D94330, "SV_NewChaseDir", (size_t)&SV_NewChaseDir }, //NOXREF + //{ 0x01D94620, "SV_CloseEnough", (size_t)&SV_CloseEnough }, //NOXREF + //{ 0x01D94680, "SV_ReachedGoal", (size_t)&SV_ReachedGoal }, //NOXREF + { 0x01D946D0, "SV_NewChaseDir2", (size_t)&SV_NewChaseDir2 }, + { 0x01D949C0, "SV_MoveToOrigin_I", (size_t)&SV_MoveToOrigin_I }, + +#endif // Sv_Move_region + +#ifndef Sv_pmove_region + + { 0x01D975F0, "PM_SV_PlaybackEventFull", (size_t)&PM_SV_PlaybackEventFull }, + { 0x01D97630, "PM_SV_PlaySound", (size_t)&PM_SV_PlaySound }, + { 0x01D97670, "PM_SV_TraceTexture", (size_t)&PM_SV_TraceTexture }, + +#endif // Sv_pmove_region + +#ifndef R_Studio_region + + { 0x01D6F260, "SV_InitStudioHull", (size_t)&SV_InitStudioHull }, + { 0x01D6F2F0, "R_CheckStudioCache", (size_t)&R_CheckStudioCache }, + //{ 0x01D6F3C0, "R_AddToStudioCache", (size_t)&R_AddToStudioCache }, // NOXREF + { 0x01D6F500, "AngleQuaternion", (size_t)&AngleQuaternion }, + { 0x01D6F600, "QuaternionSlerp", (size_t)&QuaternionSlerp }, + { 0x01D6F810, "QuaternionMatrix", (size_t)&QuaternionMatrix }, + { 0x01D6F900, "R_StudioCalcBoneAdj", (size_t)&R_StudioCalcBoneAdj }, + { 0x01D6FB60, "R_StudioCalcBoneQuaterion", (size_t)&R_StudioCalcBoneQuaterion }, + { 0x01D6FD20, "R_StudioCalcBonePosition", (size_t)&R_StudioCalcBonePosition }, + { 0x01D6FE70, "R_StudioSlerpBones", (size_t)&R_StudioSlerpBones }, + { 0x01D6FF80, "R_GetAnim", (size_t)&R_GetAnim }, + { 0x01D70020, "SV_StudioSetupBones", (size_t)&SV_StudioSetupBones }, + { 0x01D70390, "SV_SetStudioHullPlane", (size_t)&SV_SetStudioHullPlane }, + { 0x01D70400, "R_StudioHull", (size_t)&R_StudioHull }, + { 0x01D70A40, "SV_HitgroupForStudioHull", (size_t)&SV_HitgroupForStudioHull }, + //{ 0x01D70A50, "R_InitStudioCache", (size_t)&R_InitStudioCache }, // NOXREF + //{ 0x01D70A90, "R_FlushStudioCache", (size_t)&R_FlushStudioCache }, // NOXREF + { 0x01D70AA0, "R_StudioBodyVariations", (size_t)&R_StudioBodyVariations }, + { 0x01D70AF0, "R_StudioPlayerBlend", (size_t)&R_StudioPlayerBlend }, + { 0x01D70BD0, "SV_HullForStudioModel", (size_t)&SV_HullForStudioModel }, + { 0x01D70E10, "DoesSphereIntersect", (size_t)&DoesSphereIntersect }, + { 0x01D70ED0, "SV_CheckSphereIntersection", (size_t)&SV_CheckSphereIntersection }, + { 0x01D70FF0, "AnimationAutomove", (size_t)&AnimationAutomove }, + { 0x01D71000, "GetBonePosition", (size_t)&GetBonePosition }, + { 0x01D710A0, "GetAttachment", (size_t)&GetAttachment }, + { 0x01D71170, "ModelFrameCount", (size_t)&ModelFrameCount }, + { 0x01D76260, "R_StudioBoundVertex", (size_t)&R_StudioBoundVertex }, + { 0x01D762F0, "R_StudioBoundBone", (size_t)&R_StudioBoundBone }, + { 0x01D76380, "R_StudioAccumulateBoneVerts", (size_t)&R_StudioAccumulateBoneVerts }, + { 0x01D76420, "R_StudioComputeBounds", (size_t)&R_StudioComputeBounds }, + { 0x01D76600, "R_GetStudioBounds", (size_t)&R_GetStudioBounds }, + { 0x01D76C40, "R_ResetSvBlending", (size_t)&R_ResetSvBlending }, + +#endif // R_Studio_region + +#ifndef Net_ws_region + + { 0x01D57050, "NET_ThreadLock", (size_t)&NET_ThreadLock }, + { 0x01D57070, "NET_ThreadUnlock", (size_t)&NET_ThreadUnlock }, + { 0x01D57090, "Q_ntohs", (size_t)&Q_ntohs }, + { 0x01D570A0, "NetadrToSockadr", (size_t)&NetadrToSockadr }, + { 0x01D57160, "SockadrToNetadr", (size_t)&SockadrToNetadr }, + { 0x01D571D0, "NET_HostToNetShort", (size_t)&NET_HostToNetShort }, // NOXREF + { 0x01D571E0, "NET_CompareAdr", (size_t)&NET_CompareAdr }, + { 0x01D57270, "NET_CompareClassBAdr", (size_t)&NET_CompareClassBAdr }, + { 0x01D572C0, "NET_IsReservedAdr", (size_t)&NET_IsReservedAdr }, + { 0x01D57310, "NET_CompareBaseAdr", (size_t)&NET_CompareBaseAdr }, + { 0x01D57380, "NET_AdrToString", (size_t)&NET_AdrToString }, + { 0x01D574A0, "NET_BaseAdrToString", (size_t)&NET_BaseAdrToString }, + { 0x01D575A0, "NET_StringToSockaddr", (size_t)&NET_StringToSockaddr }, + { 0x01D57820, "NET_StringToAdr", (size_t)&NET_StringToAdr }, + { 0x01D57890, "NET_IsLocalAddress", (size_t)&NET_IsLocalAddress }, + { 0x01D578A0, "NET_ErrorString", (size_t)&NET_ErrorString }, + { 0x01D57B20, "NET_TransferRawData", (size_t)&NET_TransferRawData }, + { 0x01D57B50, "NET_GetLoopPacket", (size_t)&NET_GetLoopPacket }, + { 0x01D57C00, "NET_SendLoopPacket", (size_t)&NET_SendLoopPacket }, + { 0x01D57C80, "NET_RemoveFromPacketList", (size_t)&NET_RemoveFromPacketList }, + { 0x01D57CA0, "NET_CountLaggedList", (size_t)&NET_CountLaggedList }, + { 0x01D57CC0, "NET_ClearLaggedList", (size_t)&NET_ClearLaggedList }, + { 0x01D57D10, "NET_AddToLagged", (size_t)&NET_AddToLagged }, + { 0x01D57D80, "NET_AdjustLag", (size_t)&NET_AdjustLag }, + { 0x01D57EC0, "NET_LagPacket", (size_t)&NET_LagPacket }, + { 0x01D58090, "NET_FlushSocket", (size_t)&NET_FlushSocket }, + { 0x01D580E0, "NET_GetLong", (size_t)&NET_GetLong }, + { 0x01D582F0, "NET_QueuePacket", (size_t)&NET_QueuePacket }, +#ifdef __linux__ + { 0x0, "NET_Sleep_Timeout", (size_t)&NET_Sleep_Timeout }, +#endif // __linux__ + { 0x01D584A0, "NET_Sleep", (size_t)&NET_Sleep }, + { 0x01D58630, "NET_StartThread", (size_t)&NET_StartThread }, + { 0x01D586B0, "NET_StopThread", (size_t)&NET_StopThread }, + { 0x01D586F0, "net_malloc", (size_t)&net_malloc }, + { 0x01D58710, "NET_AllocMsg", (size_t)&NET_AllocMsg }, + { 0x01D58760, "NET_FreeMsg", (size_t)&NET_FreeMsg }, + { 0x01D587A0, "NET_GetPacket", (size_t)&NET_GetPacket }, + { 0x01D588B0, "NET_AllocateQueues", (size_t)&NET_AllocateQueues }, + { 0x01D588F0, "NET_FlushQueues", (size_t)&NET_FlushQueues }, + { 0x01D58960, "NET_SendLong", (size_t)&NET_SendLong }, + { 0x01D58AE0, "NET_SendPacket", (size_t)&NET_SendPacket }, + { 0x01D58C80, "NET_IPSocket", (size_t)&NET_IPSocket }, + { 0x01D58E80, "NET_OpenIP", (size_t)&NET_OpenIP }, +#ifdef _WIN32 + { 0x01D59000, "NET_IPXSocket", (size_t)&NET_IPXSocket }, + { 0x01D59170, "NET_OpenIPX", (size_t)&NET_OpenIPX }, +#endif //_WIN32 + { 0x01D59240, "NET_GetLocalAddress", (size_t)&NET_GetLocalAddress }, + { 0x01D59410, "NET_IsConfigured", (size_t)&NET_IsConfigured }, + { 0x01D59420, "NET_Config", (size_t)&NET_Config }, + { 0x01D596F0, "MaxPlayers_f", (size_t)&MaxPlayers_f }, + { 0x01D594D0, "NET_Init", (size_t)&NET_Init }, + { 0x01D59790, "NET_ClearLagData", (size_t)&NET_ClearLagData }, + { 0x01D597E0, "NET_Shutdown", (size_t)&NET_Shutdown }, + { 0x01D59810, "NET_JoinGroup", (size_t)&NET_JoinGroup }, + { 0x01D59870, "NET_LeaveGroup", (size_t)&NET_LeaveGroup }, + +#endif // Net_ws_region + +#ifndef Net_chan_region + + { 0x01D54DB0, "Netchan_UnlinkFragment", (size_t)&Netchan_UnlinkFragment }, + { 0x01D54E20, "Netchan_OutOfBand", (size_t)&Netchan_OutOfBand }, + { 0x01D54EA0, "Netchan_OutOfBandPrint", (size_t)&Netchan_OutOfBandPrint }, + { 0x01D54F00, "Netchan_ClearFragbufs", (size_t)&Netchan_ClearFragbufs }, + { 0x01D54F30, "Netchan_ClearFragments", (size_t)&Netchan_ClearFragments }, + { 0x01D54FA0, "Netchan_Clear", (size_t)&Netchan_Clear }, + { 0x01D55040, "Netchan_Setup", (size_t)&Netchan_Setup }, + { 0x01D550D0, "Netchan_CanPacket", (size_t)&Netchan_CanPacket }, + { 0x01D55130, "Netchan_UpdateFlow", (size_t)&Netchan_UpdateFlow }, + { 0x01D55240, "Netchan_Transmit", (size_t)&Netchan_Transmit }, + { 0x01D558E0, "Netchan_FindBufferById", (size_t)&Netchan_FindBufferById }, + { 0x01D55950, "Netchan_CheckForCompletion", (size_t)&Netchan_CheckForCompletion }, + { 0x01D55A00, "Netchan_Validate", (size_t)&Netchan_Validate }, + { 0x01D55A90, "Netchan_Process", (size_t)&Netchan_Process }, + { 0x01D55F40, "Netchan_FragSend", (size_t)&Netchan_FragSend }, + { 0x01D55F90, "Netchan_AddBufferToList", (size_t)&Netchan_AddBufferToList }, + { 0x01D55FE0, "Netchan_AllocFragbuf", (size_t)&Netchan_AllocFragbuf }, + { 0x01D56010, "Netchan_AddFragbufToTail", (size_t)&Netchan_AddFragbufToTail }, + { 0x01D56050, "Netchan_CreateFragments_", (size_t)&Netchan_CreateFragments_ }, + { 0x01D56210, "Netchan_CreateFragments", (size_t)&Netchan_CreateFragments }, + { 0x01D56250, "Netchan_CreateFileFragmentsFromBuffer", (size_t)&Netchan_CreateFileFragmentsFromBuffer }, + { 0x01D56450, "Netchan_CreateFileFragments", (size_t)&Netchan_CreateFileFragments }, + { 0x01D56850, "Netchan_FlushIncoming", (size_t)&Netchan_FlushIncoming }, + { 0x01D568C0, "Netchan_CopyNormalFragments", (size_t)&Netchan_CopyNormalFragments }, + { 0x01D569D0, "Netchan_CopyFileFragments", (size_t)&Netchan_CopyFileFragments }, + //{ 0x01D56DB0, "Netchan_IsSending", (size_t)&Netchan_IsSending }, + //{ 0x01D56DE0, "Netchan_IsReceiving", (size_t)&Netchan_IsReceiving }, + { 0x01D56E10, "Netchan_IncomingReady", (size_t)&Netchan_IncomingReady }, + //{ 0x01D56E40, "Netchan_UpdateProgress", (size_t)&Netchan_UpdateProgress }, + { 0x01D56FE0, "Netchan_Init", (size_t)&Netchan_Init }, + //{ 0x01D57030, "Netchan_CompressPacket", (size_t)&Netchan_CompressPacket }, //NOXREF + //{ 0x01D57040, "Netchan_DecompressPacket", (size_t)&Netchan_DecompressPacket }, //NOXREF + +#endif // Net_chan_region + +#ifndef Hashpak_region + + { 0x01D3E970, "HPAK_GetDataPointer", (size_t)&HPAK_GetDataPointer }, + { 0x01D3EC40, "HPAK_FindResource", (size_t)&HPAK_FindResource }, + { 0x01D3ECB0, "HPAK_AddToQueue", (size_t)&HPAK_AddToQueue }, + { 0x01D3EDC0, "HPAK_FlushHostQueue", (size_t)&HPAK_FlushHostQueue }, + { 0x01D3EE20, "HPAK_AddLump", (size_t)&HPAK_AddLump }, + { 0x01D3F3D0, "HPAK_RemoveLump", (size_t)&HPAK_RemoveLump }, + { 0x01D3F850, "HPAK_ResourceForIndex", (size_t)&HPAK_ResourceForIndex }, + { 0x01D3F9E0, "HPAK_ResourceForHash", (size_t)&HPAK_ResourceForHash }, + { 0x01D3FBA0, "HPAK_List_f", (size_t)&HPAK_List_f }, + { 0x01D3FE30, "HPAK_CreatePak", (size_t)&HPAK_CreatePak }, + { 0x01D40140, "HPAK_Remove_f", (size_t)&HPAK_Remove_f }, + { 0x01D401F0, "HPAK_Validate_f", (size_t)&HPAK_Validate_f }, + { 0x01D405B0, "HPAK_Extract_f", (size_t)&HPAK_Extract_f }, + { 0x01D409A0, "HPAK_Init", (size_t)&HPAK_Init }, + { 0x01D409F1, "HPAK_GetItem", (size_t)&HPAK_GetItem }, // NOXREF + { 0x01D40B90, "HPAK_CheckSize", (size_t)&HPAK_CheckSize }, + { 0x01D40CE0, "HPAK_ValidatePak", (size_t)&HPAK_ValidatePak }, + { 0x01D40F80, "HPAK_CheckIntegrity", (size_t)&HPAK_CheckIntegrity }, + +#endif // Hashpak_region + +#ifndef Wad_region + + { 0x01DB8D30, "W_CleanupName", (size_t)&W_CleanupName }, + { 0x01DB8D90, "W_LoadWadFile", (size_t)&W_LoadWadFile }, + { 0x01DB8EF0, "W_GetLumpinfo", (size_t)&W_GetLumpinfo }, + { 0x01DB8F70, "W_GetLumpName", (size_t)&W_GetLumpName }, + //{ 0x, "W_GetLumpNum", (size_t)&W_GetLumpNum }, // NOXREF + { 0x01DB8FF0, "W_Shutdown", (size_t)&W_Shutdown }, + { 0x01DB9020, "SwapPic", (size_t)&SwapPic }, + +#endif // Wad_region + +#ifndef Textures_region + + { 0x01DA7200, "SafeRead", (size_t)&SafeRead }, + { 0x01DA7230, "CleanupName", (size_t)&CleanupName }, + { 0x01DA7290, "lump_sorter", (size_t)&lump_sorter }, + { 0x01DA72E0, "ForwardSlashes", (size_t)&ForwardSlashes }, + { 0x01DA7300, "TEX_InitFromWad", (size_t)&TEX_InitFromWad }, + { 0x01DA75D0, "TEX_CleanupWadInfo", (size_t)&TEX_CleanupWadInfo }, + { 0x01DA7630, "TEX_LoadLump", (size_t)&TEX_LoadLump }, + { 0x01DA76D4, "FindMiptex", (size_t)&FindMiptex }, + { 0x01DA7740, "TEX_AddAnimatingTextures", (size_t)&TEX_AddAnimatingTextures }, + +#endif // Textures_region + +#ifndef Sv_user_region + + { 0x01D9B3B0, "SV_ParseConsistencyResponse", (size_t)&SV_ParseConsistencyResponse }, + { 0x01D9B790, "SV_FileInConsistencyList", (size_t)&SV_FileInConsistencyList }, + { 0x01D9B7F0, "SV_TransferConsistencyInfo", (size_t)&SV_TransferConsistencyInfo }, + { 0x01D9B960, "SV_SendConsistencyList", (size_t)&SV_SendConsistencyList }, + { 0x01D9BA50, "SV_PreRunCmd", (size_t)&SV_PreRunCmd }, + { 0x01D9BA60, "SV_CopyEdictToPhysent", (size_t)&SV_CopyEdictToPhysent }, + { 0x01D9BD70, "SV_AddLinksToPM_", (size_t)&SV_AddLinksToPM_ }, + { 0x01D9C070, "SV_AddLinksToPM", (size_t)&SV_AddLinksToPM }, + { 0x01D9C1A0, "SV_PlayerRunPreThink", (size_t)&SV_PlayerRunPreThink }, + { 0x01D9C1C0, "SV_PlayerRunThink", (size_t)&SV_PlayerRunThink }, + { 0x01D9C260, "SV_CheckMovingGround", (size_t)&SV_CheckMovingGround }, + { 0x01D9C340, "SV_ConvertPMTrace", (size_t)&SV_ConvertPMTrace }, + { 0x01D9C3A0, "SV_ForceFullClientsUpdate", (size_t)&SV_ForceFullClientsUpdate }, + { 0x01D9C470, "SV_RunCmd", (size_t)&SV_RunCmd }, + { 0x01D9D69F, "SV_ValidateClientCommand", (size_t)&SV_ValidateClientCommand }, + { 0x01D9D6EF, "SV_CalcClientTime", (size_t)&SV_CalcClientTime }, + { 0x01D9D86F, "SV_ComputeLatency", (size_t)&SV_ComputeLatency }, + { 0x01D9D88F, "SV_UnlagCheckTeleport", (size_t)&SV_UnlagCheckTeleport }, + { 0x01D9D8DF, "SV_GetTrueOrigin", (size_t)&SV_GetTrueOrigin }, + { 0x01D9D96F, "SV_GetTrueMinMax", (size_t)&SV_GetTrueMinMax }, + { 0x01D9D9EF, "SV_FindEntInPack", (size_t)&SV_FindEntInPack }, + { 0x01D9DA2F, "SV_SetupMove", (size_t)&SV_SetupMove }, + { 0x01D9E01F, "SV_RestoreMove", (size_t)&SV_RestoreMove }, + { 0x01D9E17F, "SV_ParseStringCommand", (size_t)&SV_ParseStringCommand }, + { 0x01D9E1DF, "SV_ParseDelta", (size_t)&SV_ParseDelta }, + { 0x01D9E1FF, "SV_EstablishTimeBase", (size_t)&SV_EstablishTimeBase }, + { 0x01D9E2EF, "SV_ParseMove", (size_t)&SV_ParseMove }, + { 0x01D9E76F, "SV_ParseVoiceData", (size_t)&SV_ParseVoiceData }, + { 0x01D9E8DF, "SV_IgnoreHLTV", (size_t)&SV_IgnoreHLTV }, + { 0x01D9E8EF, "SV_ParseCvarValue", (size_t)&SV_ParseCvarValue }, + { 0x01D9E92F, "SV_ParseCvarValue2", (size_t)&SV_ParseCvarValue2 }, + { 0x01D9E9AF, "SV_ExecuteClientMessage", (size_t)&SV_ExecuteClientMessage }, + { 0x01D9EACF, "SV_SetPlayer", (size_t)&SV_SetPlayer }, + { 0x01D9EB2F, "SV_ShowServerinfo_f", (size_t)&SV_ShowServerinfo_f }, + { 0x01D9EB4F, "SV_SendEnts_f", (size_t)&SV_SendEnts_f }, + { 0x01D9EB7F, "SV_FullUpdate_f", (size_t)&SV_FullUpdate_f }, + +#endif // Sv_user_region + +#ifndef Tmessage_region + + { 0x01DA7B00, "memfgets", (size_t)&memfgets }, + { 0x01DA7B90, "IsComment", (size_t)&IsComment }, + { 0x01DA7BD0, "IsStartOfText", (size_t)&IsStartOfText }, + { 0x01DA7BF0, "IsEndOfText", (size_t)&IsEndOfText }, + { 0x01DA7C10, "IsWhiteSpace", (size_t)&IsWhiteSpace }, + //{ 0x01DA7C40, "SkipSpace", (size_t)&SkipSpace }, // NOXREF + //{ 0x01DA7C80, "SkipText", (size_t)&SkipText }, // NOXREF + //{ 0x01DA7CC0, "ParseFloats", (size_t)&ParseFloats }, // NOXREF + { 0x01DA7D10, "TrimSpace", (size_t)&TrimSpace }, + //{ 0x01DA7D90, "IsToken", (size_t)&IsToken }, // NOXREF + //{ 0x01DA7DD0, "ParseDirective", (size_t)&ParseDirective }, // NOXREF + //{ 0x01DA80A0, "TextMessageParse", (size_t)&TextMessageParse }, // NOXREF + //{ 0x01DA8030, "TextMessageShutdown", (size_t)&TextMessageShutdown }, // NOXREF + //{ 0x01DA8050, "TextMessageInit", (size_t)&TextMessageInit }, // NOXREF + //{ 0x01DA8410, "TextMessageGet", (size_t)&TextMessageGet }, // NOXREF + +#endif // Tmessage_region + +#ifndef TraceInit_Region + + { 0x01DA8CA0, "_ZN12CInitTracker4InitEPKcS1_i", mfunc_ptr_cast(&CInitTracker::Init) }, + { 0x01DA8D80, "_ZN12CInitTracker8ShutdownEPKci", mfunc_ptr_cast(&CInitTracker::Shutdown) }, + //{ 0x01DA8B60, "_ZN12CInitTrackerC2Ev", mfunc_ptr_cast(&CInitTracker::CInitTracker) }, + //{ 0x01DA8BD0, "_ZN12CInitTrackerD2Ev", mfunc_ptr_cast(&CInitTracker::~CInitTracker) }, + { 0x01DA8E60, "_Z9TraceInitPKcS0_i", (size_t)&TraceInit }, + { 0x01DA8E80, "_Z13TraceShutdownPKci", (size_t)&TraceShutdown }, + +#endif // TraceInit_Region + +#ifndef Vid_null_region + + //{ 0x, "VID_SetPalette", (size_t)&VID_SetPalette }, + //{ 0x, "VID_ShiftPalette", (size_t)&VID_ShiftPalette }, + //{ 0x, "VID_WriteBuffer", (size_t)&VID_WriteBuffer }, + //{ 0x01DB4BD0, "VID_Init", (size_t)&VID_Init }, + //{ 0x, "D_FlushCaches", (size_t)&D_FlushCaches }, + //{ 0x, "R_SetStackBase", (size_t)&R_SetStackBase }, + //{ 0x01D7E3D0, "SCR_UpdateScreen", (size_t)&SCR_UpdateScreen }, + //{ 0x, "V_Init", (size_t)&V_Init }, + //{ 0x, "Draw_Init", (size_t)&Draw_Init }, + //{ 0x, "SCR_Init", (size_t)&SCR_Init }, + //{ 0x01D65630, "R_Init", (size_t)&R_Init }, + //{ 0x01D67B20, "R_ForceCVars", (size_t)&R_ForceCVars }, + //{ 0x01D7E320, "SCR_BeginLoadingPlaque", (size_t)&SCR_BeginLoadingPlaque }, + //{ 0x01D7E3A0, "SCR_EndLoadingPlaque", (size_t)&SCR_EndLoadingPlaque }, + //{ 0x, "R_InitSky", (size_t)&R_InitSky }, + //{ 0x01D65F70, "R_MarkLeaves", (size_t)&R_MarkLeaves }, + { 0x01D65570, "R_InitTextures", (size_t)&R_InitTextures }, + //{ 0x, "StartLoadingProgressBar", (size_t)&StartLoadingProgressBar }, + //{ 0x01D07670, "ContinueLoadingProgressBar", (size_t)&ContinueLoadingProgressBar }, + //{ 0x01D07700, "SetLoadingProgressBarStatusText", (size_t)&SetLoadingProgressBarStatusText }, + +#endif // Vid_null_region + +#ifndef L_studio_region + + { 0x01D4F0E0, "Mod_LoadStudioModel", (size_t)&Mod_LoadStudioModel }, + +#endif // L_studio_region + +#ifndef Crc_region + + { 0x01D2C610, "CRC32_Init", (size_t)&CRC32_Init }, + { 0x01D2C620, "CRC32_Final", (size_t)&CRC32_Final }, + { 0x01D2C630, "CRC32_ProcessByte", (size_t)&CRC32_ProcessByte }, + { 0x01D2C660, "CRC32_ProcessBuffer", (size_t)&CRC32_ProcessBuffer }, + { 0x01D2C8D0, "COM_BlockSequenceCRCByte", (size_t)&COM_BlockSequenceCRCByte }, + { 0x01D2C970, "CRC_File", (size_t)&CRC_File }, // NOXREF + { 0x01D2CA40, "CRC_MapFile", (size_t)&CRC_MapFile }, + { 0x01D2CBB0, "MD5Init", (size_t)&MD5Init }, + { 0x01D2CBE0, "MD5Update", (size_t)&MD5Update }, + { 0x01D2CCB0, "MD5Final", (size_t)&MD5Final }, + { 0x01D2CD40, "MD5Transform", (size_t)&MD5Transform }, + { 0x01D2D5B0, "MD5_Hash_File", (size_t)&MD5_Hash_File }, + { 0x01D2D6F0, "MD5_Print", (size_t)&MD5_Print }, + +#endif // Crc_region + +#ifndef Sv_RemoteAccess_region + + { 0x01D984E0, "_ZN19CServerRemoteAccess20SendMessageToAdminUIEPKc", mfunc_ptr_cast(&CServerRemoteAccess::SendMessageToAdminUI) }, + { 0x01D985E0, "NotifyDedicatedServerUI", (size_t)&NotifyDedicatedServerUI }, + { 0x01D98090, "_ZN19CServerRemoteAccess17LookupStringValueEPKc", mfunc_ptr_cast(&CServerRemoteAccess::LookupStringValue) }, + { 0x01D97D40, "_ZN19CServerRemoteAccess11LookupValueEPKcR10CUtlBuffer", mfunc_ptr_cast(&CServerRemoteAccess::LookupValue) }, + + { 0x01D98190, "_ZN19CServerRemoteAccess14GetUserBanListER10CUtlBuffer", mfunc_ptr_cast(&CServerRemoteAccess::GetUserBanList) }, + { 0x01D98280, "_ZN19CServerRemoteAccess13GetPlayerListER10CUtlBuffer", mfunc_ptr_cast(&CServerRemoteAccess::GetPlayerList) }, + { 0x01D983B0, "_ZN19CServerRemoteAccess10GetMapListER10CUtlBuffer", mfunc_ptr_cast(&CServerRemoteAccess::GetMapList) }, + + { 0x01D97AD0, "_ZN19CServerRemoteAccess12RequestValueEiPKc", mfunc_ptr_cast(&CServerRemoteAccess::RequestValue) }, + { 0x01D97C20, "_ZN19CServerRemoteAccess8SetValueEPKcS1_", mfunc_ptr_cast(&CServerRemoteAccess::SetValue) }, + { 0x01D97D10, "_ZN19CServerRemoteAccess11ExecCommandEPKc", mfunc_ptr_cast(&CServerRemoteAccess::ExecCommand) }, + + { 0x01D97850, "_ZN19CServerRemoteAccess16WriteDataRequestEPKvi", mfunc_ptr_cast(&CServerRemoteAccess::WriteDataRequest_noVirt) }, + { 0x01D979A0, "_ZN19CServerRemoteAccess16ReadDataResponseEPvi", mfunc_ptr_cast(&CServerRemoteAccess::ReadDataResponse_noVirt) }, + +#endif // Sv_RemoteAccess_region + +#ifndef IpratelimitWrapper_region + + //{ 0x01D4D990, "CheckIP", (size_t)&CheckIP }, + +#endif // IpratelimitWrapper_region + +#ifndef Com_custom + + { 0x01D28610, "COM_ClearCustomizationList", (size_t)&COM_ClearCustomizationList }, + { 0x01D28740, "COM_CreateCustomization", (size_t)&COM_CreateCustomization }, + { 0x01D28980, "COM_SizeofResourceList", (size_t)&COM_SizeofResourceList }, + +#endif // Com_custom + +#ifndef Sv_upld + + { 0x01D9A980, "SV_CheckFile", (size_t)&SV_CheckFile }, + { 0x01D9AA50, "SV_ClearResourceLists", (size_t)&SV_ClearResourceLists }, + { 0x01D9AA90, "SV_CreateCustomizationList", (size_t)&SV_CreateCustomizationList }, + { 0x01D9ABB0, "SV_Customization", (size_t)&SV_Customization }, + { 0x01D9AD20, "SV_RegisterResources", (size_t)&SV_RegisterResources }, + { 0x01D9AD70, "SV_MoveToOnHandList", (size_t)&SV_MoveToOnHandList }, + { 0x01D9ADB0, "SV_AddToResourceList", (size_t)&SV_AddToResourceList }, + { 0x01D9AE00, "SV_ClearResourceList", (size_t)&SV_ClearResourceList }, + { 0x01D9AE50, "SV_RemoveFromResourceList", (size_t)&SV_RemoveFromResourceList }, + { 0x01D9AE80, "SV_EstimateNeededResources", (size_t)&SV_EstimateNeededResources }, + { 0x01D9AEF0, "SV_RequestMissingResourcesFromClients", (size_t)&SV_RequestMissingResourcesFromClients }, + { 0x01D9AF40, "SV_UploadComplete", (size_t)&SV_UploadComplete }, + { 0x01D9AFA0, "SV_BatchUploadRequest", (size_t)&SV_BatchUploadRequest }, + { 0x01D9B040, "SV_RequestMissingResources", (size_t)&SV_RequestMissingResources }, + { 0x01D9B070, "SV_ParseResourceList", (size_t)&SV_ParseResourceList }, + +#endif // Sv_upld + +#ifndef Decals + + { 0x01D33EF0, "Draw_Shutdown", (size_t)&Draw_Shutdown }, + { 0x01D33F30, "Draw_DecalShutdown", (size_t)&Draw_DecalShutdown }, + { 0x01D33F60, "Draw_AllocateCacheSpace", (size_t)&Draw_AllocateCacheSpace }, + { 0x01D33F90, "Draw_CacheWadInitFromFile", (size_t)&Draw_CacheWadInitFromFile }, + { 0x01D34070, "Draw_CacheWadInit", (size_t)&Draw_CacheWadInit }, + { 0x01D340C0, "Draw_CustomCacheWadInit", (size_t)&Draw_CustomCacheWadInit }, + { 0x01D3A830, "Draw_MiptexTexture", (size_t)&Draw_MiptexTexture }, + { 0x01D34290, "Draw_CacheWadHandler", (size_t)&Draw_CacheWadHandler }, + { 0x01D342B0, "Draw_FreeWad", (size_t)&Draw_FreeWad }, + { 0x01D34380, "Draw_DecalSetName", (size_t)&Draw_DecalSetName }, // NOXREF + { 0x01D343C0, "Draw_DecalIndex", (size_t)&Draw_DecalIndex }, // NOXREF + { 0x01D34450, "Draw_DecalCount", (size_t)&Draw_DecalCount }, + { 0x01D34460, "Draw_DecalSize", (size_t)&Draw_DecalSize }, + { 0x01D34490, "Draw_DecalName", (size_t)&Draw_DecalName }, + { 0x01D344C0, "Draw_DecalTexture", (size_t)&Draw_DecalTexture }, // NOXREF + { 0x01D34560, "Draw_CacheByIndex", (size_t)&Draw_CacheByIndex }, + { 0x01D34600, "Draw_DecalIndexFromName", (size_t)&Draw_DecalIndexFromName }, // NOXREF + { 0x01D34670, "Decal_ReplaceOrAppendLump", (size_t)&Decal_ReplaceOrAppendLump }, + { 0x01D34710, "Decal_CountLumps", (size_t)&Decal_CountLumps }, + { 0x01D34730, "Decal_SizeLumps", (size_t)&Decal_SizeLumps }, + { 0x01D34750, "Decal_MergeInDecals", (size_t)&Decal_MergeInDecals }, + { 0x01D349A0, "Decal_Init", (size_t)&Decal_Init }, + { 0x01D34B00, "CustomDecal_Validate", (size_t)&CustomDecal_Validate }, + { 0x01D34B60, "CustomDecal_Init", (size_t)&CustomDecal_Init }, + { 0x01D34BD0, "Draw_CacheGet", (size_t)&Draw_CacheGet }, // NOXREF + { 0x01D34CC0, "Draw_CustomCacheGet", (size_t)&Draw_CustomCacheGet }, + { 0x01D34D60, "Draw_CacheReload", (size_t)&Draw_CacheReload }, // NOXREF + { 0x01D34E40, "Draw_ValidateCustomLogo", (size_t)&Draw_ValidateCustomLogo }, + { 0x01D35000, "Draw_CacheLoadFromCustom", (size_t)&Draw_CacheLoadFromCustom }, + { 0x01D35110, "Draw_CacheIndex", (size_t)&Draw_CacheIndex }, // NOXREF + { 0x01D351A9, "Draw_CacheFindIndex", (size_t)&Draw_CacheFindIndex }, // NOXREF + +#endif // Decals + +#ifndef Sys_engine + + //{ 0x, "CEngine::CEngine", (size_t)&CEngine::CEngine }, + //{ 0x, "CEngine::~CEngine", (size_t)&CEngine::~CEngine }, + { 0x01DA1C80, "_ZN7CEngine6UnloadEv", mfunc_ptr_cast(&CEngine::Unload_noVirt) }, + { 0x01DA1CA0, "_ZN7CEngine4LoadEbPcS0_", mfunc_ptr_cast(&CEngine::Load_noVirt) }, + { 0x01DA1CF0, "_ZN7CEngine5FrameEv", mfunc_ptr_cast(&CEngine::Frame_noVirt) }, + { 0x01DA1DD0, "_ZN7CEngine11SetSubStateEi", mfunc_ptr_cast(&CEngine::SetSubState_noVirt) }, + { 0x01DA1DF0, "_ZN7CEngine8SetStateEi", mfunc_ptr_cast(&CEngine::SetState_noVirt) }, + { 0x01DA1E10, "_ZN7CEngine8GetStateEv", mfunc_ptr_cast(&CEngine::GetState_noVirt) }, + { 0x01DA1E20, "_ZN7CEngine11GetSubStateEv", mfunc_ptr_cast(&CEngine::GetSubState_noVirt) }, + { 0x01DA1E30, "_ZN7CEngine12GetFrameTimeEv", mfunc_ptr_cast(&CEngine::GetFrameTime_noVirt) }, + { 0x01DA1E40, "_ZN7CEngine10GetCurTimeEv", mfunc_ptr_cast(&CEngine::GetCurTime_noVirt) }, + { 0x01DA1E50, "_ZN7CEngine13TrapKey_EventEib", mfunc_ptr_cast(&CEngine::TrapKey_Event_noVirt) }, + { 0x01DA1E90, "_ZN7CEngine15TrapMouse_EventEib", mfunc_ptr_cast(&CEngine::TrapMouse_Event_noVirt) }, + { 0x01DA1ED0, "_ZN7CEngine13StartTrapModeEv", mfunc_ptr_cast(&CEngine::StartTrapMode_noVirt) }, + { 0x01DA1EE0, "_ZN7CEngine10IsTrappingEv", mfunc_ptr_cast(&CEngine::IsTrapping_noVirt) }, + { 0x01DA1EF0, "_ZN7CEngine17CheckDoneTrappingERiS0_", mfunc_ptr_cast(&CEngine::CheckDoneTrapping_noVirt) }, + { 0x01DA1F30, "_ZN7CEngine11SetQuittingEi", mfunc_ptr_cast(&CEngine::SetQuitting_noVirt) }, + { 0x01DA1F40, "_ZN7CEngine11GetQuittingEv", mfunc_ptr_cast(&CEngine::GetQuitting_noVirt) }, + +#endif // Sys_engine + +#ifndef Sys_linuxwind + // Disable/enable all at once! + + { 0x01DA5A10, "_ZN5CGame4InitEPv", mfunc_ptr_cast(&CGame::Init_noVirt) }, + { 0x01DA5A20, "_ZN5CGame8ShutdownEv", mfunc_ptr_cast(&CGame::Shutdown_noVirt) }, + { 0x01DA5760, "_ZN5CGame16CreateGameWindowEv", mfunc_ptr_cast(&CGame::CreateGameWindow_noVirt) }, + { 0x01DA4B20, "_ZN5CGame15SleepUntilInputEi", mfunc_ptr_cast(&CGame::SleepUntilInput_noVirt) }, + { 0x01DA5A40, "_ZN5CGame13GetMainWindowEv", mfunc_ptr_cast(&CGame::GetMainWindow_noVirt) }, + { 0x01DA5A50, "_ZN5CGame20GetMainWindowAddressEv", mfunc_ptr_cast(&CGame::GetMainWindowAddress_noVirt) }, + { 0x01DA5A60, "_ZN5CGame11SetWindowXYEii", mfunc_ptr_cast(&CGame::SetWindowXY_noVirt) }, + { 0x01DA5A80, "_ZN5CGame13SetWindowSizeEii", mfunc_ptr_cast(&CGame::SetWindowSize_noVirt) }, + { 0x01DA5B00, "_ZN5CGame13GetWindowRectEPiS0_S0_S0_", mfunc_ptr_cast(&CGame::GetWindowRect_noVirt) }, + { 0x01DA5B40, "_ZN5CGame11IsActiveAppEv", mfunc_ptr_cast(&CGame::IsActiveApp_noVirt) }, + { 0x01DA5B60, "_ZN5CGame13IsMultiplayerEv", mfunc_ptr_cast(&CGame::IsMultiplayer_noVirt) }, + { 0x01DA5BB0, "_ZN5CGame17PlayStartupVideosEv", mfunc_ptr_cast(&CGame::PlayStartupVideos_noVirt) }, + { 0x01DA5BC0, "_ZN5CGame14PlayAVIAndWaitEPKc", mfunc_ptr_cast(&CGame::PlayAVIAndWait_noVirt) }, + { 0x01DA5B70, "_ZN5CGame16SetCursorVisibleEb", mfunc_ptr_cast(&CGame::SetCursorVisible_noVirt) }, + +#endif //Sys_linuxwind + + { NULL, NULL, NULL }, +}; + + +AddressRef g_FunctionRefs[] = +{ +#ifndef Function_References_region + + { 0x01D4D990, "CheckIP", (size_t)&pCheckIP }, + + // Find C STD functions + { 0x01E000AE, "time", 0 }, + { 0x01E0008C, "rand", 0 }, + { 0x01E0007F, "srand", 0 }, + { 0x01E00AF1, "localtime", 0 }, + +#endif // Function_References_region + + { NULL, NULL, NULL }, +}; + +AddressRef g_DataRefs[] = +{ +#ifndef Data_References_region + + { 0x0229AE80, "pr_strings", (size_t)&ppr_strings }, + { 0x01E45C04, "gNullString", (size_t)&pgNullString }, + + { 0x01E46480, "SV_UPDATE_BACKUP", (size_t)&pSV_UPDATE_BACKUP }, + { 0x01E46484, "SV_UPDATE_MASK", (size_t)&pSV_UPDATE_MASK }, + + + { 0x021D3E80, "gGlobalVariables", (size_t)&pgGlobalVariables }, + { 0x021D3DE0, "svs", (size_t)&psvs }, + { 0x021D4960, "sv", (size_t)&psv }, + { 0x0208F788, "gPacketSuppressed", (size_t)&pgPacketSuppressed }, + { 0x01E45C08, "giNextUserMsg", (size_t)&pgiNextUserMsg }, + { 0x0208F7A4, "hashstrings_collisions", (size_t)&phashstrings_collisions }, + + { 0x0208F76C, "g_pplayerdelta", (size_t)&pg_pplayerdelta }, + { 0x0208F770, "g_pentitydelta", (size_t)&pg_pentitydelta }, + { 0x0208F774, "g_pcustomentitydelta", (size_t)&pg_pcustomentitydelta }, + { 0x0208F778, "g_pclientdelta", (size_t)&pg_pclientdelta }, + { 0x0208F77C, "g_pweapondelta", (size_t)&pg_pweapondelta }, + + { 0x021C2B60, "localinfo", (size_t)&plocalinfo }, + { 0x021D3F40, "localmodels", (size_t)&plocalmodels }, + + { 0x0221AD80, "ipfilters", (size_t)&pipfilters }, + { 0x021D4940, "numipfilters", (size_t)&pnumipfilters }, + { 0x0229B6C0, "userfilters", (size_t)&puserfilters }, + { 0x0208F798, "numuserfilters", (size_t)&pnumuserfilters }, + + { 0x01E45F84, "sv_lan", (size_t)&psv_lan }, + { 0x01E45FAC, "sv_lan_rate", (size_t)&psv_lan_rate }, + { 0x01E45E8C, "sv_aim", (size_t)&psv_aim }, + + { 0x021D1BC0, "sv_decalnames", (size_t)&psv_decalnames }, + { 0x0208F78C, "sv_decalnamecount", (size_t)&psv_decalnamecount }, + + { 0x01E46274, "sv_skycolor_r", (size_t)&psv_skycolor_r }, + { 0x01E46298, "sv_skycolor_g", (size_t)&psv_skycolor_g }, + { 0x01E462BC, "sv_skycolor_b", (size_t)&psv_skycolor_b }, + { 0x01E462E0, "sv_skyvec_x", (size_t)&psv_skyvec_x }, + { 0x01E46304, "sv_skyvec_y", (size_t)&psv_skyvec_y }, + { 0x01E46328, "sv_skyvec_z", (size_t)&psv_skyvec_z }, + + { 0x01E48F64, "sv_spectatormaxspeed", (size_t)&psv_spectatormaxspeed }, + { 0x01E48F90, "sv_airaccelerate", (size_t)&psv_airaccelerate }, + { 0x01E48FBC, "sv_wateraccelerate", (size_t)&psv_wateraccelerate }, + { 0x01E48FE4, "sv_waterfriction", (size_t)&psv_waterfriction }, + { 0x01E49008, "sv_zmax", (size_t)&psv_zmax }, + { 0x01E4902C, "sv_wateramp", (size_t)&psv_wateramp }, + { 0x01E49054, "sv_skyname", (size_t)&psv_skyname }, + { 0x01E46034, "mapcyclefile", (size_t)&pmapcyclefile }, + { 0x01E46060, "motdfile", (size_t)&pmotdfile }, + { 0x01E46090, "servercfgfile", (size_t)&pservercfgfile }, + { 0x01E460F0, "lservercfgfile", (size_t)&plservercfgfile }, + { 0x01E46114, "logsdir", (size_t)&plogsdir }, + { 0x01E46144, "bannedcfgfile", (size_t)&pbannedcfgfile }, + + + { 0x0208F790, "sv_gpNewUserMsgs", (size_t)&psv_gpNewUserMsgs }, + { 0x0208F794, "sv_gpUserMsgs", (size_t)&psv_gpUserMsgs }, + + { 0x0239BCE0, "g_svmove", (size_t)&pg_svmove }, + + { 0x0208F760, "sv_lastnum", (size_t)&psv_lastnum }, + { 0x02089220, "g_sv_instance_baselines", (size_t)&pg_sv_instance_baselines }, + { 0x0208F764, "g_bOutOfDateRestart", (size_t)&pg_bOutOfDateRestart }, + { 0x01E45C00, "g_userid", (size_t)&pg_userid }, + + { 0x0208F768, "g_sv_delta", (size_t)&pg_sv_delta }, + { 0x0208F780, "g_peventdelta", (size_t)&pg_peventdelta }, + + { 0x01E45C1C, "rcon_password", (size_t)&prcon_password }, + { 0x01E45C48, "sv_enableoldqueries", (size_t)&psv_enableoldqueries }, + + { 0x01E45C74, "sv_instancedbaseline", (size_t)&psv_instancedbaseline }, + { 0x01E45C94, "sv_contact", (size_t)&psv_contact }, + { 0x01E45CC4, "sv_maxupdaterate", (size_t)&psv_maxupdaterate }, + { 0x01E45CF4, "sv_minupdaterate", (size_t)&psv_minupdaterate }, + { 0x01E45D18, "sv_filterban", (size_t)&psv_filterban }, + { 0x01E45D3C, "sv_minrate", (size_t)&psv_minrate }, + { 0x01E45D60, "sv_maxrate", (size_t)&psv_maxrate }, + { 0x01E45D84, "sv_logrelay", (size_t)&psv_logrelay }, + + { 0x01E45DD0, "violence_hblood", (size_t)&pviolence_hblood }, + { 0x01E45DF8, "violence_ablood", (size_t)&pviolence_ablood }, + { 0x01E45E20, "violence_hgibs", (size_t)&pviolence_hgibs }, + { 0x01E45E48, "violence_agibs", (size_t)&pviolence_agibs }, + { 0x01E45E6C, "sv_newunit", (size_t)&psv_newunit }, + + { 0x01E45ED8, "sv_clienttrace", (size_t)&psv_clienttrace }, + { 0x01E45EFC, "sv_timeout", (size_t)&psv_timeout }, + { 0x01E45F24, "sv_failuretime", (size_t)&psv_failuretime }, + + { 0x01E45F44, "sv_cheats", (size_t)&psv_cheats }, + { 0x01E45F64, "sv_password", (size_t)&psv_password }, + { 0x01E45FD0, "sv_proxies", (size_t)&psv_proxies }, + { 0x01E46000, "sv_outofdatetime", (size_t)&psv_outofdatetime }, + + { 0x01E460B8, "mapchangecfgfile", (size_t)&pmapchangecfgfile }, + + { 0x021D1BA0, "allow_cheats", (size_t)&pallow_cheats }, + + { 0x01E455A8, "mp_logecho", (size_t)&pmp_logecho }, + { 0x01E45584, "mp_logfile", (size_t)&pmp_logfile }, + + { 0x01E4616C, "sv_allow_download", (size_t)&psv_allow_download }, + { 0x01E46190, "sv_send_logos", (size_t)&psv_send_logos }, + { 0x01E461B8, "sv_send_resources", (size_t)&psv_send_resources }, + + { 0x01E455FC, "sv_log_singleplayer", (size_t)&psv_log_singleplayer }, + { 0x01E45620, "sv_logsecret", (size_t)&psv_logsecret }, + { 0x01E455D0, "sv_log_onefile", (size_t)&psv_log_onefile }, + { 0x01E461DC, "sv_logbans", (size_t)&psv_logbans }, + { 0x01E46204, "sv_allow_upload", (size_t)&psv_allow_upload }, + { 0x01E4622C, "sv_max_upload", (size_t)&psv_max_upload }, + { 0x01E46250, "hpk_maxsize", (size_t)&phpk_maxsize }, + { 0x01E46358, "sv_visiblemaxplayers", (size_t)&psv_visiblemaxplayers }, + + { 0x01E46380, "max_queries_sec", (size_t)&pmax_queries_sec }, + { 0x01E463B0, "max_queries_sec_global", (size_t)&pmax_queries_sec_global }, + { 0x01E463DC, "max_queries_window", (size_t)&pmax_queries_window }, + + { 0x01E46400, "sv_logblocks", (size_t)&psv_logblocks }, + { 0x01E46424, "sv_downloadurl", (size_t)&psv_downloadurl }, + { 0x01E4644C, "sv_allow_dlfile", (size_t)&psv_allow_dlfile }, + { 0x01E4646C, "sv_version", (size_t)&psv_version }, + + { 0x0229B2A0, "sv_playermodel", (size_t)&psv_playermodel }, + + { 0x026EB5E0, "cls", (size_t)&pcls }, + { 0x026F1DE0, "cl", (size_t)&pcl }, + { 0x01FED50C, "key_dest", (size_t)&pkey_dest }, + + { 0x0269BB00, "g_clmove", (size_t)&pg_clmove }, + { 0x028A1454, "cl_inmovie", (size_t)&pcl_inmovie }, + + { 0x01E2F0F8, "cl_name", (size_t)&pcl_name }, + { 0x01E2F1B4, "rate", (size_t)&prate }, + { 0x01E33D6C, "console", (size_t)&pconsole }, + + { 0x01E39FF4, "host_name", (size_t)&phost_name }, + { 0x01E3A040, "host_speeds", (size_t)&phost_speeds }, + { 0x01E3A064, "host_profile", (size_t)&phost_profile }, + { 0x01E3A084, "developer", (size_t)&pdeveloper }, + { 0x01E3A0AC, "host_limitlocal", (size_t)&phost_limitlocal }, + { 0x01E3A0C8, "skill", (size_t)&pskill }, + { 0x01E3A0EC, "deathmatch", (size_t)&pdeathmatch }, + { 0x01E3A108, "coop", (size_t)&pcoop }, + { 0x0266AFA0, "realtime", (size_t)&prealtime }, + { 0x01FED0C0, "rolling_fps", (size_t)&prolling_fps }, + + { 0x0266AF20, "host_parms", (size_t)&phost_parms }, + { 0x01FED0B4, "host_initialized", (size_t)&phost_initialized }, + { 0x0266AEC8, "host_frametime", (size_t)&phost_frametime }, + + { 0x0266AED0, "host_framecount", (size_t)&phost_framecount }, + + { 0x0266AEDC, "host_client", (size_t)&phost_client }, + { 0x01FED0B8, "gfNoMasterServer", (size_t)&pgfNoMasterServer }, + + { 0x0266AF38, "oldrealtime", (size_t)&poldrealtime }, + { 0x0266AEC4, "host_hunklevel", (size_t)&phost_hunklevel }, + { 0x0266AF60, "host_abortserver", (size_t)&phost_abortserver }, + { 0x0266AEE0, "host_enddemo", (size_t)&phost_enddemo }, + + { 0x0266AED4, "host_basepal", (size_t)&phost_basepal }, + + { 0x01FD9778, "bfread", (size_t)&pbfread }, + { 0x01FD9790, "bfwrite", (size_t)&pbfwrite }, + { 0x02699D48, "msg_readcount", (size_t)&pmsg_readcount }, + { 0x02699D4C, "msg_badread", (size_t)&pmsg_badread }, + + { 0x01FEB260, "decal_wad", (size_t)&pdecal_wad }, + { 0x01FEB264, "menu_wad", (size_t)&pmenu_wad }, + { 0x0266D440, "szCustName", (size_t)&pszCustName }, + { 0x0266B440, "decal_names", (size_t)&pdecal_names }, + { 0x01FEB268, "m_bDrawInitialized", (size_t)&pm_bDrawInitialized }, + { 0x01FEB25C, "gfCustomBuild", (size_t)&pgfCustomBuild }, + + { 0x01FEB26C, "g_defs", (size_t)&pg_defs }, + { 0x01FEB270, "g_encoders", (size_t)&pg_encoders }, + { 0x01FEB274, "g_deltaregistry", (size_t)&pg_deltaregistry }, + + { 0x021B97E0, "gNetworkTextMessageBuffer", (size_t)&pgNetworkTextMessageBuffer }, + { 0x021B9FE0, "gMessageParms", (size_t)&pgMessageParms }, + { 0x02095C8C, "gMessageTable", (size_t)&pgMessageTable }, + { 0x02095C90, "gMessageTableCount", (size_t)&pgMessageTableCount }, + + { 0x01E4CE10, "gNetworkMessageNames", (size_t)&pgNetworkMessageNames }, + { 0x01E4CE30, "gNetworkTextMessage", (size_t)&pgNetworkTextMessage }, + + { 0x021B61C4, "hunk_base", (size_t)&phunk_base }, + { 0x021B61C8, "hunk_tempactive", (size_t)&phunk_tempactive }, + { 0x021B61D0, "hunk_low_used", (size_t)&phunk_low_used }, + { 0x021B61D4, "hunk_size", (size_t)&phunk_size }, + { 0x021B61D8, "hunk_high_used", (size_t)&phunk_high_used }, + { 0x021B61E0, "cache_head", (size_t)&pcache_head }, + { 0x021B6238, "hunk_tempmark", (size_t)&phunk_tempmark }, + { 0x01E4DEC0, "mem_dbgfile", (size_t)&pmem_dbgfile }, + { 0x021B61CC, "mainzone", (size_t)&pmainzone }, + { 0x0266AEC0, "current_skill", (size_t)&pcurrent_skill }, + { 0x01FED1E0, "g_careerState", (size_t)&pg_careerState }, + { 0x01FED1D8, "gHostSpawnCount", (size_t)&pgHostSpawnCount }, + { 0x01E3A960, "g_pSaveGameCommentFunc", (size_t)&pg_pSaveGameCommentFunc }, + { 0x01E5C834, "g_LastScreenUpdateTime", (size_t)&pg_LastScreenUpdateTime }, + { 0x023FECB4, "scr_skipupdate", (size_t)&pscr_skipupdate }, + { 0x023FF0C0, "scr_centertime_off", (size_t)&pscr_centertime_off }, + + { 0x02699460, "serverinfo", (size_t)&pserverinfo }, + { 0x026995EC, "com_argc", (size_t)&pcom_argc }, + { 0x02699708, "com_argv", (size_t)&pcom_argv }, + { 0x02699840, "com_token", (size_t)&pcom_token }, + { 0x01FE1FA0, "com_ignorecolons", (size_t)&pcom_ignorecolons }, + { 0x01FE1FA4, "s_com_token_unget", (size_t)&ps_com_token_unget }, + { 0x02699600, "com_clientfallback", (size_t)&pcom_clientfallback }, + { 0x02699720, "com_gamedir", (size_t)&pcom_gamedir }, + { 0x02699C40, "com_cmdline", (size_t)&pcom_cmdline }, + + { 0x02699580, "gpszVersionString", (size_t)&pgpszVersionString }, + { 0x026995C0, "gpszProductString", (size_t)&pgpszProductString }, + + { 0x02699D44, "bigendien", (size_t)&pbigendien }, + { 0x026995E8, "BigShort", (size_t)&pBigShort }, + { 0x026995E0, "LittleShort", (size_t)&pLittleShort }, + { 0x0269970C, "BigLong", (size_t)&pBigLong }, + { 0x02699710, "LittleLong", (size_t)&pLittleLong }, + { 0x026995A0, "BigFloat", (size_t)&pBigFloat }, + { 0x02699560, "LittleFloat", (size_t)&pLittleFloat }, + + { 0x01FD3420, "cmd_argc", (size_t)&pcmd_argc }, + { 0x01FD3428, "cmd_argv", (size_t)&pcmd_argv }, + { 0x01FD366C, "cmd_args", (size_t)&pcmd_args }, + { 0x02699D7C, "cmd_source", (size_t)&pcmd_source }, + { 0x02699D74, "cmd_wait", (size_t)&pcmd_wait }, + { 0x01FD3670, "cmd_functions", (size_t)&pcmd_functions }, + { 0x02699D60, "cmd_text", (size_t)&pcmd_text }, + { 0x02699D84, "cmd_alias", (size_t)&pcmd_alias }, + + { 0x01FE501C, "cvar_vars", (size_t)&pcvar_vars }, + + { 0x026995E4, "loadcache", (size_t)&ploadcache }, + { 0x02699704, "loadbuf", (size_t)&ploadbuf }, + { 0x02699D40, "loadsize", (size_t)&ploadsize }, + + { 0x01FEC4C8, "g_fallbackLocalizationFiles", (size_t)&pg_fallbackLocalizationFiles }, + { 0x01FEC4E0, "s_pBaseDir", (size_t)&ps_pBaseDir }, + + { 0x01FEC6E8, "bLowViolenceBuild", (size_t)&pbLowViolenceBuild }, + + { 0x01FEC6EC, "g_pFileSystem", (size_t)&pg_pFileSystem }, + { 0x01FEC6E0, "g_pFileSystemModule", (size_t)&pg_pFileSystemModule }, + { 0x01FEC6E4, "g_FileSystemFactory", (size_t)&pg_FileSystemFactory }, + + { 0x01E4AAC0, "g_hfind", (size_t)&pg_hfind }, + { 0x01E4AAC8, "g_engfuncsExportedToDlls", (size_t)&pg_engfuncsExportedToDlls }, + + { 0x021C2260, "gszDisconnectReason", (size_t)&pgszDisconnectReason }, + { 0x021C27C0, "gszExtendedDisconnectReason", (size_t)&pgszExtendedDisconnectReason }, + { 0x02090C64, "gfExtendedError", (size_t)&pgfExtendedError }, + { 0x021C28F8, "g_bIsDedicatedServer", (size_t)&pg_bIsDedicatedServer }, + + { 0x021C2248, "giSubState", (size_t)&pgiSubState }, + { 0x021C2448, "giActive", (size_t)&pgiActive }, + { 0x02090C60, "giStateInfo", (size_t)&pgiStateInfo }, + + { 0x021C2380, "gEntityInterface", (size_t)&pgEntityInterface }, + { 0x021C28E0, "gNewDLLFunctions", (size_t)&pgNewDLLFunctions }, + { 0x01FF0638, "g_modfuncs", (size_t)&pg_modfuncs }, + + { 0x021C2480, "g_rgextdll", (size_t)&pg_rgextdll }, + { 0x02090C94, "g_iextdllMac", (size_t)&pg_iextdllMac }, + { 0x021C2900, "gmodinfo", (size_t)&pgmodinfo }, + { 0x02090C90, "gfBackground", (size_t)&pgfBackground }, + + + { 0x02699454, "con_debuglog", (size_t)&pcon_debuglog }, + { 0x02090C78, "g_bPrintingKeepAliveDots", (size_t)&pg_bPrintingKeepAliveDots }, + { 0x02090C80, "Launcher_ConsolePrintf", (size_t)&pLauncher_ConsolePrintf }, + + { 0x01E42EC4, "registry", (size_t)&pregistry }, + + { 0x0239B740, "outputbuf", (size_t)&poutputbuf }, + { 0x021CAB94, "sv_redirected", (size_t)&psv_redirected }, + { 0x021CAB80, "sv_redirectto", (size_t)&psv_redirectto }, + + { 0x01E464A0, "sv_rcon_minfailures", (size_t)&psv_rcon_minfailures }, + { 0x01E464CC, "sv_rcon_maxfailures", (size_t)&psv_rcon_maxfailures }, + { 0x01E464FC, "sv_rcon_minfailuretime", (size_t)&psv_rcon_minfailuretime }, + { 0x01E46528, "sv_rcon_banpenalty", (size_t)&psv_rcon_banpenalty }, + { 0x0208E828, "g_rgRconFailures", (size_t)&pg_rgRconFailures }, + + { 0x01E42FF8, "scr_downloading", (size_t)&pscr_downloading }, + + { 0x0208F7B8, "g_bCS_CZ_Flags_Initialized", (size_t)&pg_bCS_CZ_Flags_Initialized }, + { 0x0208F7AC, "g_bIsCZero", (size_t)&pg_bIsCZero }, + { 0x0208F7B4, "g_bIsCZeroRitual", (size_t)&pg_bIsCZeroRitual }, + { 0x0208F7B0, "g_bIsTerrorStrike", (size_t)&pg_bIsTerrorStrike }, + { 0x0208F7BC, "g_bIsTFC", (size_t)&pg_bIsTFC }, + { 0x0208F7C0, "g_bIsHL1", (size_t)&pg_bIsHL1 }, + { 0x0208F7A8, "g_bIsCStrike", (size_t)&pg_bIsCStrike }, + + { 0x01FD3E80, "gPAS", (size_t)&pgPAS }, + { 0x01FD3E84, "gPVS", (size_t)&pgPVS }, + { 0x01FD3A78, "gPVSRowBytes", (size_t)&pgPVSRowBytes }, + { 0x01FD3A80, "mod_novis", (size_t)&pmod_novis }, + + { 0x0229AE84, "fatbytes", (size_t)&pfatbytes }, + { 0x0229B2C0, "fatpvs", (size_t)&pfatpvs }, + { 0x0229B2A4, "fatpasbytes", (size_t)&pfatpasbytes }, + { 0x0229AEA0, "fatpas", (size_t)&pfatpas }, + + { 0x0208FAB8, "s_Steam3Server", (size_t)&ps_Steam3Server }, + { 0x0208FA58, "s_Steam3Client", (size_t)&ps_Steam3Client }, + + { 0x01E39F14, "sys_ticrate", (size_t)&psys_ticrate }, + { 0x01E39F3C, "sys_timescale", (size_t)&psys_timescale }, + { 0x01E39F60, "fps_max", (size_t)&pfps_max }, + { 0x01E39F84, "host_killtime", (size_t)&phost_killtime }, + { 0x01E39FA4, "sv_stats", (size_t)&psv_stats }, + { 0x01E39FC8, "fps_override", (size_t)&pfps_override }, + { 0x01E3A01C, "host_framerate", (size_t)&phost_framerate }, + { 0x01E3A128, "pausable", (size_t)&ppausable }, + + { 0x01E43F6C, "suitvolume", (size_t)&psuitvolume }, + + { 0x0208FAC0, "truepositions", (size_t)&ptruepositions }, + { 0x021C2B44, "sv_player", (size_t)&psv_player }, + { 0x01E4A328, "clcommands", (size_t)&pclcommands }, + { 0x0209064C, "g_balreadymoved", (size_t)&pg_balreadymoved }, + { 0x01E4A658, "sv_clcfuncs", (size_t)&psv_clcfuncs }, + { 0x020905C0, "s_LastFullUpdate", (size_t)&ps_LastFullUpdate }, + + { 0x01E4A3E0, "sv_edgefriction", (size_t)&psv_edgefriction }, + { 0x01E4A404, "sv_maxspeed", (size_t)&psv_maxspeed }, + { 0x01E4A42C, "sv_accelerate", (size_t)&psv_accelerate }, + { 0x01E4A3BC, "sv_footsteps", (size_t)&psv_footsteps }, + { 0x01E4A454, "sv_rollspeed", (size_t)&psv_rollspeed }, + { 0x01E4A47C, "sv_rollangle", (size_t)&psv_rollangle }, + + { 0x01E4A49C, "sv_unlag", (size_t)&psv_unlag }, + { 0x01E4A4C0, "sv_maxunlag", (size_t)&psv_maxunlag }, + { 0x01E4A4E8, "sv_unlagpush", (size_t)&psv_unlagpush }, + { 0x01E4A510, "sv_unlagsamples", (size_t)&psv_unlagsamples }, + { 0x01E4A398, "mp_consistency", (size_t)&pmp_consistency }, + { 0x01E4A568, "sv_voiceenable", (size_t)&psv_voiceenable }, + + { 0x02090648, "nofind", (size_t)&pnofind }, + + { 0x01E3F7F4, "pm_showclip", (size_t)&ppm_showclip }, + { 0x01E3F808, "player_mins", (size_t)&pplayer_mins }, + { 0x01E3F838, "player_maxs", (size_t)&pplayer_maxs }, + { 0x02004308, "pmove", (size_t)&ppmove }, + { 0x025E3F00, "movevars", (size_t)&pmovevars }, + + { 0x01FED51C, "vec3_origin", (size_t)&pvec3_origin }, + + { 0x02004980, "gMsgData", (size_t)&pgMsgData }, + { 0x01E3F9AC, "gMsgBuffer", (size_t)&pgMsgBuffer }, + { 0x02004B80, "gMsgEntity", (size_t)&pgMsgEntity }, + { 0x02004B84, "gMsgDest", (size_t)&pgMsgDest }, + { 0x02004B88, "gMsgType", (size_t)&pgMsgType }, + { 0x02004B8C, "gMsgStarted", (size_t)&pgMsgStarted }, + { 0x020043A8, "gMsgOrigin", (size_t)&pgMsgOrigin }, + { 0x02004B90, "idum", (size_t)&pidum }, + { 0x02004B9C, "g_groupop", (size_t)&pg_groupop }, + { 0x02004B98, "g_groupmask", (size_t)&pg_groupmask }, + { 0x025E39E0, "checkpvs", (size_t)&pcheckpvs }, + { 0x025E3DE0, "c_invis", (size_t)&pc_invis }, + { 0x025E39CC, "c_notvis", (size_t)&pc_notvis }, + + { 0x0208F7E0, "vec_origin", (size_t)&pvec_origin }, + + { 0x025DFD94, "r_visframecount", (size_t)&pr_visframecount }, + + { 0x02052A48, "cache_hull_hitgroup", (size_t)&pcache_hull_hitgroup }, + { 0x0206FB60, "cache_hull", (size_t)&pcache_hull }, + { 0x0201CDC8, "cache_planes", (size_t)&pcache_planes }, + + { 0x0206FB50, "pstudiohdr", (size_t)&ppstudiohdr }, + { 0x0200A398, "studio_hull", (size_t)&pstudio_hull }, + { 0x02052C48, "studio_hull_hitgroup", (size_t)&pstudio_hull_hitgroup }, + { 0x0200C998, "studio_planes", (size_t)&pstudio_planes }, + { 0x02052E48, "studio_clipnodes", (size_t)&pstudio_clipnodes }, + { 0x0206E908, "rgStudioCache", (size_t)&prgStudioCache }, + { 0x0206FB54, "r_cachecurrent", (size_t)&pr_cachecurrent }, + { 0x02016DC4, "nCurrentHull", (size_t)&pnCurrentHull }, + { 0x0200A384, "nCurrentPlane", (size_t)&pnCurrentPlane }, + { 0x025DD0E0, "bonetransform", (size_t)&pbonetransform }, + { 0x01E42284, "r_cachestudio", (size_t)&pr_cachestudio }, + { 0x01E424E8, "g_pSvBlendingAPI", (size_t)&pg_pSvBlendingAPI }, + { 0x01E424E0, "svBlending", (size_t)&psvBlending }, + { 0x01E424D0, "server_studio_api", (size_t)&pserver_studio_api }, + { 0x025DEEE0, "rotationmatrix", (size_t)&protationmatrix }, + + { 0x021B1568, "box_hull", (size_t)&pbox_hull, 1 }, + { 0x021B1540, "beam_hull", (size_t)&pbeam_hull }, + { 0x021B1590, "box_clipnodes", (size_t)&pbox_clipnodes, 1 }, + { 0x021B15C0, "box_planes", (size_t)&pbox_planes, 1 }, + { 0x021B14C8, "beam_planes", (size_t)&pbeam_planes }, + { 0x021B6240, "sv_areanodes", (size_t)&psv_areanodes }, + { 0x021B6640, "sv_numareanodes", (size_t)&psv_numareanodes }, + + + { 0x02004310, "g_contentsresult", (size_t)&pg_contentsresult }, + { 0x025E3E00, "box_hull", (size_t)&pbox_hull_0, 2 }, + { 0x025E3E40, "box_clipnodes", (size_t)&pbox_clipnodes_0, 2 }, + { 0x025E3E80, "box_planes", (size_t)&pbox_planes_0, 2 }, + + { 0x01E48EF0, "sv_maxvelocity", (size_t)&psv_maxvelocity }, + { 0x01E48EC4, "sv_gravity", (size_t)&psv_gravity }, + { 0x01E48F34, "sv_bounce", (size_t)&psv_bounce }, + { 0x01E48F14, "sv_stepsize", (size_t)&psv_stepsize }, + { 0x01E48E78, "sv_friction", (size_t)&psv_friction }, + { 0x01E48EA0, "sv_stopspeed", (size_t)&psv_stopspeed }, + + { 0x021C2B48, "g_moved_from", (size_t)&pg_moved_from }, + { 0x021C2B4C, "sv_numareanodes", (size_t)&pg_moved_edict }, + + { 0x021C2B50, "c_yes", (size_t)&pc_yes }, + { 0x021C2B54, "c_no", (size_t)&pc_no }, + + { 0x020042AC, "net_thread_initialized", (size_t)&pnet_thread_initialized }, + { 0x01E3E8DC, "net_address", (size_t)&pnet_address }, + { 0x01E3E900, "ipname", (size_t)&pipname }, + { 0x01E3E968, "defport", (size_t)&pdefport }, + { 0x01E3E98C, "ip_clientport", (size_t)&pip_clientport }, + { 0x01E3E9B4, "clientport", (size_t)&pclientport }, + { 0x01E3EB34, "net_sleepforever", (size_t)&pnet_sleepforever }, + { 0x01FF2B60, "loopbacks", (size_t)&ploopbacks }, + { 0x01FF2AE8, "g_pLagData", (size_t)&pg_pLagData }, + { 0x020042D8, "gFakeLag", (size_t)&pgFakeLag }, + { 0x020042FC, "net_configured", (size_t)&pnet_configured }, + { 0x025F4020, "net_message", (size_t)&pnet_message }, + { 0x025F4040, "net_local_adr", (size_t)&pnet_local_adr }, + { 0x02604060, "net_from", (size_t)&pnet_from }, + { 0x020042BC, "noip", (size_t)&pnoip }, + { 0x01E3E9D8, "clockwindow", (size_t)&pclockwindow }, + + { 0x020042B0, "use_thread", (size_t)&puse_thread }, + + { 0x025F4000, "in_message", (size_t)&pin_message }, + { 0x025F3FC0, "in_from", (size_t)&pin_from }, + + { 0x020042C0, "ip_sockets", (size_t)&pip_sockets }, + { 0x01E3E924, "iphostport", (size_t)&piphostport }, + { 0x01E3E944, "hostport", (size_t)&phostport }, + { 0x01E3EA04, "multicastport", (size_t)&pmulticastport }, + { 0x01E3EA70, "fakelag", (size_t)&pfakelag }, + { 0x01E3EA94, "fakeloss", (size_t)&pfakeloss }, + + { 0x01E3EAB4, "net_graph", (size_t)&pnet_graph }, + { 0x01E3EADC, "net_graphwidth", (size_t)&pnet_graphwidth }, + { 0x01E3EAFC, "net_scale", (size_t)&pnet_scale }, + { 0x01E3EB20, "net_graphpos", (size_t)&pnet_graphpos }, + { 0x025F4060, "net_message_buffer", (size_t)&pnet_message_buffer }, + { 0x025E3FC0, "in_message_buf", (size_t)&pin_message_buf }, + +#ifdef _WIN32 + { 0x025F3FE0, "net_local_ipx_adr", (size_t)&pnet_local_ipx_adr }, + { 0x020042B8, "noipx", (size_t)&pnoipx }, + { 0x01E3EA28, "ipx_hostport", (size_t)&pipx_hostport }, + { 0x01E3EA50, "ipx_clientport", (size_t)&pipx_clientport }, + { 0x020042CC, "ipx_sockets", (size_t)&pipx_sockets }, +#endif // _WIN32 + { 0x02604080, "gNetSplit", (size_t)&pgNetSplit }, + { 0x020042E8, "messages", (size_t)&pmessages }, + { 0x020042F4, "normalqueue", (size_t)&pnormalqueue }, + + { 0x02605040, "gDownloadFile", (size_t)&pgDownloadFile }, + + { 0x02605140, "net_drop", (size_t)&pnet_drop }, + { 0x01E3E00C, "net_log", (size_t)&pnet_log }, + { 0x01E3E034, "net_showpackets", (size_t)&pnet_showpackets }, + { 0x01E3E058, "net_showdrop", (size_t)&pnet_showdrop }, + { 0x01E3E080, "net_drawslider", (size_t)&pnet_drawslider }, + { 0x01E3E0A4, "net_chokeloopback", (size_t)&pnet_chokeloopback }, + { 0x01E3E0D8, "sv_filetransfercompression", (size_t)&psv_filetransfercompression }, + { 0x01E3E110, "sv_filetransfermaxsize", (size_t)&psv_filetransfermaxsize }, + +#ifdef _WIN32 + { 0x02090C88, "g_PerfCounterInitialized", (size_t)&pg_PerfCounterInitialized }, + { 0x021C2460, "g_PerfCounterMutex", (size_t)&pg_PerfCounterMutex }, + + { 0x021C2454, "g_PerfCounterShiftRightAmount", (size_t)&pg_PerfCounterShiftRightAmount }, + { 0x021C28C0, "g_PerfCounterSlice", (size_t)&pg_PerfCounterSlice }, + { 0x02090C68, "g_CurrentTime", (size_t)&pg_CurrentTime }, + { 0x02090C70, "g_StartTime", (size_t)&pg_StartTime }, + + { 0x01E4E98C, "g_FPUCW_Mask_Prec_64Bit", (size_t)&pg_FPUCW_Mask_Prec_64Bit }, + { 0x01E4E990, "g_FPUCW_Mask_Prec_64Bit_2", (size_t)&pg_FPUCW_Mask_Prec_64Bit_2 }, + { 0x01E4E988, "g_FPUCW_Mask_ZeroDiv_OFlow", (size_t)&pg_FPUCW_Mask_Round_Trunc }, + { 0x01E4E984, "g_FPUCW_Mask_OFlow", (size_t)&pg_FPUCW_Mask_Round_Up }, + + { 0x021C2244, "g_WinNTOrHigher", (size_t)&pg_WinNTOrHigher }, + { 0x020914E4, "g_bIsWin95", (size_t)&pg_bIsWin95 }, + { 0x020914E8, "g_bIsWin98", (size_t)&pg_bIsWin98 }, +#endif // _WIN32 + + { 0x02605180, "loadmodel", (size_t)&ploadmodel }, + { 0x02605160, "loadname", (size_t)&ploadname }, + { 0x026051A0, "mod_known", (size_t)&pmod_known }, + { 0x02605144, "mod_numknown", (size_t)&pmod_numknown }, + { 0x026671A0, "mod_base", (size_t)&pmod_base }, + { 0x01FF062C, "wadpath", (size_t)&pwadpath }, + { 0x01FF0630, "tested", (size_t)&ptested }, + { 0x01FF0634, "ad_enabled", (size_t)&pad_enabled }, + { 0x026671C0, "ad_wad", (size_t)&pad_wad }, + { 0x01FED528, "mod_known_info", (size_t)&pmod_known_info }, + + { 0x02095B48, "lumpinfo", (size_t)&plumpinfo }, + { 0x02095B4C, "nTexLumps", (size_t)&pnTexLumps }, + { 0x021C2040, "texfiles", (size_t)&ptexfiles }, + { 0x02095B44, "nTexFiles", (size_t)&pnTexFiles }, + { 0x021B7660, "texgammatable", (size_t)&ptexgammatable }, + { 0x025DFCE4, "r_notexture_mip", (size_t)&pr_notexture_mip }, + { 0x021C2020, "nummiptex", (size_t)&pnummiptex }, + { 0x021BA020, "miptex", (size_t)&pmiptex }, + + { 0x01E41A30, "r_wadtextures", (size_t)&pr_wadtextures }, + + { 0x01E42270, "r_dointerp", (size_t)&pr_dointerp }, + { 0x025DFE40, "r_origin", (size_t)&pr_origin }, + + { 0x01E415BC, "r_pixbytes", (size_t)&pr_pixbytes }, + { 0x01E43090, "gl_vsync", (size_t)&pgl_vsync }, + { 0x023FF0D0, "scr_con_current", (size_t)&pscr_con_current }, + + + { 0x0208F7EC, "g_ServerRemoteAccess", (size_t)&pg_ServerRemoteAccess }, + + { 0x01FED1E8, "cpuPercent", (size_t)&pcpuPercent }, + { 0x01FED1D4, "startTime", (size_t)&pstartTime }, + { 0x01FED1E4, "g_bMajorMapChange", (size_t)&pg_bMajorMapChange }, + { 0x01E3A97C, "voice_recordtofile", (size_t)&pvoice_recordtofile }, + { 0x01E3A9A8, "voice_inputfromfile", (size_t)&pvoice_inputfromfile }, + { 0x01E3B250, "gTitleComments", (size_t)&pgTitleComments }, + { 0x01E3A9D8, "gGameHeaderDescription", (size_t)&pgGameHeaderDescription }, + { 0x01E3AAA0, "gSaveHeaderDescription", (size_t)&pgSaveHeaderDescription }, + { 0x01E3ABB0, "gAdjacencyDescription", (size_t)&pgAdjacencyDescription }, + { 0x01E3AC20, "gEntityTableDescription", (size_t)&pgEntityTableDescription }, + { 0x01E3AC80, "gLightstyleDescription", (size_t)&pgLightstyleDescription }, + { 0x01E3ACB0, "gHostMap", (size_t)&pgHostMap }, + { 0x01FED208, "g_iQuitCommandIssued", (size_t)&pg_iQuitCommandIssued }, + { 0x01FED20C, "g_pPostRestartCmdLineArgs", (size_t)&pg_pPostRestartCmdLineArgs }, + + { 0x021CABA0, "g_rg_sv_challenges", (size_t)&pg_rg_sv_challenges }, + + { 0x0239BCC0, "g_svdeltacallback", (size_t)&pg_svdeltacallback }, + + { 0x01FED4D0, "_ZL11rateChecker", (size_t)&prateChecker }, + + { 0x01FEC7F4, "gp_hpak_queue", (size_t)&pgp_hpak_queue }, + { 0x01FEC7F8, "hash_pack_dir", (size_t)&phash_pack_dir }, + { 0x0266AFB0, "hash_pack_header", (size_t)&phash_pack_header }, + + { 0x020891D8, "firstLog", (size_t)&pfirstLog }, + + { 0x01E4C6C4, "game", (size_t)&pgame }, + { 0x01E4BB44, "eng", (size_t)&peng }, + { 0x021B1468, "wads", (size_t)&pwads }, + { 0x01FF06B0, "g_module", (size_t)&pg_module }, + + { 0x020914E0, "dedicated", (size_t)&pdedicated }, + { 0x020914E4, "g_bIsWin95", (size_t)&pg_bIsWin95 }, + { 0x020914E8, "g_bIsWin98", (size_t)&pg_bIsWin98 }, + { 0x020914F8, "g_flLastSteamProgressUpdateTime", (size_t)&pg_flLastSteamProgressUpdateTime }, + { 0x01E4B3E0, "szCommonPreloads", (size_t)&pszCommonPreloads }, + { 0x01E4B3F0, "szReslistsBaseDir", (size_t)&pszReslistsBaseDir }, + { 0x01E4B3FC, "szReslistsExt", (size_t)&pszReslistsExt }, + + { 0x02095C98, "g_InitTracker", (size_t)&pg_InitTracker }, + +#ifndef _WIN32 + { 0x0, "gHasMMXTechnology", (size_t)&pgHasMMXTechnology }, +#endif + +#endif // Data_References_region + + { NULL, NULL, NULL }, +}; diff --git a/rehlds/hookers/engine.h b/rehlds/hookers/engine.h new file mode 100644 index 0000000..b28d161 --- /dev/null +++ b/rehlds/hookers/engine.h @@ -0,0 +1,84 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "common.h" +#include "keys.h" +#include "decal.h" +#include "delta.h" +#include "server.h" +#include "sys_dll.h" +#include "sys_dll2.h" +#include "sys_engine.h" +#include "zone.h" +#include "client.h" +#include "cmd.h" +#include "cvar.h" +#include "filesystem_internal.h" +#include "mem.h" +#include "unicode_strtools.h" +#include "host.h" +#include "filesystem_.h" +#include "info.h" +#include "iregistry.h" +#include "cmodel.h" +#include "model_rehlds.h" +#include "sv_log.h" +#include "sv_steam3.h" +#include "host_cmd.h" +#include "sv_user.h" +#include "pmove.h" +#include "pmovetst.h" +#include "pr_edict.h" +#include "pr_cmds.h" +#include "mathlib_e.h" +#include "world.h" +#include "sv_phys.h" +#include "sv_move.h" +#include "sv_pmove.h" +#include "studio_rehlds.h" +#include "net_ws.h" +#include "net_chan.h" + + + + +#include "tmessage.h" +#include "traceinit.h" +#include "wad.h" +#include "textures.h" +#include "vid_null.h" +#include "l_studio.h" +#include "crc.h" +#include "sv_remoteaccess.h" +#include "sv_upld.h" +#include "com_custom.h" +#include "hashpak.h" +#include "ipratelimit.h" +#include "ipratelimitWrapper.h" +#include "savegame_version.h" +#include "sys_linuxwnd.h" diff --git a/rehlds/hookers/hooker.cpp b/rehlds/hookers/hooker.cpp new file mode 100644 index 0000000..bf54d54 --- /dev/null +++ b/rehlds/hookers/hooker.cpp @@ -0,0 +1,184 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +HIDDEN Module g_EngineModule = { NULL, NULL, NULL, NULL }; + +extern const size_t g_BaseOffset; +extern FunctionHook g_FunctionHooks[]; +extern AddressRef g_FunctionRefs[]; +extern AddressRef g_DataRefs[]; + +void *GetOriginalFuncAddrOrDie(const char *funcName) +{ + for (FunctionHook *cfh = &g_FunctionHooks[0]; cfh->symbolName; cfh++) + { + if (!strcmp(cfh->symbolName, funcName)) + return (void*) cfh->originalAddress; + } + + rehlds_syserror("%s: Could not find function '%s'", __FUNCTION__, funcName); + return NULL; +} + +void *GetOriginalFuncAddrOrDefault(const char *funcName, void *def) +{ + for (FunctionHook *cfh = &g_FunctionHooks[0]; cfh->symbolName; cfh++) + { + if (!strcmp(cfh->symbolName, funcName)) + return (void*)cfh->originalAddress; + } + + return def; +} + +void *GetFuncRefAddrOrDie(const char *funcName) +{ + for (AddressRef *cfh = &g_FunctionRefs[0]; cfh->symbolName; cfh++) + { + if (!strcmp(cfh->symbolName, funcName)) + return (void*)cfh->originalAddress; + } + + rehlds_syserror("%s: Could not find function '%s'", __FUNCTION__, funcName); + return NULL; +} + +void *GetFuncRefAddrOrDefault(const char *funcName, void *def) +{ + for (AddressRef *cfh = &g_FunctionRefs[0]; cfh->symbolName; cfh++) + { + if (!strcmp(cfh->symbolName, funcName)) + return (void*)cfh->originalAddress; + } + + return def; +} + +int HookEngine(size_t addr) +{ + if (addr == NULL || !FindModuleByAddress(addr, &g_EngineModule)) + { + return (FALSE); + } + + // Find all addresses + bool success = true; + + AddressRef *refData = g_DataRefs; + while (refData->symbolName != NULL) + { + if (!GetAddress(&g_EngineModule, (Address*)refData, g_BaseOffset)) + { +#if _DEBUG + printf("%s: symbol not found \"%s\", symbol index: %i\n", __FUNCTION__, refData->symbolName, refData->symbolIndex); + success = false; +#endif + } + refData++; + } + + AddressRef *refFunc = g_FunctionRefs; + while (refFunc->symbolName != NULL) + { + if (!GetAddress(&g_EngineModule, (Address*)refFunc, g_BaseOffset)) + { +#if _DEBUG + printf("%s: symbol not found \"%s\", symbol index: %i\n", __FUNCTION__, refData->symbolName, refData->symbolIndex); + success = false; +#endif + } + refFunc++; + } + + FunctionHook *hookFunc = g_FunctionHooks; + while (hookFunc->handlerFunc != NULL) + { + if (!GetAddress(&g_EngineModule, (Address*)hookFunc, g_BaseOffset)) + { +#if _DEBUG + printf("%s: symbol not found \"%s\", symbol index: %i\n", __FUNCTION__, refData->symbolName, refData->symbolIndex); + success = false; +#endif + } + hookFunc++; + } + + if (!success) + { +#if _DEBUG + printf("%s: failed to hook engine!\n", __FUNCTION__); +#endif + return (FALSE); + } + +#ifdef _WIN32 + Module hlds_exe; + if (!FindModuleByName("hlds.exe", &hlds_exe)) + return (FALSE); + + TestSuite_Init(&g_EngineModule, &hlds_exe, g_FunctionRefs); +#endif + + + refData = g_DataRefs; + while (refData->addressRef != NULL) + { + if (!FindDataRef(&g_EngineModule, refData)) + return (FALSE); + refData++; + } + + refFunc = g_FunctionRefs; + while (refFunc->addressRef != NULL) + { + if (!FindDataRef(&g_EngineModule, refFunc)) + return (FALSE); + refFunc++; + } + + // Actually hook all things + if (!g_RehldsRuntimeConfig.disableAllHooks) + { + hookFunc = g_FunctionHooks; + while (hookFunc->handlerFunc != NULL) + { + if (!HookFunction(&g_EngineModule, hookFunc)) + return (FALSE); + hookFunc++; + } + } + +#ifdef _WIN32 + Rehlds_Debug_Init(&g_EngineModule); +#endif + + return (TRUE); +} diff --git a/rehlds/hookers/hooker.h b/rehlds/hookers/hooker.h new file mode 100644 index 0000000..937007a --- /dev/null +++ b/rehlds/hookers/hooker.h @@ -0,0 +1,8 @@ +#pragma once + +#include "osconfig.h" + +extern void *GetOriginalFuncAddrOrDie(const char *funcName); +extern void *GetOriginalFuncAddrOrDefault(const char *funcName, void *def); +extern void *GetFuncRefAddrOrDie(const char *funcName); +extern void *GetFuncRefAddrOrDefault(const char *funcName, void *def); diff --git a/rehlds/hookers/main.cpp b/rehlds/hookers/main.cpp new file mode 100644 index 0000000..e68c643 --- /dev/null +++ b/rehlds/hookers/main.cpp @@ -0,0 +1,120 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + + +int HookEngine(size_t addr); + + +IBaseInterface* CreateFileSystemInterface(void); +InterfaceReg iface = InterfaceReg(CreateFileSystemInterface, "VFileSystem009"); + +#ifdef _WIN32 +#define ORIGINAL_ENGINE_DLL_NAME "swds.dll" +#define ORIGINAL_FILESYSTEM_DLL_NAME "filesystem_stdio2.dll" +#else +#define ORIGINAL_ENGINE_DLL_NAME "engine_i486.so" +#define ORIGINAL_FILESYSTEM_DLL_NAME "filesystem_stdio2.so" +#endif + +CSysModule *g_pOriginalFileSystemModule = NULL; +CreateInterfaceFn g_OriginalFileSystemFactory = NULL; +IFileSystem *g_pOriginalFileSystem = NULL; + + +IBaseInterface *CreateFileSystemInterface(void) +{ + if (g_pOriginalFileSystem) + return g_pOriginalFileSystem; + + if (g_pOriginalFileSystemModule) + { + g_OriginalFileSystemFactory = Sys_GetFactory(g_pOriginalFileSystemModule); + if (g_OriginalFileSystemFactory) + { + int returnCode = 0; + g_pOriginalFileSystem = reinterpret_cast(g_OriginalFileSystemFactory(FILESYSTEM_INTERFACE_VERSION, &returnCode)); + return g_pOriginalFileSystem; + } + } + + return NULL; +} + +#ifdef _WIN32 + +// DLL entry point +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + g_RehldsRuntimeConfig.parseFromCommandLine(GetCommandLineA()); + +#ifdef HOOK_ENGINE + size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_ENGINE_DLL_NAME, CREATEINTERFACE_PROCNAME); + HookEngine(addr); + + g_pOriginalFileSystemModule = Sys_LoadModule(ORIGINAL_FILESYSTEM_DLL_NAME); +#endif // HOOK_ENGINE + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + if (g_pOriginalFileSystemModule) + { + Sys_UnloadModule(g_pOriginalFileSystemModule); + g_pOriginalFileSystemModule = NULL; + g_OriginalFileSystemFactory = NULL; + g_pOriginalFileSystem = NULL; + } + } + return TRUE; +} + +#else // _WIN32 + +void __attribute__((constructor)) DllMainLoad() +{ + size_t addr = (size_t)Sys_GetProcAddress(ORIGINAL_ENGINE_DLL_NAME, CREATEINTERFACE_PROCNAME); + HookEngine(addr); + + g_pOriginalFileSystemModule = Sys_LoadModule(ORIGINAL_FILESYSTEM_DLL_NAME); +} + +void __attribute__((destructor)) DllMainUnload() +{ + if (g_pOriginalFileSystemModule) + { + Sys_UnloadModule(g_pOriginalFileSystemModule); + g_pOriginalFileSystemModule = NULL; + g_OriginalFileSystemFactory = NULL; + g_pOriginalFileSystem = NULL; + } +} + +#endif // _WIN32 diff --git a/rehlds/hookers/main_swds.cpp b/rehlds/hookers/main_swds.cpp new file mode 100644 index 0000000..d470c6b --- /dev/null +++ b/rehlds/hookers/main_swds.cpp @@ -0,0 +1,68 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifdef _WIN32 + +// DLL entry point +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + g_RehldsRuntimeConfig.parseFromCommandLine(GetCommandLineA()); + +#ifdef _WIN32 + Module hlds_exe; + if (!FindModuleByName("hlds.exe", &hlds_exe)) + return (FALSE); + + TestSuite_Init(NULL, &hlds_exe, NULL); +#endif + + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + + } + return TRUE; +} + +#else // _WIN32 + +void __attribute__((constructor)) DllMainLoad() +{ + +} + +void __attribute__((destructor)) DllMainUnload() +{ + +} + +#endif // _WIN32 diff --git a/rehlds/hookers/memory.cpp b/rehlds/hookers/memory.cpp new file mode 100644 index 0000000..80824d1 --- /dev/null +++ b/rehlds/hookers/memory.cpp @@ -0,0 +1,768 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +#ifdef _WIN32 + +bool HIDDEN FindModuleByAddress(size_t addr, Module *module) +{ + if (!module) + return false; + + MEMORY_BASIC_INFORMATION mem; + VirtualQuery((void *)addr, &mem, sizeof(mem)); + + IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER*)mem.AllocationBase; + IMAGE_NT_HEADERS *pe = (IMAGE_NT_HEADERS*)((unsigned long)dos + (unsigned long)dos->e_lfanew); + + if (pe->Signature != IMAGE_NT_SIGNATURE) + return false; + + module->base = (size_t)mem.AllocationBase; + module->size = (size_t)pe->OptionalHeader.SizeOfImage; + module->end = module->base + module->size - 1; + module->handle = NULL; + + ProcessModuleData(module); + + return true; +} +bool HIDDEN FindModuleByName(const char *moduleName, Module *module) +{ + if (!moduleName || !*moduleName || !module) + return false; + + HANDLE hProcess = GetCurrentProcess(); + HMODULE hModuleDll = GetModuleHandle(moduleName); + + if (!hProcess || !hModuleDll) + return false; + + MODULEINFO moduleInfo; + GetModuleInformation(hProcess, hModuleDll, &moduleInfo, sizeof(moduleInfo)); + + module->base = (size_t)moduleInfo.lpBaseOfDll; + module->size = (size_t)moduleInfo.SizeOfImage; + module->end = module->base + module->size - 1; + module->handle = NULL; + + ProcessModuleData(module); + + return true; +} + +#else // _WIN32 + +static Section _initialSection = {}; // will hold all process memory sections + +// Parses /proc/PID/maps file for the process memory sections. +bool HIDDEN ReloadProcessMemoryInfo() +{ + Section *section = _initialSection.next; + while (section != NULL) + { + Section *next = section->next; + delete section; + section = next; + } + _initialSection.next = NULL; + + char file[_MAX_FNAME]; + char buffer[2048]; + + pid_t pid = getpid(); + snprintf(file, sizeof(file), "/proc/%d/maps", pid); + file[sizeof(file)-1] = 0; + + FILE *fp = fopen(file, "rt"); + if (!fp) + return false; + + static char mbuffer[65536]; + setbuffer(fp, mbuffer, sizeof(mbuffer)); + + size_t length = 0; + size_t start, end, size; + char accessProtection[5]; + int inode; + int fields; + section = &_initialSection; + while (!feof(fp)) + { + if (fgets(buffer, sizeof(buffer), fp) == NULL) + break; + + fields = sscanf(buffer, "%lx-%lx %4s %*s %*s %d %255s", &start, &end, accessProtection, &inode, file); + //printf("%lx-%lx %4s %d %s\n", start, end, accessProtection, inode, fields > 4 ? file : ""); + if (fields < 4) + return false; + + section->next = new Section; + section = section->next; + section->next = NULL; + section->start = start; + section->end = end; + section->size = end - start; + section->protection = 0; + if (accessProtection[0] == 'r') section->protection |= PROT_READ; + if (accessProtection[1] == 'w') section->protection |= PROT_WRITE; + if (accessProtection[2] == 'x') section->protection |= PROT_EXEC; + section->inode = inode; + if (fields > 4) + { + strncpy(section->filename, file, _MAX_FNAME); + section->filename[_MAX_FNAME - 1] = 0; + section->namelen = strlen(section->filename); + } + else + { + section->filename[0] = 0; + section->namelen = 0; + } + } + + fclose(fp); + + return true; +} +// Finds section by the address. +Section* HIDDEN FindSectionByAddress(size_t addr) +{ + Section *section = _initialSection.next; + while (section != NULL) + { + if (section->start <= addr && addr < section->end) + break; + section = section->next; + } + return section; +} +// Finds section by the file name. +Section* HIDDEN FindSectionByName(const char *moduleName) +{ + int len = strlen(moduleName); + Section *section = _initialSection.next; + while (section != NULL) + { + if (len < section->namelen && + section->filename[section->namelen - len - 1] == '/' && + !_stricmp(section->filename + section->namelen - len, moduleName)) + break; + section = section->next; + } + return section; +} +// Finds section by the address. +Section* HIDDEN GetSectionByAddress(size_t addr) +{ + Section *section = FindSectionByAddress(addr); + if (section == NULL) + { + // Update sections info + if (!ReloadProcessMemoryInfo()) + return NULL; + section = FindSectionByAddress(addr); + } + return section; +} +// Finds section by the file name. +Section* HIDDEN GetSectionByName(const char *moduleName) +{ + Section *section = FindSectionByName(moduleName); + if (section == NULL) + { + // Update sections info + if (!ReloadProcessMemoryInfo()) + return NULL; + section = FindSectionByName(moduleName); + } + return section; +} +// Fills module structure by info from the sections. Should be supplied with the first module section. +bool HIDDEN FillModule(Section *section, Module *module) +{ + if (!section || !module) + return false; + + size_t base = section->start; + size_t end = section->end; + char *filename = section->filename; + + // Iterate thru next sections to find the end + section = section->next; + while (section != NULL) + { + if (end != section->start) // not adjacent sections - we don't support this + return false; + else if (section->inode == 0) // end of the module memory + break; + else + end = section->end; + section = section->next; + } + + //printf("%s: %lx-%lx\n", filename, base, end); + + module->base = base; + module->size = end - base; + module->end = module->base + module->size - 1; + module->handle = (size_t)dlopen(filename, RTLD_NOW); // lock from unloading + + ProcessModuleData(module); + + return true; +} + +bool HIDDEN FindModuleByAddress(size_t addr, Module *module) +{ + if (!module) + return false; + + Section *section = GetSectionByAddress(addr); + if (section == NULL) + return false; + + if (section->filename[0] != '/') // should point to a real file + return false; + + // Start over with the name to find module start + return FindModuleByName(section->filename + 1, module); +} +bool HIDDEN FindModuleByName(const char *moduleName, Module *module) +{ + if (!moduleName || !*moduleName || !module) + return false; + + Section *section = GetSectionByName(moduleName); + if (section == NULL) + return false; + + return FillModule(section, module); +} + +#endif // _WIN32 + + +#ifdef _WIN32 + +inline size_t HIDDEN FindSymbol(Module *module, const char* symbolName, int index) +{ + return NULL; +} + +#else // _WIN32 + +size_t HIDDEN FindSymbol(Module *module, const char* symbolName, int index) +{ + int i; + link_map *dlmap; + struct stat dlstat; + int dlfile; + uintptr_t map_base; + Elf32_Ehdr *file_hdr; + Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr; + Elf32_Sym *symtab; + const char *shstrtab, *strtab; + uint16_t section_count; + uint32_t symbol_count; + size_t address; + + // If index > 0 then we shouldn't use dlsym, cos it will give wrong result + if (index == 0) + { + address = (size_t)dlsym((void *)module->handle, symbolName); + if (address != NULL) + return address; + } + + dlmap = (struct link_map *)module->handle; + symtab_hdr = NULL; + strtab_hdr = NULL; + + dlfile = open(dlmap->l_name, O_RDONLY); + if (dlfile == -1 || fstat(dlfile, &dlstat) == -1) + { + close(dlfile); + return NULL; + } + + // Map library file into memory + file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0); + map_base = (uintptr_t)file_hdr; + close(dlfile); + if (file_hdr == MAP_FAILED) + { + return NULL; + } + + if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF) + { + munmap(file_hdr, dlstat.st_size); + return NULL; + } + + sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff); + section_count = file_hdr->e_shnum; + // Get ELF section header string table + shstrtab_hdr = §ions[file_hdr->e_shstrndx]; + shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset); + + // Iterate sections while looking for ELF symbol table and string table + for (uint16_t i = 0; i < section_count; i++) + { + Elf32_Shdr &hdr = sections[i]; + const char *section_name = shstrtab + hdr.sh_name; + //printf("Seg[%d].name = '%s'\n", i, section_name); + + if (strcmp(section_name, ".symtab") == 0) + { + symtab_hdr = &hdr; + } + else if (strcmp(section_name, ".strtab") == 0) + { + strtab_hdr = &hdr; + } + } + + if (symtab_hdr == NULL || strtab_hdr == NULL) + { + munmap(file_hdr, dlstat.st_size); + return NULL; + } + + symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset); + strtab = (const char *)(map_base + strtab_hdr->sh_offset); + symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize; + + int mangleNameLength; + int mangleNameLastLength = 1024; // Is it enouph? + + // If index is 0 then we need to take first entry + if (index == 0) index++; + + // Iterate symbol table + int match = 1; + for (uint32_t i = 0; i < symbol_count; i++) + { + Elf32_Sym &sym = symtab[i]; + unsigned char sym_type = ELF32_ST_TYPE(sym.st_info); + const char *sym_name = strtab + sym.st_name; + + // Skip symbols that are undefined or do not refer to functions or objects + if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT)) + { + continue; + } + + if (strcmp(sym_name, symbolName) == 0) + { + if (match == index) + { + address = (size_t)(dlmap->l_addr + sym.st_value); + break; + } + else + { + match++; + } + } + // Try to find lowest length mangled name then + if (sym_name[0] == '_' && sym_name[1] == 'Z' && strstr(sym_name + 2, symbolName) != NULL && (mangleNameLength = strlen(sym_name)) < mangleNameLastLength) + { + mangleNameLastLength = mangleNameLength; + address = (size_t)(dlmap->l_addr + sym.st_value); +#ifdef _DEBUG + printf("FindSymbol (mangled name): symbol: \"%s\", address: %lx\n", sym_name, address); +#endif + } + } + + munmap(file_hdr, dlstat.st_size); + +#ifdef _DEBUG + printf("FindSymbol (elf): symbol: \"%s\", address: %lx\n", symbolName, address); +#endif + + return address; +} + +#endif // _WIN32 + +#ifdef _WIN32 +void ProcessModuleData(Module *module) +{ + int i = 0; + PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)module->base; + if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { + rehlds_syserror(__FUNCTION__ ": Invalid DOS header signature"); + return; + } + + PIMAGE_NT_HEADERS NTHeaders = (PIMAGE_NT_HEADERS)((size_t)module->base + dosHeader->e_lfanew); + if (NTHeaders->Signature != 0x4550) { + rehlds_syserror(__FUNCTION__ ": Invalid NT header signature"); + return; + } + + PIMAGE_SECTION_HEADER cSection = (PIMAGE_SECTION_HEADER)((size_t)(&NTHeaders->OptionalHeader) + NTHeaders->FileHeader.SizeOfOptionalHeader); + + PIMAGE_SECTION_HEADER CodeSection = NULL; + + for (i = 0; i < NTHeaders->FileHeader.NumberOfSections; i++, cSection++) { + if (cSection->VirtualAddress == NTHeaders->OptionalHeader.BaseOfCode) + CodeSection = cSection; + } + + if (CodeSection == NULL) { + rehlds_syserror(__FUNCTION__ ": Code section not found"); + return; + } + + module->codeSection.start = (uint32_t)module->base + CodeSection->VirtualAddress; + module->codeSection.size = CodeSection->Misc.VirtualSize; + module->codeSection.end = module->codeSection.start + module->codeSection.size; + module->codeSection.next = NULL; +} +#else // _WIN32 +void ProcessModuleData(Module *module) +{ + +} +#endif + +#ifdef _WIN32 + +static DWORD oldPageProtection; + +inline bool HIDDEN EnablePageWrite(size_t addr, size_t size) +{ + return VirtualProtect((void *)addr, size, PAGE_EXECUTE_READWRITE, &oldPageProtection) != 0; +} +inline bool HIDDEN RestorePageProtection(size_t addr, size_t size) +{ + bool ret = VirtualProtect((void *)addr, size, oldPageProtection, &oldPageProtection) != 0; + FlushInstructionCache(GetCurrentProcess(), (void *)addr, size); + return ret; +} + +#else // _WIN32 + +bool HIDDEN EnablePageWrite(size_t addr, size_t size) +{ + size_t alignedAddr = ALIGN(addr); + size += addr - alignedAddr; + return mprotect((void *)alignedAddr, size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0; +} +bool HIDDEN RestorePageProtection(size_t addr, size_t size) +{ + Section *section = GetSectionByAddress(addr); + if (section == NULL) + return false; + size_t alignedAddr = ALIGN(addr); + size += addr - alignedAddr; + return mprotect((void *)alignedAddr, size, section->protection) == 0; +} + +#endif // _WIN32 + + +// Converts HEX string containing pairs of symbols 0-9, A-F, a-f with possible space splitting into byte array +size_t HIDDEN ConvertHexString(const char *srcHexString, unsigned char *outBuffer, size_t bufferSize) +{ + unsigned char *in = (unsigned char *)srcHexString; + unsigned char *out = outBuffer; + unsigned char *end = outBuffer + bufferSize; + bool low = false; + uint8_t byte = 0; + while (*in && out < end) + { + if (*in >= '0' && *in <= '9') { byte |= *in - '0'; } + else if (*in >= 'A' && *in <= 'F') { byte |= *in - 'A' + 10; } + else if (*in >= 'a' && *in <= 'f') { byte |= *in - 'a' + 10; } + else if (*in == ' ') { in++; continue; } + + if (!low) + { + byte = byte << 4; + in++; + low = true; + continue; + } + low = false; + + *out = byte; + byte = 0; + + in++; + out++; + } + return out - outBuffer; +} +size_t HIDDEN MemoryFindForward(size_t start, size_t end, const unsigned char *pattern, const unsigned char *mask, size_t len) +{ + // Ensure start is lower than the end + if (start > end) + { + size_t reverse = end; + end = start; + start = reverse; + } + + unsigned char *cend = (unsigned char*)(end - len + 1); + unsigned char *current = (unsigned char*)(start); + + // Just linear search for sequence of bytes from the start till the end minus pattern length + size_t i; + if (mask) + { + // honoring mask + while (current < cend) + { + for (i = 0; i < len; i++) + { + if ((current[i] & mask[i]) != (pattern[i] & mask[i])) + break; + } + + if (i == len) + return (size_t)(void*)current; + + current++; + } + } + else + { + // without mask + while (current < cend) + { + for (i = 0; i < len; i++) + { + if (current[i] != pattern[i]) + break; + } + + if (i == len) + return (size_t)(void*)current; + + current++; + } + } + + return NULL; +} +size_t HIDDEN MemoryFindBackward(size_t start, size_t end, const unsigned char *pattern, const unsigned char *mask, size_t len) +{ + // Ensure start is higher than the end + if (start < end) + { + size_t reverse = end; + end = start; + start = reverse; + } + + unsigned char *cend = (unsigned char*)(end); + unsigned char *current = (unsigned char*)(start - len); + + // Just linear search backward for sequence of bytes from the start minus pattern length till the end + size_t i; + if (mask) + { + // honoring mask + while (current >= cend) + { + for (i = 0; i < len; i++) + { + if ((current[i] & mask[i]) != (pattern[i] & mask[i])) + break; + } + + if (i == len) + return (size_t)(void*)current; + + current--; + } + } + else + { + // without mask + while (current >= cend) + { + for (i = 0; i < len; i++) + { + if (current[i] != pattern[i]) + break; + } + + if (i == len) + return (size_t)(void*)current; + + current--; + } + } + + return NULL; +} +size_t HIDDEN MemoryFindRefForwardPrefix8(size_t start, size_t end, size_t refAddress, uint8_t prefixValue, bool relative) +{ + // Ensure start is lower than the end + if (start > end) + { + size_t reverse = end; + end = start; + start = reverse; + } + + unsigned char *cend = (unsigned char*)(end - 5 + 1); + unsigned char *current = (unsigned char*)(start); + + // Just linear search for sequence of bytes from the start till the end minus pattern length + while (current < cend) + { + if (*current == prefixValue) + { + if (relative) + { + if ((size_t)(*(size_t *)(current + 1) + current + 5) == refAddress) + return (size_t)(void*)current; + } + else + { + if (*(size_t *)(current + 1) == refAddress) + return (size_t)(void*)current; + } + } + current++; + } + + return NULL; +} + +// Replaces double word on specified address with a new dword, returns old dword +uint32_t HIDDEN HookDWord(size_t addr, uint32_t newDWord) +{ + uint32_t origDWord = *(size_t *)addr; + EnablePageWrite(addr, sizeof(uint32_t)); + *(size_t *)addr = newDWord; + RestorePageProtection(addr, sizeof(uint32_t)); + return origDWord; +} +// Exchanges bytes between memory address and bytes array +void HIDDEN ExchangeMemoryBytes(size_t origAddr, size_t dataAddr, uint32_t size) +{ + EnablePageWrite(origAddr, size); + unsigned char data[MAX_PATTERN]; + int32_t iSize = size; + while (iSize > 0) + { + size_t s = iSize <= MAX_PATTERN ? iSize : MAX_PATTERN; + memcpy(data, (void *)origAddr, s); + memcpy((void *)origAddr, (void *)dataAddr, s); + memcpy((void *)dataAddr, data, s); + iSize -= MAX_PATTERN; + } + RestorePageProtection(origAddr, size); +} + +bool HIDDEN GetAddress(Module *module, Address *addr, size_t baseOffset) +{ + if (addr->originalAddress == NULL || baseOffset == NULL) + { + if (addr->symbolName != NULL) + { + // Find address under Linux + size_t address = FindSymbol(module, addr->symbolName, addr->symbolIndex); + if (address == NULL) + return false; + addr->originalAddress = address; + } + else + { + return false; + } + } + else + { + addr->originalAddress += module->base - baseOffset; + } + + return true; +} +bool HIDDEN HookFunction(Module *module, FunctionHook *hook) +{ + if (hook->originalAddress == NULL) + return false; + + // Calculate and store offset for jump to our handler + unsigned char patch[5]; + *(size_t *)&patch[1] = hook->handlerFunc - hook->originalAddress - 5; + patch[0] = 0xE9; + + ExchangeMemoryBytes(hook->originalAddress, (size_t)patch, 5); + + return true; +} + +void HIDDEN HookFunctionCall(void* hookWhat, void* hookAddr) +{ + unsigned char patch[5]; + *(size_t *)&patch[1] = (size_t)hookAddr - (size_t)hookWhat - 5; + patch[0] = 0xE8; + + ExchangeMemoryBytes((size_t)hookWhat, (size_t)patch, 5); +} + +bool HIDDEN FindDataRef(Module *module, AddressRef *ref) +{ + if (ref->originalAddress == NULL) + return false; + + if (ref->addressRef) { + if (ref->reverse) + *(size_t*)ref->originalAddress = *(size_t*)ref->addressRef; + else + *(size_t*)ref->addressRef = ref->originalAddress; + } + + return true; +} + +#ifdef _WIN32 +void FindAllCalls(Section* section, CFuncAddr** calls, uint32_t findRefsTo) +{ + uint32_t coderef_addr = section->start; + coderef_addr = MemoryFindRefForwardPrefix8(coderef_addr, section->end, findRefsTo, 0xE8, true); + while (coderef_addr) { + CFuncAddr* cfa = new CFuncAddr(coderef_addr); + cfa->Next = *calls; + *calls = cfa; + + coderef_addr = MemoryFindRefForwardPrefix8(coderef_addr + 1, section->end, findRefsTo, 0xE8, true); + } +} +#endif // _WIN32 diff --git a/rehlds/hookers/memory.h b/rehlds/hookers/memory.h new file mode 100644 index 0000000..5401b95 --- /dev/null +++ b/rehlds/hookers/memory.h @@ -0,0 +1,139 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef _MEMORY_H +#define _MEMORY_H + +#include "osconfig.h" + + +#define MAX_PATTERN 128 + + +struct Section; +struct Section +{ + Section *next; + size_t start; + size_t size; + size_t end; + int protection; + int inode; + char filename[_MAX_FNAME]; + int namelen; +}; + +struct Module +{ + size_t base; + size_t size; + size_t end; + size_t handle; + +#ifdef _WIN32 + Section codeSection; +#endif // _WIN32 +}; + +struct Address +{ + // Keeps offset for SWDS on application start; during HookEngine() an real address is written here. + size_t originalAddress; + const char *symbolName; + size_t address; + int symbolIndex; +}; + +struct FunctionHook +{ + // Keeps offset for SWDS on application start; during HookEngine() an real address is written here. + size_t originalAddress; + const char *symbolName; + size_t handlerFunc; + int symbolIndex; +}; + +struct AddressRef +{ + // Keeps offset for SWDS on application start; during HookEngine() an real address is written here. + size_t originalAddress; + const char *symbolName; + size_t addressRef; + int symbolIndex; + bool reverse; +}; + +class CFuncAddr { +public: + uint32_t Addr; + CFuncAddr *Next; + + void *operator new(size_t size){ + return malloc(size * sizeof(CFuncAddr)); + } + + void operator delete(void *cPoint, size_t size) { + free(cPoint); + } + + CFuncAddr(uint32_t addr) { + Addr = addr; + Next = NULL; + } + + ~CFuncAddr() { + if (Next) { + delete Next; + Next = NULL; + } + } +}; + +bool FindModuleByAddress(size_t addr, Module *module); +bool FindModuleByName(const char *moduleName, Module *module); + +void ProcessModuleData(Module *module); + +size_t ConvertHexString(const char *srcHexString, unsigned char *outBuffer, size_t bufferSize); +size_t MemoryFindForward(size_t start, size_t end, const unsigned char *pattern, const unsigned char *mask, size_t len); +size_t MemoryFindBackward(size_t start, size_t end, const unsigned char *pattern, const unsigned char *mask, size_t len); +size_t MemoryFindRefForwardPrefix8(size_t start, size_t end, size_t refAddress, uint8_t prefixValue, bool relative); + +uint32_t HookDWord(size_t addr, uint32_t newDWord); +void ExchangeMemoryBytes(size_t origAddr, size_t dataAddr, uint32_t size); + +bool GetAddress(Module *module, Address *addr, size_t baseOffset); +bool HookFunction(Module *module, FunctionHook *hook); +void HookFunctionCall(void* hookWhat, void* hookAddr); +bool HIDDEN FindDataRef(Module *module, AddressRef *ref); + +#ifdef _WIN32 +void FindAllCalls(Section* section, CFuncAddr** calls, uint32_t findRefsTo); +#endif // _WIN32 + +#endif // _MEMORY_H diff --git a/rehlds/hookers/rehlds_debug.cpp b/rehlds/hookers/rehlds_debug.cpp new file mode 100644 index 0000000..c302772 --- /dev/null +++ b/rehlds/hookers/rehlds_debug.cpp @@ -0,0 +1,652 @@ +#include "precompiled.h" + +#define REHLDS_DEBUG_MAX_EDICTS 2048 + +uint32_t calcFloatChecksum(uint32_t crc, const float* pFloat) { + uint32_t sVal = *reinterpret_cast(pFloat); + return _mm_crc32_u32(crc, sVal); +} + +uint32_t calcVec3Checksum(uint32_t crc, const vec_t* v) +{ + crc = calcFloatChecksum(crc, v); + crc = calcFloatChecksum(crc, v + 1); + crc = calcFloatChecksum(crc, v + 2); + return crc; +} + +uint32_t calcEdictRefChecksum(uint32_t crc, edict_t* ed) { + if (ed == NULL) { + return _mm_crc32_u32(crc, -1); + } + + return _mm_crc32_u32(crc, ed - g_psv.edicts); +} + +uint32_t calcEngStringChecksum(uint32_t crc, int str) { + if (str == 0) { + return _mm_crc32_u8(crc, 0); + } + + crc = _mm_crc32_u8(crc, 1); + const char* cc = pr_strings + str; + while (*cc) { + crc = _mm_crc32_u8(crc, *cc); + ++cc; + } + + crc = _mm_crc32_u8(crc, 0); + return crc; +} + +uint32_t calcEntvarsChecksum(uint32_t crc, const entvars_t* ev) { + crc = calcEngStringChecksum(crc, ev->classname); + crc = calcEngStringChecksum(crc, ev->globalname); + + crc = calcVec3Checksum(crc, ev->origin); + crc = calcVec3Checksum(crc, ev->oldorigin); + crc = calcVec3Checksum(crc, ev->velocity); + crc = calcVec3Checksum(crc, ev->basevelocity); + crc = calcVec3Checksum(crc, ev->clbasevelocity); + crc = calcVec3Checksum(crc, ev->movedir); + crc = calcVec3Checksum(crc, ev->angles); + crc = calcVec3Checksum(crc, ev->avelocity); + crc = calcVec3Checksum(crc, ev->punchangle); + crc = calcVec3Checksum(crc, ev->v_angle); + + crc = calcVec3Checksum(crc, ev->endpos); + crc = calcVec3Checksum(crc, ev->startpos); + crc = calcFloatChecksum(crc, &ev->impacttime); + crc = calcFloatChecksum(crc, &ev->starttime); + + crc = _mm_crc32_u32(crc, ev->fixangle); + crc = calcFloatChecksum(crc, &ev->idealpitch); + crc = calcFloatChecksum(crc, &ev->pitch_speed); + crc = calcFloatChecksum(crc, &ev->ideal_yaw); + crc = calcFloatChecksum(crc, &ev->yaw_speed); + + crc = _mm_crc32_u32(crc, ev->modelindex); + + crc = calcEngStringChecksum(crc, ev->model); + + crc = calcEngStringChecksum(crc, ev->viewmodel); + crc = calcEngStringChecksum(crc, ev->weaponmodel); + + crc = calcVec3Checksum(crc, ev->absmin); + crc = calcVec3Checksum(crc, ev->absmax); + crc = calcVec3Checksum(crc, ev->mins); + crc = calcVec3Checksum(crc, ev->maxs); + crc = calcVec3Checksum(crc, ev->size); + + crc = calcFloatChecksum(crc, &ev->ltime); + crc = calcFloatChecksum(crc, &ev->nextthink); + + crc = _mm_crc32_u32(crc, ev->movetype); + crc = _mm_crc32_u32(crc, ev->solid); + + crc = _mm_crc32_u32(crc, ev->skin); + crc = _mm_crc32_u32(crc, ev->body); + crc = _mm_crc32_u32(crc, ev->effects); + + crc = calcFloatChecksum(crc, &ev->gravity); + crc = calcFloatChecksum(crc, &ev->friction); + + crc = _mm_crc32_u32(crc, ev->light_level); + + crc = _mm_crc32_u32(crc, ev->sequence); + crc = _mm_crc32_u32(crc, ev->gaitsequence); + crc = calcFloatChecksum(crc, &ev->frame); + crc = calcFloatChecksum(crc, &ev->animtime); + crc = calcFloatChecksum(crc, &ev->framerate); + crc = _mm_crc32_u32(crc, *(uint32_t*)&ev->controller[0]); + crc = _mm_crc32_u16(crc, *(uint16_t*)&ev->blending[0]); + + crc = calcFloatChecksum(crc, &ev->scale); + + crc = _mm_crc32_u32(crc, ev->rendermode); + crc = calcFloatChecksum(crc, &ev->renderamt); + crc = calcVec3Checksum(crc, ev->rendercolor); + crc = _mm_crc32_u32(crc, ev->renderfx); + + crc = calcFloatChecksum(crc, &ev->health); + crc = calcFloatChecksum(crc, &ev->frags); + crc = _mm_crc32_u32(crc, ev->weapons); + crc = calcFloatChecksum(crc, &ev->takedamage); + + crc = _mm_crc32_u32(crc, ev->deadflag); + crc = calcVec3Checksum(crc, ev->view_ofs); + + crc = _mm_crc32_u32(crc, ev->button); + crc = _mm_crc32_u32(crc, ev->impulse); + + crc = calcEdictRefChecksum(crc, ev->chain); + crc = calcEdictRefChecksum(crc, ev->dmg_inflictor); + crc = calcEdictRefChecksum(crc, ev->enemy); + crc = calcEdictRefChecksum(crc, ev->aiment); + crc = calcEdictRefChecksum(crc, ev->owner); + crc = calcEdictRefChecksum(crc, ev->groundentity); + + crc = _mm_crc32_u32(crc, ev->spawnflags); + crc = _mm_crc32_u32(crc, ev->flags); + + crc = _mm_crc32_u32(crc, ev->colormap); + crc = _mm_crc32_u32(crc, ev->team); + + crc = calcFloatChecksum(crc, &ev->max_health); + crc = calcFloatChecksum(crc, &ev->teleport_time); + crc = calcFloatChecksum(crc, &ev->armortype); + crc = calcFloatChecksum(crc, &ev->armorvalue); + + crc = _mm_crc32_u32(crc, ev->waterlevel); + crc = _mm_crc32_u32(crc, ev->watertype); + + crc = calcEngStringChecksum(crc, ev->target); + crc = calcEngStringChecksum(crc, ev->targetname); + crc = calcEngStringChecksum(crc, ev->netname); + crc = calcEngStringChecksum(crc, ev->message); + + crc = calcFloatChecksum(crc, &ev->speed); + crc = calcFloatChecksum(crc, &ev->air_finished); + crc = calcFloatChecksum(crc, &ev->pain_finished); + crc = calcFloatChecksum(crc, &ev->radsuit_finished); + + crc = calcEdictRefChecksum(crc, ev->pContainingEntity); + + //int playerclass; + + crc = calcFloatChecksum(crc, &ev->maxspeed); + + crc = calcFloatChecksum(crc, &ev->fov); + crc = _mm_crc32_u32(crc, ev->weaponanim); + + crc = _mm_crc32_u32(crc, ev->pushmsec); + + crc = _mm_crc32_u32(crc, ev->bInDuck); + crc = _mm_crc32_u32(crc, ev->flTimeStepSound); + crc = _mm_crc32_u32(crc, ev->flSwimTime); + crc = _mm_crc32_u32(crc, ev->flDuckTime); + crc = _mm_crc32_u32(crc, ev->iStepLeft); + crc = calcFloatChecksum(crc, &ev->flFallVelocity); + + crc = _mm_crc32_u32(crc, ev->gamestate); + crc = _mm_crc32_u32(crc, ev->oldbuttons); + crc = _mm_crc32_u32(crc, ev->groupinfo); + + return crc; +} + +uint32_t calcEdictChecksum(uint32_t crc, const edict_t* ed) { + crc = _mm_crc32_u32(crc, ed->free); + if (ed->free) + return crc; + + crc = _mm_crc32_u32(crc, ed->serialnumber); + crc = _mm_crc32_u32(crc, ed->headnode); + crc = _mm_crc32_u32(crc, ed->num_leafs); + for (int i = 0; i < ed->num_leafs; i++) + crc = _mm_crc32_u16(crc, ed->leafnums[i]); + + crc = calcFloatChecksum(crc, &ed->freetime); + crc = calcEntvarsChecksum(crc, &ed->v); + return crc; +} + +void PrintFloat(const float* pVal, std::stringstream &ss) { + uint32_t sVal = *reinterpret_cast(pVal); + ss << "{ float: " << *pVal << "; raw: " << std::hex << sVal << " }"; +} + +void PrintVec3(const vec_t* vec, std::stringstream &ss) { + ss << "{ vec[0]: "; PrintFloat(&vec[0], ss); + ss << "; vec[1]: "; PrintFloat(&vec[1], ss); + ss << "; vec[2]: "; PrintFloat(&vec[2], ss); + ss << "} "; + +} + +void PrintClipnode(dclipnode_t* clipnode, std::stringstream &ss) { + ss << "{" + << " addr: " << (size_t)clipnode + << " planenum: " << clipnode->planenum + << " child[0]: " << clipnode->children[0] + << " child[1]: " << clipnode->children[1] + << " }"; +} + +void PrintHull(hull_t* hull, std::stringstream &ss) +{ + + ss << "{" + << " addr: " << (size_t)hull + << " clip_mins: "; PrintVec3(hull->clip_mins, ss); + ss << "; clip_maxs: "; PrintVec3(hull->clip_maxs, ss); + ss << "; firstclipnode: " << hull->firstclipnode + << "; lastclipnode: " << hull->lastclipnode + << " }"; +} + +void PrintTrace(trace_t* trace, std::stringstream &ss) +{ + ss << "{ " + << " allsolid: " << trace->allsolid + << "; startsolid: " << trace->startsolid + << "; inopen: " << trace->inopen + << "; inwater: " << trace->inwater + << "; hitgroup: " << trace->hitgroup + << "; ent: "; + if (trace->ent == NULL) + ss << "NULL"; + else + ss << (uint32_t)(trace->ent - g_psv.edicts); + + ss << "; fraction: "; PrintFloat(&trace->fraction, ss); + ss << "; endpos: "; PrintVec3(trace->endpos, ss); + ss << "; plane.normal: "; PrintVec3(trace->plane.normal, ss); + ss << "; plane.dist: "; PrintFloat(&trace->plane.dist, ss); + ss << " }"; +} + +enum PrintEdictFlags_e { + ED_PRINT_POSITION = (1 << 0), + ED_PRINT_VELOCITY = (1 << 1), + ED_PRINT_CRC = (1 << 2), +}; + +void PrintEdict(edict_t* ent, std::stringstream &ss, int flags) +{ + if (ent == NULL) { + ss << "NULL"; + return; + } + + ss << "{" + << " id: " << (uint32_t)(ent - g_psv.edicts); + + if (flags & ED_PRINT_POSITION) { + ss << "; origin: "; PrintVec3(ent->v.origin, ss); + ss << "; angles: "; PrintVec3(ent->v.angles, ss); + } + + if (flags & ED_PRINT_VELOCITY) { + ss << "; avelocity: "; PrintVec3(ent->v.avelocity, ss); + ss << "; velocity: "; PrintVec3(ent->v.velocity, ss); + } + + if (flags & ED_PRINT_CRC) { + ss << "; crc: " << std::hex << calcEdictChecksum(0, ent); + } + + ss << " } "; +} + +std::ofstream g_RehldsDebugLog; + +#ifndef SV_PushRotate_debug_region + +SV_PushRotate_proto SV_PushRotate_orig; +int g_SVPushRotateCallQueue = 0; + +int __cdecl SV_PushRotate_hooked(edict_t *pusher, float movetime) +{ + static int callCounter = 0; + + std::stringstream ss; + int currentCallID = ++callCounter; + ss << " >>> [" << currentCallID << "] SV_PushRotate_hooked( " + << "ent: "; PrintEdict(pusher, ss, 0); + ss << "; movetime: "; PrintFloat(&movetime, ss); + ss << " )"; + + uint32_t entCheckSums[REHLDS_DEBUG_MAX_EDICTS]; + for (int i = 0; i < g_psv.num_edicts; i++) + entCheckSums[i] = calcEdictChecksum(0, &g_psv.edicts[i]); + + g_RehldsDebugLog << ss.str() << "\n"; + g_RehldsDebugLog.flush(); + + g_SVPushRotateCallQueue++; + int res = SV_PushRotate_orig(pusher, movetime); + g_SVPushRotateCallQueue--; + + std::stringstream ess; + ess << " <<< [" << currentCallID << "] SV_PushRotate_hooked( "; + ess << " ent: "; PrintEdict(pusher, ess, ED_PRINT_CRC); + ess << " chanedEdicts: [ "; + + for (int i = 0; i < g_psv.num_edicts; i++) { + uint32_t newCrc = calcEdictChecksum(0, &g_psv.edicts[i]); + if (newCrc != entCheckSums[i]) { + ess << " { " << i << ": " << entCheckSums[i] << " -> " << newCrc; + if (65097 == currentCallID) { + ess << "; ent: "; PrintEdict(&g_psv.edicts[i], ess, ED_PRINT_POSITION | ED_PRINT_VELOCITY); + } + ess << " } "; + } + } + + ess << " ) => " << res; + + g_RehldsDebugLog << ess.str() << "\n"; + g_RehldsDebugLog.flush(); + + return res; +} +#endif + + +#ifndef SV_RecursiveHullCheck_debug_region + +SV_RecursiveHullCheck_proto SV_RecursiveHullCheck_orig; + +qboolean __cdecl SV_RecursiveHullCheck_hooked(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, trace_t *trace) +{ + static int callCounter = 0; + + std::stringstream ss; + int currentCallID = ++callCounter; + ss << " >>> [" << currentCallID << "] SV_RecursiveHullCheck_hooked( " + << "hull: "; PrintHull(hull, ss); + ss << "; num: " << num << "; p1f: "; PrintFloat(&p1f, ss); + ss << "; p2f: "; PrintFloat(&p2f, ss); + ss << "; p1: "; PrintVec3(p1, ss); + ss << "; p2: "; PrintVec3(p2, ss); + ss << "; trace: "; PrintTrace(trace, ss); + ss << ")"; + + g_RehldsDebugLog << ss.str() << "\n"; + g_RehldsDebugLog.flush(); + + qboolean res = SV_RecursiveHullCheck_orig(hull, num, p1f, p2f, p1, p2, trace); + + std::stringstream ess; + ess << " <<< [" << currentCallID << "] SV_RecursiveHullCheck_hooked( " + << "trace: "; PrintTrace(trace, ess); + ess << " ) => " << res; + + g_RehldsDebugLog << ess.str() << "\n"; + g_RehldsDebugLog.flush(); + + return res; +} + +#endif + +#ifndef SV_SingleClipMoveToEntity_debug_region + +SV_SingleClipMoveToEntity_proto SV_SingleClipMoveToEntity_orig; + +void __cdecl SV_SingleClipMoveToEntity_hooked(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, trace_t *trace) +{ + static int callCounter = 0; + + std::stringstream ss; + int currentCallID = ++callCounter; + ss << " >>> [" << currentCallID << "] SV_SingleClipMoveToEntity_hooked( " + << "ent: "; + + if (ent == NULL) + ss << "NULL"; + else + ss << (uint32_t)(ent - g_psv.edicts); + + ss << "; start: "; PrintVec3(start, ss); + ss << "; mins: "; PrintVec3(mins, ss); + ss << "; maxs: "; PrintVec3(maxs, ss); + ss << "; end: "; PrintVec3(end, ss); + ss << ")"; + + g_RehldsDebugLog << ss.str() << "\n"; + g_RehldsDebugLog.flush(); + + SV_SingleClipMoveToEntity_orig(ent, start, mins, maxs, end, trace); + + std::stringstream ess; + ess << " <<< [" << currentCallID << "] SV_SingleClipMoveToEntity_hooked( " + << "trace: "; PrintTrace(trace, ess); + ess << " )"; + + g_RehldsDebugLog << ess.str() << "\n"; + g_RehldsDebugLog.flush(); +} + +#endif + +#ifndef SV_PushEntity_debug_region +SV_PushEntity_proto SV_PushEntity_orig; + +trace_t __cdecl SV_PushEntity_hooked(edict_t *ent, vec_t *push) +{ + static int callCounter = 0; + + if (g_SVPushRotateCallQueue <= 0 || true) { + return SV_PushEntity_orig(ent, push); + } + + std::stringstream ss; + int currentCallID = ++callCounter; + ss << " >>> [" << currentCallID << "] SV_PushEntity_hooked( " + << "ent: "; PrintEdict(ent, ss, 0); + ss << "; push: "; PrintVec3(push, ss); + ss << ")"; + + g_RehldsDebugLog << ss.str() << "\n"; + g_RehldsDebugLog.flush(); + + trace_t res = SV_PushEntity_orig(ent, push); + + std::stringstream ess; + ess << " <<< [" << currentCallID << "] SV_PushEntity_hooked( "; + ess << " ) "; + + g_RehldsDebugLog << ess.str() << "\n"; + g_RehldsDebugLog.flush(); + + return res; +} +#endif + +#ifndef SV_LinkEdict_debug_region + +SV_LinkEdict_proto SV_LinkEdict_orig; + +void __cdecl SV_LinkEdict_hooked(edict_t *ent, qboolean touch_triggers) +{ + static int callCounter = 0; + + if (g_SVPushRotateCallQueue <= 0) { + SV_LinkEdict_orig(ent, touch_triggers); + return; + } + + std::stringstream ss; + int currentCallID = ++callCounter; + ss << " >>> [" << currentCallID << "] SV_LinkEdict_hooked( " + << "ent: "; PrintEdict(ent, ss, ED_PRINT_CRC); + ss << "; touch_triggers: " << touch_triggers + << " )"; + + g_RehldsDebugLog << ss.str() << "\n"; + g_RehldsDebugLog.flush(); + + SV_LinkEdict_orig(ent, touch_triggers); + + std::stringstream ess; + ess << " <<< [" << currentCallID << "] SV_LinkEdict_hooked( "; + ess << " ) "; + + g_RehldsDebugLog << ess.str() << "\n"; + g_RehldsDebugLog.flush(); +} + +#endif + +#ifndef ran1_debug_region + +ran1_proto ran1_orig; +int32 __cdecl ran1_hooked() +{ + static int callCounter = 0; + + std::stringstream ss; + int currentCallID = ++callCounter; + ss << " >>> [" << currentCallID << "] ran1() "; + g_RehldsDebugLog << ss.str() << "\n"; + g_RehldsDebugLog.flush(); + + int res = ran1_orig(); + + std::stringstream ess; + ess << " <<< [" << currentCallID << "] ran1() => " << res; + + g_RehldsDebugLog << ess.str() << "\n"; + g_RehldsDebugLog.flush(); + + return res; +} + +#endif + +#ifndef SV_Physics_Step_debug_region + +SV_Physics_Step_proto SV_Physics_Step_orig; + +void __cdecl SV_Physics_Step_hooked(edict_t *ent) +{ + static int callCounter = 0; + + std::stringstream ss; + int currentCallID = ++callCounter; + ss << " >>> [" << currentCallID << "] SV_Physics_Step_hooked( " + << "ent: "; PrintEdict(ent, ss, ED_PRINT_CRC | ED_PRINT_VELOCITY | ED_PRINT_POSITION); + ss << ")"; + + g_RehldsDebugLog << ss.str() << "\n"; + g_RehldsDebugLog.flush(); + + SV_Physics_Step_orig(ent); + + std::stringstream ess; + ess << " <<< [" << currentCallID << "] SV_Physics_Step_hooked( " + << "ent: "; PrintEdict(ent, ess, ED_PRINT_CRC | ED_PRINT_VELOCITY | ED_PRINT_POSITION); + ess << " ) "; + + g_RehldsDebugLog << ess.str() << "\n"; + g_RehldsDebugLog.flush(); +} + +#endif + +void Rehlds_Debug_logAlloc(size_t sz, void* ptr) +{ + g_RehldsDebugLog << "malloc(" << sz << ") => " << std::hex << (size_t)ptr << "\n"; + g_RehldsDebugLog.flush(); +} + +void Rehlds_Debug_logRealloc(size_t sz, void* oldPtr, void* newPtr) +{ + g_RehldsDebugLog << "realloc(" << std::hex << (size_t)oldPtr << ", " << sz << ") => " << std::hex << (size_t)newPtr << "\n"; + g_RehldsDebugLog.flush(); +} + +void Rehlds_Debug_logFree(void* ptr) +{ + g_RehldsDebugLog << "free(" << std::hex << (size_t)ptr << ")\n"; + g_RehldsDebugLog.flush(); +} + + +void Rehlds_Debug_Init(Module* engine) +{ + //CFuncAddr* cfa; + + /* + CFuncAddr* recursiveHullCheckCalls = NULL; + FindAllCalls(&engine->codeSection, &recursiveHullCheckCalls, 0xBA160 + engine->base); + SV_RecursiveHullCheck_orig = (SV_RecursiveHullCheck_proto)((void*)(0xBA160 + engine->base)); + + cfa = recursiveHullCheckCalls; + while (cfa != NULL) { + HookFunctionCall((void*)cfa->Addr, (void*)&SV_RecursiveHullCheck_hooked); + cfa = cfa->Next; + } + + + CFuncAddr* singleClipMoveToEntityCalls = NULL; + FindAllCalls(&engine->codeSection, &singleClipMoveToEntityCalls, 0xBA550 + engine->base); + SV_SingleClipMoveToEntity_orig = (SV_SingleClipMoveToEntity_proto)((void*)(0xBA550 + engine->base)); + + cfa = singleClipMoveToEntityCalls; + while (cfa != NULL) { + HookFunctionCall((void*)cfa->Addr, (void*)&SV_SingleClipMoveToEntity_hooked); + cfa = cfa->Next; + } + + */ + + /* + CFuncAddr* pushEntityCalls = NULL; + FindAllCalls(&engine->codeSection, &pushEntityCalls, 0x95450 + engine->base); + SV_PushEntity_orig = (SV_PushEntity_proto)((void*)(0x95450 + engine->base)); + + cfa = pushEntityCalls; + while (cfa != NULL) { + HookFunctionCall((void*)cfa->Addr, (void*)&SV_PushEntity_hooked); + cfa = cfa->Next; + } + */ + + + /* + CFuncAddr* linkEdictCalls = NULL; + FindAllCalls(&engine->codeSection, &linkEdictCalls, 0xB9CF0 + engine->base); + SV_LinkEdict_orig = (SV_LinkEdict_proto)((void*)(0xB9CF0 + engine->base)); + + cfa = linkEdictCalls; + while (cfa != NULL) { + HookFunctionCall((void*)cfa->Addr, (void*)&SV_LinkEdict_hooked); + cfa = cfa->Next; + } + */ + + /* + CFuncAddr* pushRotateCalls = NULL; + FindAllCalls(&engine->codeSection, &pushRotateCalls, 0x958F0 + engine->base); + SV_PushRotate_orig = (SV_PushRotate_proto)((void*)(0x958F0 + engine->base)); + + cfa = pushRotateCalls; + while (cfa != NULL) { + HookFunctionCall((void*)cfa->Addr, (void*)&SV_PushRotate_hooked); + cfa = cfa->Next; + } + */ + + /* + CFuncAddr* ran1Calls = NULL; + FindAllCalls(&engine->codeSection, &ran1Calls, 0x60A10 + engine->base); + ran1_orig = (ran1_proto)((void*)(0x60A10 + engine->base)); + + cfa = ran1Calls; + while (cfa != NULL) { + HookFunctionCall((void*)cfa->Addr, (void*)&ran1_hooked); + cfa = cfa->Next; + } + */ + + /* + CFuncAddr* svPysicsStepCallc = NULL; + FindAllCalls(&engine->codeSection, &svPysicsStepCallc, 0x96E70 + engine->base); + SV_Physics_Step_orig = (SV_Physics_Step_proto)((void*)(0x96E70 + engine->base)); + + cfa = svPysicsStepCallc; + while (cfa != NULL) { + HookFunctionCall((void*)cfa->Addr, (void*)&SV_Physics_Step_hooked); + cfa = cfa->Next; + } + */ + + + //g_RehldsDebugLog.exceptions(std::ios::badbit | std::ios::failbit); + //g_RehldsDebugLog.open("d:\\rehlds_debug.log", std::ios::out | std::ios::binary); + + +} diff --git a/rehlds/hookers/rehlds_debug.h b/rehlds/hookers/rehlds_debug.h new file mode 100644 index 0000000..031de8c --- /dev/null +++ b/rehlds/hookers/rehlds_debug.h @@ -0,0 +1,46 @@ +#pragma once + +#include "osconfig.h" +#include "maintypes.h" +#include "memory.h" +#include "model.h" + + +#ifdef _WIN32 + +typedef qboolean(__cdecl *SV_RecursiveHullCheck_proto)(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, trace_t *trace); +extern SV_RecursiveHullCheck_proto SV_RecursiveHullCheck_orig; +extern qboolean __cdecl SV_RecursiveHullCheck_hooked(hull_t *hull, int num, float p1f, float p2f, vec_t *p1, vec_t *p2, trace_t *trace); + +typedef void(__cdecl *SV_SingleClipMoveToEntity_proto)(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, trace_t *trace); +extern SV_SingleClipMoveToEntity_proto SV_SingleClipMoveToEntity_orig; +void __cdecl SV_SingleClipMoveToEntity_hooked(edict_t *ent, const vec_t *start, const vec_t *mins, const vec_t *maxs, const vec_t *end, trace_t *trace); + +typedef trace_t (__cdecl *SV_PushEntity_proto)(edict_t *ent, vec_t *push); +extern SV_PushEntity_proto SV_PushEntity_orig; +trace_t __cdecl SV_PushEntity_hooked(edict_t *ent, vec_t *push); + +typedef void (__cdecl *SV_LinkEdict_proto)(edict_t *ent, qboolean touch_triggers); +extern SV_LinkEdict_proto SV_LinkEdict_orig; +void __cdecl SV_LinkEdict_hooked(edict_t *ent, qboolean touch_triggers); + +typedef int(__cdecl *SV_PushRotate_proto)(edict_t *pusher, float movetime); +extern SV_PushRotate_proto SV_PushRotate_orig; +int __cdecl SV_PushRotate_hooked(edict_t *pusher, float movetime); + +typedef int32(__cdecl *ran1_proto)(); +extern ran1_proto ran1_orig; +int32 __cdecl ran1_hooked(); + +typedef void (__cdecl *SV_Physics_Step_proto)(edict_t *ent); +extern SV_Physics_Step_proto SV_Physics_Step_orig; +void __cdecl SV_Physics_Step_hooked(edict_t *ent); + + +extern void Rehlds_Debug_logAlloc(size_t sz, void* ptr); +extern void Rehlds_Debug_logRealloc(size_t sz, void* oldPtr, void* newPtr); +extern void Rehlds_Debug_logFree(void* ptr); + +extern void Rehlds_Debug_Init(Module* engine); + +#endif diff --git a/rehlds/lib/linux32/libsteam_api.so b/rehlds/lib/linux32/libsteam_api.so new file mode 100644 index 0000000000000000000000000000000000000000..eb5b0f159d3f0a27ea2f0ab3ed8826217ce420fc GIT binary patch literal 76032 zcmeFa3wRXO`9D4h3oH=W6(dGPjha?a)I@1Z1Z}u%h)7_$1kh4LB#A*oh+&so3G6ai z%rK6nhFEQBi!EBJsI(xWfCiFg!J;6BVGc&uJGzfn$73mf} z!!NogiK{ySrzFxv+y#iowWgaSO-+-K-$+kJu&+mwv~PfMbpYnYbenk{M`&FcxaVc1 zx&PuRo_Y{vn%8<{+)%EF9HRXkW40yfgwc~dF2IBJK;%_3Z3F1zYCLw$T*GOFDxax56SA}aXu1s8WaQSeZ zkIVX%nKxt2P(@ge3*r|)4S%QMx*OMJB1V$#Gef@_u0c2i*J50xI}Miu*A!e!aPfDu z5lH7Dd9{I*6ZiX}dA|_hwYX;Bs=>7s z*8p5M;QA4+2XOIs53X8Vy>MNPi@#yGt`T>VWH&=?gO5RY7p@``W^k{0pJj&25ca?oz;!>aS-5V)W&JLpOAqaNOUD z>*2V#_}hQ>l%yjtXwuwY>La~M!I(eFz9t3@5LdIo*r?AK)5&|{gQ%L_X6Z|set=PGhis+gwvuQqCA|C*ENqx(x)ce zANZ|t7yAzak<1a=^Euli7(h(o>A` z9*iq5zQ1Drr;+}8T)Gqbn1jxQ?U4DeO|YNC!2fw%`+ETLsEO037x}Co%U_v5-?ee{ zvwg80TR-CeIzc{VaqxLak66eEi627xhB*6}0D6YR=_eoh`3KrJeG~Z^4EwqS?eRtv zJ`em1jpKhA@>j&=F9e?TWBunR@bjAl_?85?7WLl-`>^bNO+xy&65tJ1WeCaNr_cun zKo-3lL7(+w`cD(`j{|=Hxc0Oc{H+_3B>Io@Fhb~ryk3rz*Ikgu3dmzR$`bY)CvTQN z1m&%VJ2!h%%Amzy&N8Aj75n52=ZA!miJo1xG~!RQ zkOd6gCeX7zf&V|E{yuAAC^@beD%8Dhev3FWyR6XcziV9&mU^t}o2y`cAI=;s@tgZ#E6)NhBqG%qmxI@5O~2%Hy5{dHf~;z5?a_HBP?I zCD4Bf`1=&~tu*UXL9g{A4Pz4UmnXnV0(@Np{411SiuN`DWs#pJQ2w7F4-5Wr0=UIREjSg^ZB+*HV9R>F)vl2L|V~GtxUT0smkE z{CEP)`Iq&(5;vn04~X#V_? z`O-Zlo|1|MQdLP&d1aBOOq%bhD)v@Nv&-krFDaf=1-Q7Rs!A%YteR8dDV2(5&n}ri zUz%50Qo+>1LL^qqD=eQkyT~(VUIoi3HnLUCE}CC5du}C5w1UdTq;}Dw!pf4W`SVDX zXK~?zOrliGMxqGKY@T`L^A?tn08tVGlbw6KMODRxMYHes&Zz=Vf<+^)s-(OGxuv-! zb6HwxRY{37#Zyu=cQUwho7`32U3DLm$bwWF`}^&o()`&)CRd9fO$f2D+`17VP^>82 z&MuofuUIOdT{drFg*1Qh-10dU_epc-c`H1Ux55DKE1gq14>GAJnp+}yJ#(zT^QF1> zQA$;F`FCznIpil5-Z{l{AtOSN{MG`)#A}bp4nxiQT*LSv+tWP6_rK2#q6q*xg`~zGtgw}ZY=oDiiP(YTxUnQo>MWu z1ZE69!~}5n8S0plS!l4{g|gz3e~YprPst*-lRKwQn~;@BD_T@^_nZY;H)a(UE|@!~ za5mdVp=WVr2^v)CJlCn1S>HjfQ?P_NR(h*S3Kz_&@_38NX=_ErQmJTB5CRMtrj0_; z2+;zh`{tCF8nUbS6O}OLw)sZe_EuCxrBOK9TM@JODC!wv<7|9#$$W2lTy4xf`Q#vSyW8?F){fdB_Ex@81LN5(eviAt;W)( zQ}9-*G~eh0qV?a#9;6F2rKmJcsnDfW=Vsqh#!d77v= zo9=>I7^}Q%{FE*R&^7H;{f>pljjuZf$5kAQj5Uu~Tw+6srNp(XSY)h?#NuM+5Nj2u zOBIddp2A8YbHfe9&!0C-U<}_*{b}YRQa&^Z)##sND(?PmuyhXC4FJ-Ua{JIDF6GhXM7FerV#q z^&D53x=TNeD}QGket%JZU+Kv%<#&rKzlW4#rlEStbMYKN{iIE1-1#Cu=9(sK(Az6Y zuTg%_X!-LmXMUU1Y~maIBuDF$u#W}uq;xaPFvCG+IK&Jy&2Xq04l~0MW|(7!W6Utm z49A<{R5P4mhBM7@mKm0rp~nn;X852Pt~bLCX1LJ|H<{r!Gi)-$eHR*hwVL59tP_yW zVlyl=!*VmMG((RWE;7TVW>}1JlQ7rXVuni@=3xDSAr@rTnBk*l*o1m}U{bz^AtsY8 z4D%%EAVVz7A7c2hB(*WboX>}Pk{-l*0N|cz#>W|AzS_YM^S&<_az2}e5c5VGL(CWL z48d3mL+Y4eZ>-TW#Kuw@LkIT$7{Z{_8G^11hUa6yfFTxihcLVVdwmQq#5x_p`k~E%S2G$=KeiM5S46nxeE5kw9`(TKLqgf2G5MIo1 zh$NLUybk-046(^m$q)_E!!Qf`SqyK)Ixxd;K~4;ZVI7kp7CvhkV&mpPhPOZ;46!M( zhT(UypT=;cB&}sQR+82+ybbGQ498*3iXk>`HZshYq)iMbK+g;@!QaMkk|gb5I9ZY! z7-A!*iQ)I5Uxs&KPnaPVAX^yD!a6v^BIui8G4#!_6#8aZhJ6u+b0kS;c&{WKWq2R- z&k$=e#~ES)xP#$5=$~OF^bb4fc|Y{eunPKT=z;zjVy(u>a541Ha0&F!a4Gc95PKKt z46#O-!O#c&GxS6M3|Bz^3(J_P+U{2}zua5ePL z@JG-;L)iIDhIQEcQvNbUK5En9G9`awMu#M+a$6)42{d@R>mPzY{SKt)bDzO>aFgwO z-)}@zL~JBP=%&Rl@~aet5F(b8nK$w)7`9Z#*e76;R<@0BrGU!`HxQmBV3Jz4 zhp=0~Fi5Gag>a65NqX5q!kGewK}uz9gwqA=Bdim43b=-FJ7Gz{wS+qexBrX$KS)?g z0^BCx)r9SYTLip@u#<3ufFC7{76kqUyq0h};dKIDM|cq7)dF5mIFqnXz#9k;BU~xq zjf8Uu&l2z^!g++<0^UN{O*luu+X&AfoGIWPgl7>>7jOgNGQv&)HxaHRED4yREn7sm z{R{HHkFbw$n}8|mvRc9|0&XR|ns9@FDf+TU32zecA;RkjuM=<^;SGdW3-}1(O@w^{ zrfSNz5v~;QQNj&`X9<|9D%(TYE#TvXTL|X}n5ru~NH|l#Ul491oGxGqw`DqEr+{sQ z+X+howiE6k-2PAUpF$WTH}EfDCt*9`76GRcb`ow7a2nw>!kYv=v+xa0}ra0WTtakZ>koC|~^4 zffKcF)StH_A0c0Pm(wk)#n530-eDALBvpUiJ_(g?Je2QLX`w)~P zc`j1rBZx#l!yX)yVdFePdtU!LVuohu^H6TH>tjizKn#p~8cJ4nqv|WO8eT-X z5#_+KXO))0drE^jU)~@oE&e9f`MtXezu&0Iu5Ca-Z6zp4+1(}4pin+quCGI)zp)7o zQ*rH44mh^D?6t1VzU{3LhUCf9FT)q*|B)Ql80 zKSddzVb|ob20u1cJ__XwidM34gi{CjjJ)x;HbGD zLi^+Zd7S)vkE)>@e5V%<> z*k(%85%>t0j;)T`{5Mort5(^kxu>LfGHj}=g*0d&DrA~ zJT;)^?|^<#(Kb{B^1+GTfgYo#!4dcw(_IHi0h`{~$D@%Zeu6|CudTJwDlPPSpAK32Z7<(5P?A07a7@AFE%-@srxsu@D@jEIK=A`8gm~Nd2J7=46xMd3THO+Q8$}wj{S?$@od^}O z`05s;$%TH3WYyc!&AZVsbr`R_m+4sz$DTd;ro8Ji`GfYs`?RSUSIdXn4FTDpYo%a= zeg`TCAFZ`L5bxO9t2Q52*U}94!xHu+l;A-LAEAUjR4xtmVlz83*Cv_jQwugYYNpT! zcru)#u^JlCgh3DmS9tLgXDYP%3+C~0_pnnP|uit0)ec7G>aO_*RgwBiHz2S<3tO){ z%6j2{uA_h0eh84VG{a7FgbbB}gZfnvLZCq{IOwPeGxb=|#md1(GMd>n+L9#2dqjDA z#0`!yCmk<0uqG#rq;@Q1)>959)iiiNRF0|MBNi`axjzLtqFnDyYzCRHpm6kL!q++i zSF@@PxoL=KK_>efK#I~Fx)~PctA1bdT;aP}@(ffC3_jVd+MdLWf>V@AiX@24~=v6HE6BZmZ1ikt= zh7o^H(o%0#s@uc_L%)*R*saL4ptvsh!h$1X0^jolH4FJYNdit#py}$8p2wXX! z1P&rO7&wH#kQzHRrvxPJ`8LFmE5vXRD{1w_5jF|&Z9p%exY|^a5qflyPHJx?GE=_y ze+towEW_(rg(ofhm?xD^CC~~`{}dx9RowcUNR?q?f*M5>8h!>1-GEVC=Ea7h@>YtO zxERfhPX{yipCB{!80V|r6t&uE_O|{A2QLd8StpcsQ~*p-K_KG!ByhqL5^Mqi6}%5d zF!G7A3Ev``t7z-H&Ka9Lo>g7X#;ePpW~l2i%!j*h zyc^v38$ZIhhl+`c(MoFGotK~4}vum{rt54&66IpFsk-+Lvu;FiXl2sS& z_}pG4YyZh0`#_8%X@*^$%k6Y(XED|bJ~=yE^PIlmTi;a=!F5L!@F`s*=O&Y@?Vi4CJsXPtxoU7>T(|57~tNhbXlCD1<_4bk6t&-+vg zy!3z8(l^2_#?zl`jU{5^rpAxYu8q(1b8xdUo|~I6Qe#WGeQ8&1c+uYcjgP(ewYYf? z&hH%DTyPF=_9zgL2zUL zPuq=$Q-`>AAKyd%?k{Io%5J8gjg2lnWU|S|#R+VTffK>{$GcR@f6T@+@PYAcSj|7q z8Qad$V2)$K`mEe^F|na3hEm2a>Z+6lXm)YJ(zt41N-n-!cWXuF*wq+7Oo9zP5e7PZsw{H zQ!KpMFnMeMpeK>LKnn&=>hnwuoKQuAqh>8iJmZ9Nrje@gc)~$7!Og;_28$XaO z#;8!tBA0%Mgyt?|*p%!}ENG`@=n~S@dJ-|bo{V{%!|Ta{k$U(ra$=@VNf=83&l5=z zREMT;0v*3L@DRHPE-SF>Ozlkq1v;P}fY@1FhBF0N{rjkkj7P&8p#Q^y{C`izKZD=? z@5^{BOO2ZYMP>XbtnExPUi-n>WV{Ti|EY{O!3<(D{v{yF_$5zQ8H?qm_d%e)vD*RB zEHN}t^Ha|~AB--)>=dg^#;Sy|0-|WNU;W!~!EpjH76??4=E>t6l5HW*2W`L^k1m#& zumDxrMw{Zg%9$3Ro{BfJ=Xx3}2j?d=+jiKszcKag|HPz3(>hJF9S1*sdXxI?*J!rK z;VVeK*+pO52j zeG=ICmSE$KH@=oOe$J6w92y^*644T@bHI*13sZP_W#Tiu0FI%n1Us%EWZr zhC6wv!=Am{7<%3VTFe|gE5n~LX5?v<{vz+UnYY@mjV;5O5x9x5<*05L1{-RBrJ$AJ zIGa+iFMNI#)>vDIyPXUB0V~H2td!w-sS9*9Ck4kSj;s0ml>C%zZ;PV_&Jx}-MNL*G zq-Kw^IacgO#KK;~bDfSAFEDLFnmQ6&M*GwxoGyvDxgCWAF}ecHE4z3OM{|9Q-JLYm zwGTn6aqh)w4uVkZWSiLg!N5ozJA|3@_e7>=)HGmo-t%oWH;uf)`_iG zmdoK3Ho01nQ!UsRnQY^xK90F$AAsh>5el)tbq&eEs5|*>2yxz`B)O?v4BsI^{d-s7 zr0lNFeL_RE{&i>qhE_1=k&h11w?b9^#y>ILYwUhGUO;KwvBCzi6BQ}B12y@|xX6E^ z8YMSfle6O@KN67{TJF#jxx!xLBQL3-?lXnYNPcc2*xVZAIzG ze#6s89qG)@wJ9Br{9VYTj7n>EeTZHE{3A;Kk?f$yu1>IJ=Q%xBaz4K(P0h(fp?z@} z;zOvC3gS61WBXoEe@Oov45|5cWn`LKa7dk;nzi@DC|k0lephz>5$`iJN1=J}7Qw&} zWU|Jja2+Lg3tEc4$0$G@DH1{pF?x%(ml675p!gemkn4gd*Iv8aY*S96T9~xpdK|e9 zMq7w;S(NMc>@UIfSZDSqo6_#c4;r+_bKUOgjjZEhd{@T!&i_!%e?dI>9w97|d>0(j zlVW@?PgSa0!S`6fxAI1I^%2Oz`y@_JsY&V*V^1`NxgY}4EI0*9ST=o%P47f;{>IB* z6}Bx{&3F2?)5In30LRw7NsVpuXEW=Y|ysfLCk+c z`<_0?q{{PJLYB!O!N{`wHKP`sTQ^K4s?YIye?i%|NtqXvVK$dLkVjvh1EcDMbe=X_ zk6Yh%p0Si1fgj^;C7Y)PpPqjNg!K(Cfx+e31A9GAWzXt!A$yAS2W8>8VxsJ61l5TXD!qb+u)? z4tXv_ma6`a2PEiG%|9}Hg3}=%2M)A25CP9#{rF8&g$F$js;$zgxY6CFDDE`qRCKuB zHYhWCwCQbRpbT=@9U4wZ^&S%bZ}{R$&k&yNK)LfEDxBkiDHR+HeIIU=^-pv<9+-)H zE2C*&hdd4v+I!*MChK>`2*imz{j(N}Mjm@Rl}=P2XKnOE=*q8;(J5BgvLd1Gs5)zJ z_?J<88=^a*I)CHP-^Xi(-B=mAF?8Fx910DFT*4PD>JCZ%pxd4V|S~{CD$T|RCXiCq$29coasGt}PlvwY&WIw6;c@wCr zPC?7{Z68Pn1auSCw|xjBJhL@*J#Lg&Rhh@cLF@&?D^nMat?E8}k#k{=vRiaQ-f;G- zo~Gedsa3C#{)OF#FL73FG5ZqTWm0r0D3YJvf?}c+fwS<_ICIS^cwq8~zHOgzr0$3( z5R|!@&0kO+6TNercbZ65XGD=_ zM(<{scg-@jkQ9{5qe*4ayJGWBk*DI0(!yYB6_s3vZ62N@V7r!eF>cl5XQvoukoO0i zp!yDYv6MevuZBMSjgRl<`N!%MQ`3$b?4045EYimwif1>~&7_g%EMEi^?W8sWusSIW zs_ICih7Pr$LG!k1bt3?>tDJ>i!ces}ojM_qDCeU98jzE35nOS{aVdx_0Opu%UP>+i{AO9o_>gdj(?=%gRRR z7rss_8{R<2hmjlx@9;8IfaIvbQ5hK51_0=lt_nR5unLRMN6?eff1qb-SErdh(|+_! zZx3IVy5P@@WY4tU`!{w=0puFKD7C6;wPWQ8^gmi18)DEUPTyv~?HPbfRp%|V8~svM zPoyA6tZQo1zknGSqYJov47Bo`$|CleN*)(>Q>;$On8xY1LJG3Xh8^vfw9Tw?_-2aU zQ4;_Ww5~r=78A?rtbtt28d`r(Yw)z4!}V-u_or;n6Mx6!@2MS}EL@NLpST`b zxE}dyyPmPdicI@g-8=><@I(DVA8-_#%PBV2pN21UE0okl6Vov8g3hWqrcI%4K2}YkG9wSs8W-o>znWmnW#b$qt&=2PQ<5)c#bmTRyh$b ziFl5*Pl#zkk|WT;LBnQ}p=@5t492SGb|3D8at;3S7lhB@+9%dW*?bS89LH8MUD$v! zeugrz1S()<^BUkO+c`%F%4<)_Kc4v?MSg3NrHPJ$tF^mdF~$dJ=WOf$&a~(M#{*K# z{W0ySg8{{l4^Ex-OnMpPgICc(Yq>(~Nq|kYg~p@#YogDjLO$LJ%zt$0%4fp=`Wt;1 zmPS2-DuyhldW2pm_kSKiw3E{f>Y^Uu1IXzt9^scem|TV?V~N=E2m|%kcTpS1uyhr- zN@1*xS?W2Dt6^f+Y-Nx6?0Zl&H1y~H4Ytniv%iaWa25?o+tEzw(Q;yn`4(ECzwwUW zokcO1QZZuCCfqEVTNTbBovNhWF9{{R`9CF{T}eNI7S5ui@4W~mDTb2dqu8RdtK*y} zb|raJ)ln(kMu}xtZfw~yB5&?(G~=A=_}-XCSx=iVh3l7JH~%&qa>It@f1#xR9wlPu zdl?Mf-}p;x!N52*qpx(H$gw3EZw@%{0u9vK0XNsy$B8@@$Rk&$V5)y7X9`&S&%w&Z zA-VbxqOwHPArW;@u0Dt;KKO|T9Ys{DT-}N&JUW1=RuR=ASGOQ)tB7h5QTw>`_Cpb| zPeioAb(M)bY^8WyYGn#$DmJXGeTk_FTNWD_n$;u>9MolYEl<RGq zqeN_L=t6;e(2N}-Vh@J?28&c(hs@XkBKA<|_aZjMjFm)eN@y)&t$93bM`&yxtlr<) z{*2HVHe9ecBhJgt6u4BC<&;L~>jZ8SaR1-eRLa&wO?5th22FhsO-Rtx9wXs2ntB!~ zr)ug^5u2!~6(TlKQ{^HyQB%`I>?xY!p@ek(3OI6qqYF#K7`_|p*_cw7i#{N?SXe5Q zrWuP5x#Lgdx|6)$(2Qja^8i97rr^Y)pZ=jD6ZrBCXDb1p{WzJ~qEh6@ih)s*eUM*sqMeM+6?0F(~lZZ`^#{LtE@bCJG zh|P$`{zb&rh}c2V*f&IMg^1l}#X{jWJ#!mMX`G4_y)O(y7VmCDbJW?8{kw*XEMIiV z@-H-Xf8!O*vIMu$EW+0g)ZY`y$w=nZi?b+gb05?~d$<@?&_!y9RpcS5NUOUTou1_p zE`|*#@(9Fdoq)f*L6fg%PL!hxY^wjnX5x$o4lw#g>WGap>l?5wE07Q^+~#Y)0|>XD8%`Wek0o;HcS}x(I&G{8y2K`BbR;zNO#+!x=XX-yXBpqeB;iLSGo(-_R0y~!8FT#tOs1uKK z8+r3L5lifRYdiU>qZcI{bIoe_>}f6fcBF#eqRH0XN)B*9iW1V~FQH`Io#s7BW5F7V zdLQZL;e-J60G*^lR(8IYz>2>VK<2vpK z5D`y-`2^AEg;#B3+p60AL2?9i#)lpuEq#^KGArW+-`X^lcv_Zmw#U#f>WG00!s%X-)^8 z6MJIBz|R;7`L+)gIX-Qc#f>Uw8adjS;|Y<2F|iy`8-n2V6hUSt$fUUw2``p14f-=o zB9vfr;A7Yhn_(@_Cr3qKygkb_^gp8>ZvF=j0au>~?c=~PZnaT3>fDB#TfTJQ5a3<# z2S7aO*eVL8VPwC$EKk{^?j%xna2f2rhvc<2+j^wq9V^+pmxqnvubsvr&g}_7-ohI2 zKz;$V?uDkf)`a2H+dca^y+-{@gYr~O2g?Mg>YV#&l6=m=B42~7}s8t|~(r;%u=pWJ0B7%^_k=JB2J%8f@oKgB378Q8r zt6J0)k>eDL;t<2BzYMkb8xQ}AG#xdKPLS{^3d)4|!(Fsh zu-`V~*jF2O?4ON0_P)j)dtBp={j_n%{?@n~7`uvzF=j3FaVyG?T%#_)eHU7F)h;Pu6u zk>Dio3JLx03x%2fqG7N3O2SnAZ_m=6`#;X(7^3H~=5*uU zu!4+enOnk7fdxUuErN<7QqhIpWq7clE4}9n%jYXK58KVLd%IduQg5jjAYeN{7FRX~vL9o@aJ*lQxJkOa^q3 zBH_m#j$^fW-8>_3ygM~{33EXZnp|z>Kf&?RZoEzM6;aL-jF52mA}SJtElNxj1%GEC z(XH1X1dcuc#iH**Kg-%qUpodEHvml)IXHg`h^&|VhVN=qH3AsJ1TK$=9ucJBgoQnWUJ7Q?X-z^5!H$gZE~K#(3CTd_3#*GOfj zF9=!!f(#->r+)|q8l8T%+36d#p}#L@f6w&nj_T9&_w}UZEuYzV%|T3!xh|W}ih4Dwm~EH@NCzWA zZ!iqAJ~A&qZRz%T{S8n9^LUR=!o#%PW*S^W1T~9?0+LZ6v6egmskSJ=U4OqkbPV%v zv>|f^%?_^ojYBZHGY2b<8b6Iy9>Id4=vU}Z6z^cGm3#9`IPVI4Kg;)GR`ZLm_S#(BV^*?YWdl*6mKa9B+G zz+pW(khhV8F?do%-eTP0Q4?9b1P9{L0RUDk71gDS6M1bXrVYTXXps$!t1bo6R* z1n>eI^tZ;*T1_5eAnLb*)Y!mYtE-I@;_mezMTpPBaMYwzeRY?UB~#REfu+{5dsf7( z149Uu$sf9>hcvlw9Q&2PWe4ej4aJ@|FbBovz*SR?LGdndWW8=Jeo)*4{Bby3LxJM} zqF}Vkh#2prrH!h>tZ>-A2O&Wf>+V43%*KxKFN%#0jajUoX_kpL6CE9gg2-^Xu}_Rq z3`tFvL+tuvv#%IR$d3dx3}ZCg4&|c%dknJo+Os!PYn}|Fp=~qmGrplcMnwoLEa>)D z4U2B@3tpR7!>xAZc7BV`fnu$^+&%4or%m#HGV(E{K2GwSo+c!~#J{pZT*5ltU zh@6Mh-xzlo_4LDhm;(k>!V!wzpQ~+FVmSPPHCS+ptV2cC9Y)rH?6o0wbI&26puPWO zK_+TA{FdQD(BWbXs_%wY@cuhICIM-2xKtZB5N00(Y21T1KBFySOvwQZf7;F?NEB}Q zv!_MJ1D|L_a??E({ts{Vyjkr*W8iT@txhZ#ndbc3<8j?p-3S^l8AksOQbhl*|LIra z-I{4EoOQF<1-}$s^a7PfAr^F;)LVv+oe)# zDe6mz$IRVZ(e|;xpRz!4E5?&x?Y6GPMVF{X0yEeH<%(CeYO<4@K#0%|^iMIqi@AIv zasT`oM$`FdKISsduz0zDxlVYLKn>Fq#CA3*d^^TRR0B83jrYGU53{}e@u z)hTd3v1<`g&d1WK1m{M!(B+`Fi;@2svhg=2)$_pLnJt=YY^U0E4$K8MeXDBD*&H?F zgqx1H>wiEeA}6Getqm#r-lZ`%lGHM5O)0?MHC%=I?p5&Z#Og$^3iRlt7tIArnUQHY`tSwfV}8$=(qX{9wO|Xj z6T7ivaMV125N~M@s0dlj%Re!C;CX=cPazZ~sE>ouD$V+@kfhp`{B4?gJI%v7#mEI& zJkXlIEix$;l?r$6sNrYY^~zY58E43nuE-ME1ug%Cv(#^iWw9os9QRr^U?$3?8KUna zdcPQY*%@jWq{v*uVV1|3<=w}kd@MafmLZDFg&k%oWtI)GEY6*$XMHGIfSKhcX7R?d z3_U}Z5sJ)(B-SD^%cxkEAD@A+97X0j6SMH`+PWi_W$GDf8KcMp%`87*mP3!m*gr#- zJVj17v)schzlmj8e}*hG6`6}&By1?NEQn=kI!zYuw#c+uip;ezWDyqmFE}1mC>KU% z%YZRPCSj9qJyX^E^)TF;P4rFM#q4`!IP72TD^{)`(gM~iak^SR#-mOB~}$4+m={L>Zzr$h+kMm z9Q&8(KXFO~9-c(%wVjcOSYI>ZU=5P)vEsyhbg8}w+424Z%**gT`9#fKiX80vm{XIt zlQC$nFHEOdo(Ul*Debjl?nUl$fW%W6WL>_CDgdtk5#s&~5Yo~VF=ta<0~Ili)2cV% z+$lJJk*hJEJ;74oLxH)0rEpaZMO2_V@u>v1w1+`T3~gf^+E}2KzML%DV|f>>O>tOP z2&`@bE4K^QmN=|`qN$X=Y!g_V-odGU^~IH;`JonZ;7`X&l!L_ zG`2P)IK)769YXa^&DDk=MROfNfFa8}FB%Pn5BqW&yk6Hp8IIW?c_5DXAi&Elh@6V{ z$vq`JVYQy~E=|_Wyymh2>c6f#mjsqZ_p{!656xp&^(qkKr$^*3=x6tB+_7gi?xLF} zes+pRTy)dKAKf(ZM>kFU1EYBCM~ocogp50D(?s+Cft%d^AxH`Otu_B<|4?FT{v9H5 zghD18LBP7|Q109!4P?44jz~IPyMvg(0X%t>-N} z7$fdc)TC;R!=8Q4nGA^zu>y4~&4GqxSF>bPARLh$Wd<5>oF2nYS3BRdG$P%cy&5m~ zkAl%9iSHweztN9|hDo*t^8(RqVlX>VG8Y!XS;ddw;#Nj5O|v#{qO%xa=ogAoh8v{> za|J;bVV0wQ7;LG_Z1}7|AJBzd!u~LS8G@mA;0WgD%z*)uVC7PXLadnGtt_*};Wy{n zlf+Qn3G9>`fQ=7XAQK7JG*d^sGvzXt;%D`k=Y;aEyn&+)KAke>fs7rCtDdllw4(S{e zd=xo?fq%j3eG}rQY`n)`g#D?w0B0=BBC_9fn!>MHRClF!2S+4{f+0ZJcG5_ zU^uik38HLX*^OpoE^9^Y^%+sZn^?d(t-aDivxJvHS#xfmQ?gfx><^zQdzzVjxyXLu zDcNrj*{7T-JDUe<&k@=CS=o8QR$u%MoopJj`pdDVWb8T37O}}9cB2(5MlC~h`Yo(~ z)u1uIfRA;U9z>JZ0*?mw21cNYycCc)|1?f@;+YvvarsscV^|rPjKxA?sLXHYN`$7) zWPU3>MUfu_j4rUZTE`R|`{~W2PR3gVR8{28R;rI^+t(yxS3VxLM;w1anN;xyjJR!Z=HbtvgK4B?@gYtjNEv^oNvf(4 z++J^1tXK@*jrBxq`x^v=>n%1>5MB)xDuzQ+Gr@2a6`R;X^08vDg1*bl{tTEF8?jqf zljnmgNE>MfZBd&bjYnZ~#`3IqCzsyq0PSr9@%=}EZ`j*sZ!`8`5xXxM`)3imRKyO! zj-G)V6tSfuc6>DUw<6XpVrNEUe=1^c7O^9uu>ldAA!5IX);3SX_7kxw7Ot@Q@%rm% z`FQ@rPn&n8l;Zgx#|s6{Qamf^cp*QvRLOr2GnMpO*N0-DeF$a7+QmSWMM=DX`HZ^x zIOMGK;K!#tW7#tB$Tw$8F1X^}D8O?&EAv2lYU=OUB)DQ?HVJf1d0$zZwp^IWQ!(uOh9Z}*`a{W4(*(}3 zMS}VU`umL<5@cWmc zM!W^U&^48*)(M$gt$COt&y3{^>_N`ZC&pZKntU{a#!5q_k-{L;Fr7mGG!VkT+l$gD zlP*SL9OLhS{Bl!<@xjW|l_G?2u2LGXtPm|lw4#A}?SpJZ8<$arR1%EK@{j5CkLZ7~ z;mQ`G4uG$jV3-;nejXpM2b!rM0b3?Xz&xG$zicHgx$;xtdRJ?<= z{Pwujqd{Cf!iydYj*IV#W;MJ7xg?4EO-cCXBR@83(emypQXg3g>g#CwSOt!eFv4=_ z##@GPswnG3)?THc-LZ98j?yU~UjEkMUT@30dMceY`xpIHEofJ6yz>rzLKMYMhf$>% z_(xYcYYR^1h!=~sD+lC{m%sIKuP>3$SA9}ibXYAoDt~_Y!oDY5?KwEF`bLDQ%8hbU zidoc&oY^^^6yH*3x#a1t*;a?UskYT-CFq`p=obhsvdM+lUR!`~k>V9*Exzgl5zhqq zaHZUt?zwWg1DstecRG#td4$vD&K%DGxzo)*nO;x0ySiv1@Cac z?RCh_-QQE|1%Z4S93W#LG*Ms7pfO*$B9<6CLk^*^FzhIgxVyeZ#)M$MX8>N*D1T5Xf9`aQ`7)^!^-7DA)&3kx zofkL$0IxQEFzm_Sn2&E#pgZwxFNT%dFlaiDLh|+u_tIyf%;ua*2`?F$VID48@&@wk zx(Ioi{j->%*?+eY6dA#6BPcb3dyJsO2t*Cd{`&x>H2ceqV6G8V7{NRvs5F8(2v9>A zgP4}a>+|3`{f%|_{)AG1x9Fqo(kw5q@-`e=xLz@tzrSw)FT92F1`{-5uU;1$C?E@6N z9xlXHMgNx#j2d7>k%Td?qG)7z78!iiFWlgGU@h*{2i4S9pxAdJA55MMEjYIRi1S)4 z|KKDy`V)NxoG1EOz9H@r)`vk^s2uqmTk&!_i<+cYjl`VLBqqIZnk2a)IW&~@oi@!D zN@H3+m+kz(DD?+@i0d@RnBPvFJh6;mYUN`3Vsjr9rg07TV#tGCTKn;$0)8O${ zGwB91i5cHElAbe@QoH1$vkmb{a~AkH)@Rj%jryk|G^%}D%$V^yMkVF#(0xFZt9M9v z8%eg!qUS%48jQ1>TPc2^4;t>}{g# zP<|&$D%cU?`4>uIo}hqIP=53%GBECYW*jxL264fa>+qL7VdyRVCCadbY(ak%Ws`|= zL9~>RimW^~uwpH4f-8uM>ZMRGf!d(|6|1~x-llw^Cn*%hA4=*Ck+e-e$Z_b#AwH>EFI5@>;_k%o}%_``dVUAU{=w}kH~fCW0QpO zqVy*59aX;4kVYxW0SV!&NaQsFW1BuXv80$u(KJFEgsC^^ou9|^+Z{=Y?M*WB0TQ~o z+QRd)_P*p~_1=`QgN6lCCD_F%d6!M@ynMmYFkTqhr2kHo1B&d*w6gHcB;^+(s!9Jb z!#JiOoOtU#`KQn&AV&8s!*B`j;&E-7FW#H@qxGUzykT|LuF&P(CXCO1)v@ArXwus0 z6rB-#=Lr21xJJDHoFAOPJHOt3F%vnn8k7T{J&gwpgE?gYrC^Smf$AR5U5pXX?4(I@ z!&En4Iy!RJF8y*14`#UaY#1_L^NW^`AwfXsrMgueJHFIEY{oWtm_^A8z0Okqq8_jL za0q{F9#(0?H@-x<`G#$C1VS(-|DvR406PMQ006c7Yd%MyMHqRjIx4UGIwY#@fiZIk zink(CEy|l}b?dbg^OT2#vF9552YEvVzp3;K<_@IjwY+pd6VigYDF!%*pgowIYJeF8 zoxxo0tN}TdU}i9PgaJAU4#Rsn4KR)1pkVG8f^x&K!7WN|PH^QGKz3ZsEAjdpDamZ1 zAbzH@QfS4s=h_?_7pPtP^7;M>U6N0d%|$w^^<$|IYYhF5StCL-Dt!>kMT`Igv|VCGw$$|EEz zC+tM7F;*@{HLv8$<#^0Azr~lm#Cst+YW+%LR3AwSHm?-JqzFIK-7*Tp2MzCx%x?-8 z_&UdXdt(Ii2y=(~`Z_0j`w(Q0kQ2Vi*Xj0Nspa8m4X4{3@it9@Dd|O`-b2bG8-N5G z38(lvr+6^@jt6MZ4<{=fFVTl^c!^h7ON^K_38GOi)TUl&n-=l5 z>YFFYVosnCWAi%0J-5+H!WW1~qr?65@ju`$ zV7U7>`Y^nKS{pOUj`7XQWLfg`r64XkVG3f^LuAzVdBl@Gc{2K2^u&|hcr7E?T16cC zu~uc0o2DOej3J!`dvMNsYOCk(DQlw_>4|f+9ue8K9MX{bx>|;Z$tpYK4acDt` z+i=4da!+_tYw)63y!Z=N_n<(5Ct05(cbwvBrzZhVYF zX;$htF&7rc1Fg6bvrlf+1R4Nw#96kvG_#32ehn=p*=?Re00!tGT|;bjJhu z{E6i2yxbu_4tw)qG+fh$suteo>+Eg3S8n0ezRn(wniWW1*xlFJEquMN)9$Eo1IyRh z%Mo}I<%RME)Ynn7n3*s1b@suB!bMz)BTz$(X#(o!sNrV6uhZcO%w_a!0bPK@La@Yz z-}H6%chp>pTgQq@k#fGH=1PFR&QwQW1T*jet*`SUN6n|idf**F^#DiBcSZb#j=%s> ztbisi9OmoHoWI!Dc{ORmfa58Fex+k2xeYxlu&#GJP!9v~bq;pOs~BA;pw%D*BrNRb z>zs$z{6S2is{~1F95r5KWWvLaz^{QEx>+PV;;2zX)=wRQ)wl`U zs0Y$`1W9DFt0od&+8sIyPPmm}rkFT#vpuw*DfKiH%usGRW{}YqQV^{b97NniBhGa& zl#e*KTMoG=MZ9)>A_jv-fiTbz5A&$P$dKjerz{2x;&rmEYCR1N?;+NBZb_F!aTqrX zP!3g!!ji?v@=#Jscw@AbCsB%#S^tA5kPh?+t8V2$EdNl_o)8=t-Z9{)xq;Q!>}){| zp(mjZ#$AHAiJ|WJOG&y8Y11RwEe_3wh}^-u)iw34#C{OiawN&|&{5o|Yj*Bq^eNZ6dV_itq#(t?jD4LmKM630T4wuN0WXD5KFvmoE*K0lE)EbSIC;^dg`j^_o ze<|9U_yj6Mtr4ZGB8y^VQH33JsXz@dr?N&=9l8$nkjrl&oTxsyQ`93evHgngf-Q8S zt$K>sJ_7xK7OwPlUgfCayS;s#Ydn3};sgJHv4)qf>XADl*)wQi?=SZ_0*4vZZ-mYB z%@KA-fUmI(4_1XyIkxr>eGjlfo#TaGp&~-UtW+t);edgt_7B|@P1)6Pd6qyKEdGWH zk#h295&}H!d~Sq6O9Noea+TG-XTQ7-PQ2< za^$-UFEjL_7@`_G{CRc}jurhdq{pbDyFP6`O;5C$#QudNEd9Mj>|c`aL;n((igu>d zyYW}sISYSZOb3S2{Mi%Q^8`hIhK679H_@YB%pO(bF*{WxeGeLiqfqNv)QM5(zHQB; zDq%Z>gE^cVz;;-JDyCCd=k@f#0LBsc0rVNZ2IGhTQzM%=snY_i)~&yakrdv%E%J4H ziKE@{wN@#dnsF$2*C&w({7pey((ZdDO=HGM`tL9ZQGz7M;B8S})(Idh^<$81l&%EE z<6haBhrjAhl4+Ja=9n!H11ZM?ebsvtvOk6kp5pFnx!d6sSF{s(e{^b=zt#e18_ ze5YIr&yMEx?YPVskK{5Xshc1wJUW_gmYs*PO{sJ#n*(Q*ZI$Bbu3vvYR*YDbVtXN1 z{<6O#aGXs~Xv4RSLwgCYtrdFpkDCR^7w&6F)jx~EUT&nRqsC)yQ_3;a6k(HQ;am15~vV|RDj&_oBG@Ft;-uU)Mj#i(6 zRG8gm=x#9n?XH(qg0Jo9W+IYj;PmO5{C*7#2ygJfn9{8;VJatUo_@aV6rY3!(gqR1 zlEtV{)Q0lbATH=?f=O~&3jHkt4!Wgijoa9jVHG`hJPPc>28ceOKgQ$-IN^|&25mjO zy@I*pnLq59JlQ=>|NJ<}HnVm_*Gm0ITY$p+d<9P+6I`gdP9-n|H(FpASq%(jWIg|4 zjD0mb%-wQFcaIGt+y&cuv%b#mFJ6q$F=iKr9?Uv@T4aGO@@@CMNlN`7z>#{EjQ5=I zAumRFML=>mfwyD?HTXlch)xDsO86R;C1~Gu6^uaXSDpX;-J^4Ssd_bf;qt9ptXV$zbVr zEVP2AA(JLen;uzci+o3UQ{J0AiJYXP6h00@+Ef8~t|WzNSW4}#&#H*4qXdQ=*2J_Y zPE*jHnv*BiCXJ&3t?-oo#*Pv+SMl-%yr>?-_~nCFJ=jf5N%Bt$hlVxiWUfIgLsx|R ztF{%!yhO>wyyUNQg?;hKVyria3dS3^C~y?l4Y*#Fgf?Qv8sAkgA=2ZH<(w&QF;g0- z-z+G*3zTWDqZ~=*x%HiCkScV8`3oj1E|;;+Z&f=ZR?bv$JAIn}D2MM@nb87p`R1U` zY+33~_R~1w?>Y#*<)DTf#nq&VF`d!B=-UmaUnTFHf!xWSIoeK+_|yk~&pAi!_#QKT zpC@^G`#w*Gk)#H(e!k}SVn{f3r8A6^JS&Co$Hb_=_xFZ7RC4Wxdnr|NXQ+X46pOn% zd6+C09Sdv+ZN!E(_!B%wMB>esVlp&kvfF=@6Bq6IGT=tMHVqF6wd>Du*=HvYs0i*p zdx9;v%%IAvb7Hs+) z#U70M{o|^)L#_To8{gNa&XtsXjoUCHmZI@u_Xo2~%8+L-jcRZTO0Y^v>i1v>5hq9W zd8UCzyoikS!*-qELI_ug^%&{C3B1!=^ogs9f?-~L0vfwTKAN;i{x$y=`Njes$#sHU z{pw0K*4ytsMf<)Mx50o3?Do+YimzYwo-}E) zVfRkcc>G6a(sG`sJBhZwERajugm+Ln(H{MO1r5<&Y6$0dDbtJraHIgA06~9jOef%P z(GOwC4w-(7V!{n#JuKR{Sl@d4Kih+xK8;J$1;)FG)GB-S{q~Das7vhGi|vlw=4d~T zHc%jym#= zsrkB=`hu47LwDpxEL5Hb2^fnnGR{3DqdUQ|+hpZa&GYS~;a=y`pTzgXc!LQ(_lH_Q zipDS09ak6IlrP`>+l25XZuIl`${o^xk+17H(BcHpfzksf7Jo2N^So%slyIaSiw%?P zN{`9Y@0Ge_a3I4(`ENEePh|O9v8u&3RwlWUd$gS_&-!iOzcgqQ5D_(z# zO}rV~(CzvjqEsJWHGr$u-5pyo&*yseMVcE6RFd4b93#HTS^M?Fh93_1;9|EeCpY|B zRzpmoXmrLh{$BCmr|@v{(M%5Pj8Q|vIdb!GxrT<|Y7I59@5#j|)lst{4I>yr2!^HE%1`jd7&zAR)W&n1Oq=;fS||cHW8Nm^h6?l{4x;P;i`IT(e*6 zIzHUhUUgoa{zpLn9F)e?AbisroE`EvZo5NxyRYDzwiMCX#rvkEdY&k&9A)7H0>6TIhu5ta_goBA zC#K;kDOD{SfKN+I9OwwFU}XNL;c78rybJLT2h4~S*G4{$7QP!!9|tt>UBva-1)HkA zqZVu$?zYXpL0x25syC>M@FhB=Z5r;{=%}e@-T3;%Bz(K&95u(Oh2{2c)f)sozVG5Q0wKf& zbGd1Y!y20;zJqWBMAmJjJ&Yk(H#jo1Dx6K~g%9tl_?D&jua2!_layond2E-vCru)V zgF2J6iMC1lQy8i#t}Uy^CZjctK$SKW?_1t&xFgVs8t9de=?6qhbi0u=S<7$3cEA?> zeq_Y57jkizeIjyg=;jDCBM&w;V5;_{&$IJ4IaYiNDdW_X76Hz`O?flu;>wDoRBu$g z>%)T}Q!VwpH~*?uZ|wH})pj=UQB+s|pWP%9Awop7sMxMpd@EfNv@LI?1d@2HCokCN|M}17bN0-g`@8p^d+xdC-nlb#chdgxw>}X&Z$r%0p6pZ?PH-X4 zM4W~Luf2{{wc*2yK}2~d#>b(?oI$5mFu(k=deRAUdzoNe^&ggj>=A+r?;=nQ!CG` zAc>f`J6;m#V4GPsJQg3d-~4YV{u?M;tvv14zudi@JCXKMxt&t&#Du0)gjy{+nk}OO zoqxzvr`kWj)!&Wh67PNpU)PCqKh=G?NWZjz}|YB&59dsDJ)(L)``0xLp35d3gK& z?(2{t?X+hYxrnm!#xuTHvF?R|I~mDYcAVL zk0^Oj+3g`|{B@-0n8`n_?%u;!v>Y2cw%~{Ox9SbkG4HP9+E8()EI#e$FJs4-?2qj- z3o3kt_20@aJ_J5~^_msr+X0Sp6X(e5VHHp3mbNFmjt}lg?iE`~+?`v*v~tSClHIZ2 zc2sup@o@W0z6RdkzMOBW4{>AAQF$<{D0^bb0dD=TxdH9GlSc;^P3~qbS-O(EpK(yk zY}Nsh^R>ina_hv`*p!pi&Wk{m2g*B=`#TaF*$sOy;%=zhk&Q42;pV-8_UvcYyiJi^ zX#BDb(@}93bJ4x}*j}rD+poxW!>}P8IEv)%_Tu|wcee-H-zPubL_uCxk+=#yd8j)y zpL>qMVkd^Y!;n|nmI)FjnvV-uRh93O7hHBu96V(8Uum+tOU2&T-oxpm48}6jVMM%E zLtC1@NM0kL3gVvjN)2!BVBUOf;cwrgSvpock=uTXChI==p}5GM${@PB7gMrKw{~xs z!;F?8eP8#3TrwtH`_zPMuS~ewl}5$Sk1ye6i_X~4EdEWjWap68Wk^KB9cX{G{r&Nk z2V!?0lgIBeC;lO`{i?iVS;x)Ug|E?+$G@~8`-0zg)3_ZgZqMzQN!uUjn3>09QLMRg zXY4$*;riwHS>*bG7-qGL_h()n|3Pfeu~!IN^K$-w{R64Vk7OmSWH-`K0uosE%zH++ z(wHJWEhf*3X6-m$i!!p3`%%V##~^X+pZwtO)%^720&#-FXUZ(cdPXvo ztTwD!K_9N}UNO%wr1Y!d+1)!;nxj>HrP(1}2jer-%&zU;s8all6ilAw&Bw}o{u&sU z{na(&w8XeQXW^gq_Nwf5rthVBdrH-^a0C3*fbMlfb*$Me9;I|x`_JWswe({Xxoobf za~FD(Cd&}iKDV1UzNK`v97WORsiMCkMf2CPlX+{0+TAp~I}0Iin8#z6XAL~VgP9$P z4$l{@xK*M&LpoX5EM;+Tn5-@dDpXI-+= zNrM{;onwH=cMw0EonbDjf|I)Et38N)hihS76Qv{PjssAG~!XVmAJLcRO& zX;x(P#9U@+@~W>}=4lKMsXKWY7x^!XQ{AUnN*(glUfc(_sJpvwQqP-lm^G&NV`SLd z{UBHA`I6IAS=u~)qZm-hKGVHee+sG|vvAL$?vMHY9;c_xp1q-DACD^6{Xiahe|N6Z z)Ezt9F7CMX5CRSpN2~+S zDt^^y&IW2{8?k|CbBjOL6j{tg&(fwuqlzq^I^9=YR99A6R5z_mtB5W|f}rP$QSmE0 zU!1J?Ky7L)h9Eu)YYKW3 zZ3!bhVa%9VGBRdVQj0~S3C%D!Z@f_(Q{NOB6L0i|)Yy?VU^vz(rpzs3MH0C zV`BIz)lH|jqPtPya8jEUmo8B+eS^w+0x>_zY4k^e;ZO`+6pRf{Nc|AJHYgz{X*2v0 ztu$1xRr+IEQA-TIOq-F6Kw+&Yxmc?WwP-T~39TyHsuhO2_DZhf1pv&>WZhlm`l_p=$TJnQ0eKJqvAIX>@N>8PV|z; zK%7TZd5L68S}RSKt;RhKv1qd=p7xnYsyR#|qotL8OWFdVmPAuDQXXlD&cSI-O*Vyt zG(rDqZC0Xb;sr!t%Pv!z7{u{+xN=P+-v#D#3vT4s(J)@FR!P00fAZ7Q& z*)(Ieo#5x!`lKmJi^?l*G+K$EPh`CEDzn8WdTN)&eHAozWi*%!hf;=MS^y0=@Kfd^ zjiK_7D}$&>Mj{BCD#`mP^GQbh^~j;B5x_xt{2pA0WaVj!#1sBVAmoWQ7}Xi=iN=Tz zM+5$_-5SK(QC@9bNm1pj+LD^ux}v&TUwKtsNlj_dv=ZNJE|t%$Dkv;8Fh$kXy+z~W zjQE<8%9(W~wRJOVil&$JmQR6!tDRO;Qc_i0HnZ2#a0O<5Wp#Dcy<{T*L*}aT((;nx z%97ez3hY(1!cW`2k*Ei!Twd&Hh$bUJ@4yo5J{0qW{mDq6(Zjh%W(`J%QVpk++LBDD zxCX{oL$hhu?qLFw@MEGhiKGuiW3f;mVHU&iyDXZFnYl*8%tB}i!v{lZ;|p-M=;mVW};4}AcQB;TL>f1)z-y$QM%+Rc5} zZ=g4zx1bY{Y>*}NFV0=&`PuOEpi7`D%xfj^2~ZFk164z9&=>C0^+`||dKB6V&67Qs zpbALN7eR|1B>OU54_Wc9i?b$f<{B8J^ zETlccZQ5M;{Y-?{!`Cv;-wBU$`*ads%6;OMXOoWG;05q8@D=cn;oITQ-Kgt_;A>-I zKZQPq-i*yq{|fld!J4))Mmg|D;rVQIvo5adQ{XES*fYE#sq5R|KZ75D%X_4<-~QE0 zksp2-z5xDM8})?mfOo;GmQzpoQTP+*YTBDCC!@(`^6L+8= z_)2VDwj*=13^5MAiLdh$@T)eE5B$}Qx_*TE4E{Pe%;luksoiy4&XEI=lwwV#0PY}6Fvui06zHJw9jx&`yRXizUV>nhsWS6 z;NO97g|o_>~gg>Ub|F5pMt zTi_qVyWn}x(LV5z@YC>d@DZQIuHcj4LHGjra`+1PCioWkjGfr4gyARPzlRU|9M2S9 z(Dh>Yzu=8kuOJ`% z^giUeRMX0Sjh^6_yo&zew;rHhz=!++e>D<$;EUk-2Pq%^I=lUHFWcfj*6qhG?u z!QX+;g}eWVp5XcL&G3uiJK&eY55nidwa;Uxa1T5Jp8}uo2K9x14SpAV%^~a&KK4(v z-zZJ{GrStU?J)AfcfxnT$Nd?3;EnL%muuS3;ZxuT;f?UX5%BQC@SX62H_;z_IXw3Y z?D#L}5B?MQBKQmNRq$WEg+0Mbj?%vH7vXtVYTCZPqCfZre*+I+@it=)JanA;!NVu; zw^wP}R(J*c06YQz()-}xGvWK-YvHHhhv1&8u_t&jeB=lCeYiaE*b3hd-wDt95c`K? z+UjsEuhCp9a$OhaWoO^zLJwTUY_+-5b^Reh6b;UudWZX*oboj}>$306awiAwDtftS zPti*xC>k`+2yp(Argwl1P?&&4X_j;C-@1_sbm}zc4a~iQt*^u!Uq+ys&*MEi>q^5KlB>qRl z?-4o1*zzn}lf5p>eUFmDuwR9j4KSwGn)q|ijNc9ZbqoLDrD+-Z$p0kxmO5SkoyhaM z9(Y45HhE+v_xxG(SHVBs1HaxWe;xSmgMU@<_xHd*;KZ*5KaF{(!ryXcd?)xfE&PpV z#vcWL+Z;3hubmk`jCQ+ZuBrb^d*FMtS26fb@Jjxy9{3*hO@ObNXX5|rakf_mUi!;6 z@F&0rUFdU<4R7|btU;E4Fd9wL93+irzL{qGr%RKU!#rhyuK$Dd+281y#{G+){bdSi z2HnUUKxAv_nI_AVDVzA11Zip)n)Woymd3Ex9`>{i{9E8v|M^M}d`5dn-4B3Y?lbFt zp$*@MzC3xnH-nGXn>yOo1D~Oz z&m;eo0n8a!>H60=Ps#2dXc)viV>}dGBe+k_fD@l4_ks$R;;-?F9nY8^0V?`k#8k?oVSy?)6|l z2K)2guv;_bo&=@~{PM-R{;S^bH)i17m1a;ZvWWY5X{*zuKa2Z$ZcEd8HOEiMe*{K& zlKkb>&mMX|n32CV8?>@l^T!3GpTS(|K70O_o*FXJ`<(N~&7^&3W#98G(N`CkC%~-g zMZT?2DS)!8zq#f2q|LjF4 zb2EyXZH5emO4@wZa&BIx>)$_P+WL&Nqe)vq+F#!K>FiPP+2Aj_&FJshi}9G2Z!1yr zQ$ti^B#|X9Z9DkyfM+OBhiZSWg}$fj^7?Ely*1umU>S^&$#u3)rusi==aL`GIq9@D zhOd_R5jcjbe&Qz)U))dp0^%q16TgD^f_~z+5Px|;@m<7^=qLUV@k9HGKTUjYKk*}2 zU;G6B(wBZF5r49u_yxqj-B0`q;*azbzlHeU_Yv=*eY%L>M?A|!>Gs2))tUZG+VBXN zm-@*=4C~o`@(?@yJeW=}bL=)|`Lv&9bSTXOz7G5w==EC8Q#M(7XI8zjTA=)18<^u@ z9Ep3D!|MGa~bEUcBig4nB@tk1NXU{E5hf?=b(h%d6UBsWh}wwzP8@xN+noe_WQTyJ=sU zQ!!(0tquI=$#=B9olX2wbe~>Y3!5Rs`X`ZnCu#qiXKWYR%QEdR>swZDF{AA&0bw+LLh0~dARTENYH@XY$$ z3~nCz$?N-0eY%aiFl+5m&1Lq2muE14?8TqBZ!>jZtJf*;Ly;rnK1#J~BGs;{{^#?o z=L|U2{@@xnG4JCZI3=&yCe}>B(wFqzHt-LAi#2+?zN!Vmn8r1E)$^Nu#EV=zh~JO> z^e4Z_bp+f(@)^~etqjjf8yZ+CH=mAByII#?d;3 z%Y3DU__f4eY;Pyacix`SPVRO?I_1R0?`|h;fVTLE^OS7HTxpF;X)4%5^g*zrzsvJ! zI~KcbGJTQAdK%0mFtBuf_W2Lbug3NhKZ*D&`-xvb{Ac@#UqSq^e&V+fKd_(pF51SYS!&nU{B>CkrXTchy&BBs zelSvQ0?adD-nZvtm20$Qs&7l4+rZ!QP~UAS7+qd()jkUg1eax{pYo7~w?(}M5Z~lC*MizBm?FMB13$kV< zG8PqzNj`;VzTf(pu79()ajJ@}mV32Xu&;Zy2&~wv&GqKjP~GKenMB8TkB#g3h!p62SJ8PcDQ6M5>OS(3_*KMD>?2;v*-HH7#P8!g)xOuMHhb1; zEXijtxL<;k=|>7@Oiwkj`EKHWLVU4(+`WF)fYoOi&r-|0`BAU7)a$|M>CgGWfiLZO zdDn|O^IX}}2F;XKAy{;tdkT47%QEaEPxF2k=c%%6c~yAxlbEaWsz$0o3&}B+q1byH zc?{jb`(*Y!u1m`^j|5)r7JD*n3fLz|cPHsy>LVS!Yi6q8LAQ9d=8P=VIChdea)05t zzpL@)o6GE)$T$3R{D4W?%c&B*qbd6D0&hO%Ut=`^nlaYrt4TM7bY~h1+Q5~8>u)Sj z?GJ7VxKVaFszr`;=N3P(7hEH_4m)m^;849gC8sg}2fGLCEq3f2!OjL-X4OgQ%H!dA z#4~&XXvc~VE;oEI(ONM-#b9PQF+~PO`G1eHeCGAB7doS3(gI#aOs`1p_ zfZ9{?iQVr6JDqoGxYbMBqS?=7%sxW=c;W}TZ1F~33_LS1_L5Y7Qg;5Onsy%V;w&v{C=scKF2`qX_w$snxLn7Dd?b#2Ies^ z(oU)RpdZAWqx6IKk$Ud~_c*wR>^Q5B(FTh!g>+9d#%odRh`qdvWKUCUR9edR@RLjY zH5u`1vgR-`vf4)EDg$>OxGEO`r#<|Nc5k(p%;x;M>x*G*=LJ^|uea*1E$&xywR>}N zzMrdg<$OWYzJ1mOujOj@=jL$vS$P4I1cR$daC6R+E^V)iGp-D2h2Q7O;jaH(`=zhD za`-clzx91-@O%>9lEdceubH4;u1Im=oS(R~7cI=Ey|O&#IhVHIo+^~Xn>5ebuf%hn za%r#pzhCJo;Tdv1e-ZV1%9V4(t^LN8!_D6tZZ4qBJ|l(%0Nmrs`GZS)+Z5Qso^oqP zT{*A0wGYiqR3r7QZHAOq;vN#H#2L^}eI;F_rhofFSNJ^*UyKtprfC0X((Q!Y1O-h=W;H~6bBfr<-C}CkfHERobrSnhaGz3!w2rJx8tqgy}`F0UDWwT z$?nM$*IQpC^Bs_UitG*2ORJLkpV7SWWz7kHJvTUIhTSM`t#Y%EtFjSvh%qN0NRFi+IA6$ku0CGboO~U+A zN49z9h37zm6MrStMr4*5FE}B&zZ0J&IPqhO@M97uHYi;D*(6BP3QqiJEPTeukKBCGgq@#{i`oLh&)$2q*CS~vdQrPWZ_O7 zW~~Qm`@D)$KNfDA4cEdxNkZ};BGzHyo-%Qw*VE^_w9`2*HAXsd&)IOfj5WDuK^6#Z z<+t00%LkVa&WaPbb^eMC=K<#dw_O0{;W7E|;i3kSPsX@?;7)OFD~O9nTK=h5S-9a$im5ZeiWR%XKEc5?p+&B{QIJ_UFzL*3uo2+LoUdLS;FF2W(h-}s|58Opo zCS0^mh1<+SOR!0`yzfOfQFbkQ5!;tOY0qyr54$Fv!$tG3^0UHrF8)o9EVEScVMf>} zS$vfdHcAkmWQ3)3!}l0r11LVm2pb(me2Ebjk81b~BW$#m_y!{^wJ>~u5jHxc^mQXF z9@Oa5Mp$NzM&C8UMunxH8ez2(tNNl5HUyVGXM_!}A^pn;ORHcv*s~m2YSxH;Q(>7s zYMS&5IkL<55 z%~WJ6JVLeD(ao$2b8RRij8UQikU8%aP<5E~G&BAhBTD^Be6b_Ei17E8^6UjJ`K_?U zkL3JbTUgR>bA+FCgnvVLYIC~$*9lkREM+}I@_!$`<6G(YA*f;(PW%UE{8ff(2pMzu zaz}W9E$jia#1X#D78ZGBt1|15@FR|J7vTn*zFv03zu^eKOIXGjIfmk)KP0@umfqfZ zrM#iG&Me_kgr7z~GDe9$t|5H+-Nt>4gi8oteLweqX8c0J2WGrg?X!{aNA&MPmERz3JK>Azk7Ld7D}=AL)&F(E5nK8bgsnr$cN;EVU6S&LIl`kH z;V%;|$3853zuplaaD-bO;kzV^e3rbAI^v&kg!d61YU@vbB)pZs0~0l$i@*Jl@bfl( z4PuB|jXvfOFYSG~F=P=k^j|`F8}?9c#xEe;YSULM;oaX%`?Ge!f0@Cz@FxBd!qy@B zdd?A+@6wmjK35Yb<-hHS|HKgw{Q*b(F-Q3S*urAZ7aBu4XNLZ+c7zjzC(u6fu8`FCTaNf25PrFp zKU-7j2Wh`>#Q)L}{*xp8A>k9WhrIhE`41YXL{UGY|B-}e*xK(aggYru;sig_h8KIk zgK)Li7z9KgciZA6%^pYiEy8cx^!u(OUOu{cpYqn3<(+R#aR?bQT;T|hcZ9EVgy%cL z5yB1hH*5UwApA%4VTB)d;9qcrUvq^2LD+5&A3Nd)<|)xr@?S*wdp7@3=!mb8ur0ox z@JDgpn`Iml{U;pwb&l};j_{9cVX?nGwy?C%>x38C+WTEwyx<3%gKli{Tts-c&0l_* zur*&DDzk3K-Y9A-AFYACTH;ftOs^=PI?XrM%T_e9gNm`0mFBOH#uD~OpO5{&B2l00 znIl^v+2d3~*}`X5Bo~xJJ)xO_gX9WFJGHhgKa}Gtu-ELVduO=Lpr)ZTg;wu5i1|niaxcn zrD|(#J*LIg9#i&YEVM-eEz9heQaYN&?q!AstzDmL{S7^JTHBaR1fxqM22>KMEqB-$ zED(;yGupZVDKjjMO$J$PvzOi=_F%8MxuK7Uz^;0tU1_3*s!$*lkNacGG~W%iiNbNd zntES?ZTVO}3&cXQu2!9KIT8(qeD!RgXBL)HwJbG8!#=eER>U8+%MuT;e_Ez7Ds|3^ zG&MAZf|Vk`V%k+*Otp5owaHj18zjZGW_C@=FqA-Jb2Ml#M!JPF+*`5fJ&lyjH&9!9 zGHkMW3DwNJW>}nEp{6O-g#6)Zf1=UZM~uev2SmO0tW+h_BKZ0+6S|VMqnWicUNFp3 zZGTzGhGNRJQhBQGDVE^S0~yK6s68{wuQVs|5WZvtzmyS=cEc^yGo9udt-)cLg&0xY z?5e^7>Gy5^`li;x!mn^H{nnRQ))K-z8loi*7a(rQa1pF9hm>jAT!hkBrEEUgtoHab z^jwQ^h9dFCXu>p`p5D^jJJP9dwnMXgshKq07)IWbRi*~x2{zBlaHh?nW=D5VCYpNb zfoW}-{V$!f^zdm(cI;x)L)7hP4y@AY(dl81GF9C&_VV&&RL|H`&@Mysl7^;+X!?pd zNLh|aTkJFT6*NXIr)F%;VC)mtLxWO1B^5hB8qU9k@x#~J6iXz#-wlzaH<=eq@1-ObQBos~HQFizcXS?y z(HCe9OJy%hdl|hnOs0EJYgRN?Uaj^fohB}hX+)1fNoA+D`(!sy1{&vx$zu>>z*J6r z?D&)uXQRFl!zk|87Yo(&sM3GkS;y>@~}D6HX@)Xk-9O!^I!e zCdQ@*m6Q;^hG>il5UtaPG(AK~wGsWsnq*8PgT^vrb51q=$`Dnh$m|fYW=C7fww~<5 znijc0G%QvFOJ6lRZ-((1lRl$8dKj51JKe}e+oh^dp0P7yPp3Jy(C2GyZaRbG#H%a) z+6L{W$iFvei|ZvD9~KqBv-jwoEiG|PIkuidnCdQeUmBNTK4UKBoPvzi!VUu|V1MPz zVF-P;)WzOR>vsK1yca@g8$shuJbijB8epr*#9No|UZ$HS=(} WmdCfu;nEJ-?n%v&n8BaN#s3%nvSsD~ literal 0 HcmV?d00001 diff --git a/rehlds/lib/steam_api.dll b/rehlds/lib/steam_api.dll new file mode 100644 index 0000000000000000000000000000000000000000..536aae5cef107a198366cea0d454affebf6156b5 GIT binary patch literal 103920 zcmeFaeSB2awKskyIY|yMVFs8$kRT((S5PBEG+_vx023k-oFrz3h)J*_osRa3;T%9E zA@L+OC&#JU>eYLzx6-t?c=g`mt;Ja15(bkXR3rK*7HXqS?T(Xbs5AtLoaejtnVBT0 zz4!Ut=lT5p`O!M(?6X32tqra^v}b8|Nc)Oiv4T- zf`zKxZ4uTV?e=Z`eZfCmapc!id!Oyuc(eBV)b7Q#cPn??+4jBbAFepudi1`uvr{jB z^WbZLc3=80%OA7<_%GXEp8t!kn{)ny|$j zK0v69|L5}x!dgoT$1R@UCnQ}k#WGnC&LU@rnd{w%r=9+z(RkeaJxLH!%+V#DLNCfe ztXXAALXzM?0*$C$;%O!~uC)loX@W4i$|Crv_(_ZK7}AMpootZV-_SN)_Zw! zdzb$Ur?NJl+! zVgP9V8IctQN%4X3(HuTJTqs()Eze+f<+M^(y+9Bu&4I?s2|rAkRrlGejE@chJ^K1o|461(YZM0cq~nbKIMW*K{rVgI%8L52T&@byB`$4*|IARE!EP}GY> zPVFo73dyf81{VdwKg%ZZ%`bIqx7McQ-)Y~Pf*Fm9pzb89EB~oxq9mC^Ab6n93V_Mc zY9&4A8|Y&t`q;;jXBuYTlE@)K#Y+>kp_i|L|F!h_pTIAa3eFmat#+pFb@*6!E>|4E z9?~dVU07Snft~KP2lP6Jwps)WFFxkpuh_M_>0Mh2dTKkQs57t1DyM6C$a5zt)3v41 zsmP|(3JDW>x1*%>tRw#LkBQ#8j~K~4)7IQcsclkTwNuIJTH&;G6*(0Q@3R-y&+YqJF37E)ta#aA%n6S`L1`8GRd}UnJ33q-c^hQ(FOP`lbPZ z_m&fpmw)X5QZN9J1E|jeIj#XYfc;FGP*BV#(yTPy2_~pEg#$~1mRHkN=(KG38hv2$ z%e)xBJPH=ULSypF%B%jb^NZuZ;ui<;iv#@PNX)9^@AFH>|0%zWhx`?OA!z>-e)&82 ze?7l^6Z(ILU%onkas2W%1Nblb#qqWL;`lm#Q3tK%dX=@|o(#bs&`L(-$-(2?TDejX z!X;L%YJ?4+G7NnRnILkCevcHLrLUA4b|59{r=yc~uT|e6xg$z#!>$ZL-ztLO+eN)( z6wI2xo@9N87@d-TJ~(?hIJ;h={7hvI)dqyFs5QWrP!A=eWD!AUC1KgpN>1iiO3Dsi zD^2f$l8fFJV9{Z!coG#U<3^}$eTpWzS4xVg4@J-87;G^y(3b1hNm{X_m(#jO_*^UI zR}wyjBy87-`LltN1t>v(mScGoTgx4-#f}!Aqvbk>?j8A+C2u|0`wLPWXbn|)w`gl( zNaocb{|}U(>K;*U)r&w5hoH=8S?}8t-664C47_N3#ed>58-Z zHqpI9v^B3W03*jN%|PWuzrTya8S7Tyz3#@8wA48Cl95tY23{Z%6iOg`P4$N64p}Vb z%Z{X1SYhY=scOGOb_v$Q1V3Fck)IrwkMYyrfIIjJ%l0^aLh390biw}-KXC}0pR%ck zZ{R1?8sn#9C#mA!;U{45Kj0^4Yq7J%=WMyo8RI7`uV2eg$UldloSdJW;3ucR9wzyS z@e>RT&QH!5KRILkofZ_{qsu0~qlWdH_GgdYDf2O@2ZL zCOWK^kou%XT_=p*t%z1ZPiy_5y4nA)4em*mThL za3^Xv9h9?mA-X_c<8T){w$DJ-HFkHged{D$;NYUt;)AG%S)yL#pXsMG#g10F`bsfe zVt3~$&ayzrQi{R6(WxdGZUg6k&CAwM1F}ko! zuNV!Kg}rtnUmHPy*+>wiaS+Pb=7pFWFBfzzry4~<40z1mErlY~SAY^30w%_)Wcu}M z^0!#)Qh+$@@m^ivOT!@9Dq4lr-79D6HuoCq&S_yR6oj;9uQ3&d<{b@tM#~yXLp+e!JU`Rpn=Bq_42LS3_4nM(_Li!ci38`p?oWJY%xnW4>XB zyv`oI2$mGjKQCslW3G!O#i|wAV79(vZi{I zmQKJpyYSV3uLq^DE+l^-d=EBpUWo3AF7(NMMdTKM8g>KnE>J;VV|CjU<=k=4jg8wL z8{dS{)4qd`-a$P6Uys{{ahLOP0|yM4TCEe6M%|C?Lt;?gQC~S96nG}Fu*Fys^UcT8 zx>AH+M^i@kSZqx+UxDniEfCXtBtA&?4k!sy>5Ak&A>XZkE5F{VY|XE>%Vm56`Yk9i zj`$pXNKfT&i%fq?EGZ91=jcV|;Oy=#*w3J%Iaql}A99~i{yl~rcJp+MPk zTl=YD_`@Y!LY&aViArPmbJhf65Ug;`4SxNQRyD+$hJfz|QS-u%lV<{RsHobh+tc)! zZlAq21rrxdg(VpFj$qQfBktAf+4TWEvk91O3`eeVRVqr>FX$8t~t!&p1NA>@iYAB_psn zO7)VVaK%s=djc!hgdx#<=oNO%1&3yJOG=izSIN}hV4Y_$By>SaPLrxl1?hfWt|mKH ze@j^bpg=5ieYx!wEat4YqWa)?^7$bY49v3;}VbAo^~$fL4YyNWzacftW6X{9E4MS%o7 zTyj#Ykk}mfYl0mGg>IxvyS*p52lNqiF{a${hWX?DXQKZRw21eg^ELfj(Z2)zr^ov* z6SY#2Pwa%Acf*VJm7eFAJ)^&JeeNoIp_^M3!AqtWx&!(N&2wt`1($>KKOaeV&U{4c2?^hg01QM&@5_wCf@4s)=<#6rO*xQj|`%&6iQgM z`fRN9Kn--4N=ZlpBw$tu*z$$~@*`t0AJU4P@-%P&uK4GVOe4~d_lsJ z2{_O4_G0v@?jp0h>c>8XS*n;Jkx`9qsa3Ey@J}{T{3P zF01~Q?eUHlFX1KXlcLFR-tqlpe+|$oF9Tv$lB8vy0R~BI+$xFfE8MX7L60JI0t9H^tU2+oM@UD~w;*|}t1)9c8oDwcMPP+e2 zXIx&q$9>)2<6Kgs=sH|7SQ;+r)v5+rNuo|gFN}s>UZ)#%;u8~ln)Ivw8v0p5z5pi3 z)j?KY{S7}Ql(f1*GVUarFy_h&c4QK2jRK{swkE1IX*wV?N!TvctXJQES^y{(zXtFbb0a!y=Ob<>@}W`KZ}Z z$hf(PM+jezEI5EQkpAdlr-4{PCV4rAxydXm7+*&8VAoNB#~GL5-RtixbjK4Y-~C|i z#Pq}Gq#rvc{rEZQJ?EsKJSY9LbJEY8liqty`nhw`?dPO7PQ>3Ff7oY4p2t{oySZ*FnAOH&}s$QyD3!Z9{J!A8mx8ca zOEWUE?S*dW`7C#&E=fP?IvA2l1DiE#jggUu68&iNF(o}Dg#^Emv5aQ~Sh)!jYd~Z} zVrq!|G=GhQ0%XJ=2tGF*^5Qbs2ao`L2%7?I5sHEciV(tK3%D;(+SQC82}5A-qJ}^G z2ql8lxQy+?S`+4_zAi6n{1|DBfK9>^=Az!s*PqDYpfm$ZH+$d`%9b#U?*;{)Q=Ts(gE)VwdoYje(j9?GX$xY-WyE-Ctde9Id9e`gDx?vn^#mBD> zV(A%T-zNF0kisRSrNP;VZ3qcvP^Nr$Wn@T1$f4$872JphW$e2b1KXev?`Q!18WgZ#V!G*FU_aqR%j#-Ah8CF2ETU|Oyrb3LbVROo z9c=hwzH&jU&%)hZ$eM}_c~a{Q7E58%5#_H9%PfLyDQtCEP-fSShA*5GOPyhdMY+uE z85%9lj$JPp$sE-(;0i>_*nV^NLKZAx95+lXjiNLJQ8O|;(+b_{h|~7yM47>S?3Qlk z{0{LA=mjQ&yw`SnEsew0{9RCl&pqgbc!qfY`)$q8m!Jz#3_YEoo?4oR@L-wT@{3Er z2$z6OurO&e7!&=t1dJ2^YRu?mv;<;r8x9j7EcGYLLIRfn@GMsW&>klLhk0M)Cr_EP zdyL^9Apm7Qo5QiJ(X3wB^Gg!UWXe-idL->IRy*7Jh%iTgHb*NxrHQfJ|Zs)Ur5N^Ud~0@$XEni^`XTbTGdJS z=kfw#KP>W>AQuunrLpcLF}srVD+_Wx$Zd^q2iSNLVZN#cR>PeT8-kue221l1c^cL` zb_Mwvcn%h4Zi)f$Qa$~Ckh1xpaw&o^f_Xp|4vnJhGI)&aZB&Hhifp8Ky=rWo)8G+W zk!SRA`><-D8}5~{^{;B+)PyubA7Dpg>GhSCu~8I3izlWP_)aL#g4_F?@~VMHkr{(O z@buU_Wf6Z4E`uvK_%qd71-M*1$KOD~aHy^fHlH2Bvoh3>8tVin6zPvDn%ohYuz z)V*0aSyc}>x>BwJnFKAP7>~BK`04f@coGo1y*-cf$Kl8LqxWI{c;`X>IC?*S9B<)| zz9#x0|yB&-3> z+hj+L@itX`301Mf@|XH1ur_R_rYBKUP9oxmMBp7A#5g>?v2KWSxcDneG->g%7?(F4 z+aUh~!~`c1z96AQ3kp}ta9fR%vNL50qUTZTMlH2V+o{$$>xDXEsl9+VXX{A{D#&kH z4U2@VIo^P5s@RyTQG9NZNi%Gc^>o_9KwL!F4iR{)eGa&+HX#qo7fD<2a0cGXjU!qr zXwgK`re+(e>kPgWFD(+O_>UmLSaCL&zW~}6NmTmUgwjibdlHSURQ#_KiWdd%PZYyd zWV)xuU@r*<6UBCL-R)yV%Ywy;B63!hjum-=OAj6*hMF}kqQbEgsEuFX7DT#Sv7R%5}zVIKVk|*nha{!G0;n@c6IP7 zf!GG+OPT{;%UnWAn@bBy%M+tCA9rL@uk^}MDP?E>3dt3qaJ5u~v)mGHrc7UO?@SCSJQ}x+;YK6{dcclG$ZL7x3^k3W1cRt&yoW%S zODWdQ&L_mj^5Y;;U=NOfJjQ!9@iFLEV?++@(1ZO{0M9KBWclcV?bBfh85!iOF8@kt zT*LD94U#OU#jK2~fqb}v;>Cw!hLYdbgaCQrg)CSgOrkA9Xpa_Ll8Nk}(k7qQ zwlF43PbZT`&!ygJqYZ83>WEGaj?5}_mm2Sy#cgCLC5n0{6p{6mD0*%}5gA{JqQ@r` z?c_!B=3qlC8+&GXeefovSW+CnzkvF?X${rWX*sp+%b+#aw|fZ^rDc3U;w!Sxcy~A1 zhk82MhdOBMobr}DxfHf5w*sW<$P0EN$SD}_+-3tEqvn`{i_j$i=;>s%O&q8-jxsNz zfp({G6BeX|@$yt~1bhG@0ooJQMqgqs=w&x4aKCF<%OyT_cgfhsl1g&Fi&HnQyaIZD z84k-AI^+D*AzSry&Kx9PVnVkh1~Kjh_^N~1 z*ahUzB?6GX=h9dnq>;1lfm0w3ZJapp{2!*Z*ADwNDNas(S{u<56s8kVZVR{Z3FL~& z{kE;?M`%N*20ASxc~z2<`2x)?vzV#~>`K$CPs0IlY&GL+cA4(WHjZFFVdEWggPE3( z%-~Us-^d`X#-6~Ss~5-AV|n>Fe}i7I1QoDSUg!_Lg9h;8hODJ6RVUfYGl|A_ZtanO zqNU0(-kZ=Ctroiumg-#>lK0LRJWTDq$3vOEmMWYejIg^o2nWs+N`oCJY^nO(c+bz~ zK`-hVM7T2M`h-)C-3AJ>%}|Lo7`j|+a({fFy2rtdn=+Gd*dbuN)fjIX{AySQdvG$0 z^GG`k{Rm$#r0UrG=;=g5_aS*c7JrXKD=x@SNBwXtKRU6ltHX5=xs4NZ+0F2}#7H;B z5Fra208PO*Cew!m_Wt{+LL4u5@ACqkbFFi(= z1z#Zifi%2yDkcNQ8cGfJ;@vpX_6~0$e^1Y#3~aV;F{}CYtAb6lL0z9-lw2X|VdMBDA56@dZLTIA2h)$rs5% z>IAb%urby*^bE=XUmVcWsT%Rcb1}Zi1YgjYiQ^7&Yn}s|wws!aXAL4m!sO=wOX+fCJo-H14-=5MG&s9}YP<``7d@*fA4XpQO@ zp93{7_&5eL29>4&gi3+IUlrL+G;|$QN0M!ibOyqA8S0;tuoqL3)i<4bIt_|^3FKWM zQ(`{t$kT})$VJSF*WnM)b{GFiK)8uE5*#dHEIYbWs4A!?bf*v~dfQDi=VK8ZV)T0rxO>08_pF~T}}zY`Q)LeZ={cTtvuQ zW_*N0nlWw7{Wbi=7KbwVDFjNH;_CPfrp-c|ia10i)pdlY!P}R_)(QlcQD7r#4ZK9F zx`CFe)1l3{C__c0IpqnC52>qgLhk3b-^?B6SNx z)NT?Ye7Zc6K!FwrcOt=RA3;IH9AupYulZ^Dav}x$U=}u1TP%KdO)4N(VzY*+oQ4v= zkKKqem}<1$tFGaf%nabsP%jDcBx9S%UdJY`Qr#>HT}6@rzXs74^g|uW>`o3&auNl#qJvwh*v^dk74lM!JDX zS&SkZ<5Z~!g(gtNob8F&Fb*V+OKG>oejdQwjImalLm*oJaU4_}A5MgdF{+)DO4Sam zUH^i1r;b+6>8SLW6ao#Z2KK_YWfFVP9!)1YSHYOA1Zi!QID}$Ke0(r6oZ^5`SzeX! z`wE3%D2vo|o)xl?`$~Tk9xDf7m;uu(_#4C{Xt`9G70`qQ5bVRI0a-IT3V{HK$6#QN z7>BBZPMVQGNUD4#8&JY^eV_jvZb6)))xb4KriFD_kmNKlx8V6Fba~QeC_{$QZzz36 zh7ShjLE<8!Iie)JR<*;5cAIqU+%UxCO>O*%`>a(~{d=SOEu%)?25Pas^7~@8(PuU+ zg|~H+j$3XBs!>L9in!xC4}5ZlVl|WzBFNef07Ha>M^yX1gf_)>j!k+22Mtd-A})A$ z*hUj*paNY0kfXrF)#392<55F#7>b=kl-OkWHnBCtIBDmN(UPLzY%_{u2t*sZ-e8AO zhfc(|IgD*q!o_ZELwkw+Hk&tw;*ZT>UU_4kv;Z_!rnmokt;bFHSzH~SfxSRbz4fSo z0GkhyzkBT_GQy9#IyG+}Oajf@k1=Uph80TlLNb8Rkb3J$v>CyFqk?wpN$qd+hb_GnxR%)0>0P&VIFh}i`Nd*g z3SuSeQ>c8B0W+&g(iBOpvkG;fo}&nN{xBJt?i%ZM(f#?h6gHJW#F`UNnG^x)v~Sf? z*%q*d-tZXFx=3W-MoQaDDN zy)unuP#S?JCv*PE=P7Y=Z8g>cwL8NQ@gZIh(1sGC0bFEtu6GS(x<$2KBWsinqALLuSmnZE6J_ycMIwG@<0X3v0- zozHHZft8Pm?6X~#JOx^Ls1!|*7el<}UHs&VY?dO`=hH``I5+F~a^GHBA-<}9)qtO8%z34g%@{L_GzTGDU0I?yrBd>-ilX*1aJv7Yzfo~znpMAOl= zM^5J;FrFDS9z+jed{Bg=Kw=q2Gk)YLz&rX5!1~#7s%4HlG?{e1#O~*JX>q#9#j9%I z4`>~71f7IbEoK2+t)J1V`dtUz?<-mPC02PB+XI=6(PKKWa&-*QIhU&grM4$J5E%D+ z8iw6{0>eP+O=|T!s3bpQU?q+w4MMrY&#FPIN_E7L=cprR;Vc;Aq4(B8_i$nMF6C0HI-9CG^q$VsDQe%m&c4)SF>F?B=M_EK4YGqJk0JTJ z9O8?9EE4^Kyc8NzUTmxrcTCo&+V)urwW(1Ul)uEpf@*!}K$+}5qu8lIG`%HlwN`h0 z*<|HlR~ptilb1-yh?gFPFykT##--A@Xfi!Sx24F(p*x7yffIlC86raje6$72OpI>7 zyOIbNy^9ECg%nZ^`2$x+-udS1+w6`!(p+>0HJx3<8)ni(z7EOFo2NM0f&{S8Sqgv* z((23Z!1p*{vPRn=j)-w&KZMZ%Ui=zC_#N~`ggBr(jd17FAM(Tuh{fOnfZ@A1{f2C- zzBXILX8gOZj@DJ#684lc8^34(I<-^P0@eUsC#MV)Ev0Cb)9M#u?Nz7VS3gXatqb33 zNmIKm>VQQV#(ecj$({7DKsr|aoCw_z(*yhTZ47p+1)GNRonc_9?e zq>F=za)~uBBRB|bmWDlBk`#wpyd?>pSZFx|WRFONaU+@R`U<`}25kFM!^N)_si$Xe zPgXmewtbVscfGnoH7MChCwd|{{&zJCJLBsDVq?oO7i6a{0#zYTh(=t%HX-6B#tUyi z2J)&#vH$aqs2jI@*^X+vqPwsdTcLikS^iknHdJjOQ)gn`GQ`8HbX#|dznqnzd1Ynv zs)Zi_S6 zl#BDdk}``ueL({83}C~Nt%~G(t#W_Wz+2F@;5?YM5p|dT}cj3QL@aX+`oa!dP^2|68^J(Y|Yz=J7QSJY#nEL0O9#*u8zuZUB6b<_xaQL zRdy^37dsPk@DME=SQZpmdP}BM7QF&nW5N0eC;r%Ynv0b0JPerAcLtDhxB zCH1r9XtMg5IL0l?By;+1iq3Dvv`{!+K?~-M^o@M!L_W#W50OTi!7K7gsGUZ{|4WN4 zKItv9;`C2Uf6w2Y{x>lFm&K-k`q=cxp={P>!6}0&Z3!e1FCrZ;!cwu3mI~W~uUjfI znHOp?CBLd)SrA}r)?wa<=n^iN2_HUK4DJAv1^nzVO0dg`ubY#IL9lMt%#STS_#zsX zp7tkk9vRu~{2|=DAqNE&rnMv5Scs;&yXtVQy^Tsj_^8f4C$U{y7A#m)IzJ@(wOlG= zPfRFC37rQ6(RJhnf*VcQP4zWv64bN0Uu-<>#5%e2lhD~})Yyv}0eyexNQy2tlMSJN zq5gSZ=buw`F^xhd_#43SJYekgg_{*($xVK_4(5^Sg|tL z_i@-66YAbMQ z+aBASk$NL8Bg54iy#5)Fn{5LiREQG`Ypsgg>u`T4#yGZx_dDjgdZw~ znxE$HD~svC18B&XUirwYglB%8ecJ`>xv_TVpW9CFj#kB2;4HGc%GsI9Uk&<7F0( z8h->Jv~8SXq-3GZz!6ZJ{S!7C(St6--K}iMFQEMTMkAe`8ZH7CJVWM33iD>+V_9`} z#m2si`fMXQVNEz1kE<8hvBJQ;_;DFj4W{WTh?@b~%th5mG^CCsDV6NxbZo{Q&@VU$ z-2{-d&vc)%HCaI|zmdz^ z8E%{;<%->_&f|v)62cOVUeu<&i>>J&F*@Y1m6$;SffFz_mUSPdh3cKPDA}N|Gk|rv z7I}e?P|jwcejH>fVg9hsEI8}(U0`ME*xr=TCAzKF(fBnuY8Us)4GxbHj`S- zuf+A<6VWb`mvQG$w0Akx$*sWbR*Tw62FW@zL-{NP)DvQXSv94yVvkoP;=QOAtci2_>`Qd0cJcZ3T9_ z<{=Zd$R(27`dZI?Y~v<-)RCFBpK=eQ_}XD)#a6w>!BL>beS@yo;QHgib&y(GYV;A; zu}bY_5uAt3c+>5uh#oG!m8d_0j~%3$88ayZtd_18EW!k!;8P5$@$4vmZB19BQc%oB ztf~Wad^Ha>0<2*Z#}{(g+>Tm2ChwIHiu~o9+iJIw4%q>9@!}bf2ax9l-&ugrH$N+m zx1)Uk9QZyT+lHb0nF9qLV6|-9Wqy{1L|F9F$+X_H@QqONTc?AE0bt?#w%4+ZT`ixAv_1_5>&vp~**>T>!wa2H4w zI%#Ccz?fWvauGbrav}Eo*3~Wdr$~UcIX`Q)EO`n}f*7@|Jlsqj_`=OphRB&S>;Xia zRK_!4%4{K6C8G!q{Otx-nJx$iBOv`Vz@11hXCUztN)T~kWLIVeiQ?=+z%-qvbMQu5 zhFr?9ZrV0NIgc4TZJWlDMlK~x#SK=Y!zQB_z~vO^T+=b#ZSi0d2cGT+UvM8aoup9~ zdkk6ele8s&LYL$B|1o#G2w1DbKB-};Ab*RWrO|3L;Q1j9o_eFe!tCMHBspa` zO_Ki#4WRm+pQEwsV4>Dxg#_xIIGP}%M=At?9)`|=W`WkdtTCTMov#;?r*;lM$-txneV=h> zCd&b1#4&F}D?rKf(l(41KK|VVQ&V9Ju3N}TP3}_f5`~?1I(@$uBwVaprzXFiobU<3 z1u$sESJoyo)rRR@jGq=S7W9+(Y4z8ak@Gqo6W$>5~w9kIL9cD7e`Ga>QOeIAT_iA1WxXlgQxE2sa}?fl(v`3*cq&0 zFcGvCDkFrrl?2Zvjy7RbXJT*Z2(VKC3#~_n4yr`&fGNU01}XSVv;&0tB+WDocn6Sc ztQQ-QAkM#@I3Mg>4aaUDjNLwWk#%b(j?nZQGDY|6^@Z-WnbIydc?s9{N~Qjg5Ma+j zo?(-7*D-p-P-9%s?FH8YXApsJXn#QVrQz+1{=%e)?me!p2Hr>6-@rPRY#txmJ6a1L z=`^0|HAmXGoU`5vwH^$;4Bx#d;QTzbfU|R20q5pyweGN>oX`E&nV>M+PGG^RIA*l_ z*<~OA^dqc`Jv28j!oY>EsRF03b~;jf-PW`o(wkQ**_y7$3l2TquPfG5G=v6Q6RtBt z^U#i`V}}@)ud?FGzU$b^@;x|Zhx^*tp2;49{Z5L_*7R4j!TQyZ$oP;*usRd2))KA- zai5KAK`qt%bZH%qOC=ngHqDcZ*|mvg|7OC;OJw{LGK}r9%81550hT6pmqWBQ-%EYq zVu-v`?Un-3$MXZ3N*)`nGLe#R211|36E^?|)iQf!n>aE)Kl>OJXsyd<2jW#PMZ4$Y zi7XoDQ&olc63>VaLIzvAHJ;cq(|4bKDN(!{q$|^dIS!9wPrTBtUtS zy!aSkl@&f^e6q2^8op_omDm={=_fBKs2gBKSlqy5#qzvjWeH*)@F_S#E)-lsJYDA`n_Nlu zN0SYlCfoo(#x-UTfuFS_1`LXZUu1{$d5{mEJ7IjCl|%U(a8M864vL(HIGGPVpwAod zb&S4z137724r2toHHeuDFei3qYI_6T1$i}_j#QYZSODgCewyskQ_U6cGIRY~U?|x@ z3OJhxp<_S00~o@WM5fjw0HoJts=KTLwig}}Cnbv_H|TsF_&M=C z9UiqYQXbxM(tXX&)$T1LyH@B@=Z9i4LT^h?V*ioaaJMAj-b&@raI#0a5C}jZ0Ev7J z2`nV`ZDt z6VLRi7@Sb6r;VMWy9dkd&Pg-|=~dDN`O9t13_6T7!i%H~Y|RvgMIXP5$kR=|Foo*{ zTQhy0U#-s)Y|V6ohdmE^s_mp?V6grXFxbzLqjLp|^EdV=r5Z@VhAjAwhMl$FXvz@C zcv`|-ELSe#ipXj9Hc<;rp`K9lP1Iy-c~^W9u{CLc$d(fDcD__xiC1tJ?gZ@R=``?D zB~FcQLJ;~q+`&Oy)7oS)m<{uv{o66RuA-zDsS!IS=Z`EK;6oNPXJrT=kJiX$o-RdDMZTXVzfmUR@uRm#fpb;;68bu+{I>>Mr zxfTb%Si!^VMf$+lAaWKM+p_dz^nja*$Jx(#SRpOpaIp`n5i#F8xa;>u2~)i%A)rjy z^-A;#;>5b6;6%OZq@f(=D}02tJ$zMJ%m?3D}n0_GiT~x7JyW< zGWsdOPi)~{fmgLIdu;LcD=Cmz(kt0)6tkr(nIU*qC_u@|s`#K0Ym~*l!`*V3>OEFr z+eL(-t=Ygz78m{zTJcS%m7o2DD;y{LUnCfu$;fu`rt+^K#{Glf8HBDSzYm?rE&B2H zJA8udG2Ym;54@SMZn(U?LgRmtud_~ln)^NZyv8rc!-w-k`+|4fZ`V#9_BbuJ<{yC| z__qCKc>#r|n2r|}SSxiQI`iVA+r{td+Tm*20o}v_G=4!VdF^^KNaeEpd}XnEmp!?5 zQGTUk+r@fm7A^un|ID@RQ?f~QLEW0b?4VYufp3>Nqw~ys5N2Ev`;kc!XncfDR7KqB zbO5X*eI6Ou0I7!J;-M1}BV#A_UpWPpTZJdBB{dDbx^om|Q`xza4FHa^#zj zOm_i4y>~PkPu`C9R`pu~`B8sMWpN|I$jd1Jjt`^-1`2jFCYiLPk$u zJZn?*)+E*il?*3j1i@FUP%HQ_cpu*s4Yts;El6VYZg3}0aOrzDDDwn&I=`zHPz^!P zr5@Ty=;WDd0aX+b_ESKW1b!%$y_<&9MkTvR_PSH3;hT3N`i=Xqd0SKb+hTHRYw83g zO`*qCK(grfB7^-aG^3GA%@L(aPVaZkIx%Do6P}5zsR-IkWO*O#IT!cr-J%ze$2|Dp zRu9C7kMlj;tcdH7RdMP0R7^-u&P3@!bui!@lAKr0V6tQGc2jbo=@0_q1oZ!o^2Sa8KXw6$m2@vHz<~u^0PS}yXloGu#S=c`+KA8eLuPB zj9z^G>GxI0tI(s3r|FAPO3DkE1)-EZj~Z2#2=$Ho$h{Jxuf*SO+yqvbQK+82y!J%6 z_%G_|Y1^lU($|9t#oum1Syd!u6^&(TrMqWN$AV6^LqdS%WuOGI>N6K z50-oqMe2n-{Lus&+zZw=6+h^m5quI!NDs*c(l8X@po{GtNYHxFT_t5^{0ub?ha`4n zF-bUHhOXkG4n66l?a7dzeSs%jgVP<5G59uPrDL$;~UIGN)^S(U5;9RxQaOg-qs58F-X zqKf03_%l5)glbxARl>g7mhgqu`mgXYktUwf}Svo)q|N zYkm^hX3(b@0g7l(1by}*@-%41fFff=t9wVob;r7+h^xT6`%LY1ECQ zG-G>_h0mu+gDXJ};+mJq z8HRG4Er5k6H^RO^C6fg~RKA_~C1(f(B+&<#a1{9yGi_F4w+>(~0qZ~hj43t!&aWUR zcF`r^8m7YO?|}10Dxu{s&QECvvA4~GlY0+XHGCg~9qcwUlX2pW&&45>@O3lH)ATe0 z2qxEzj=J{-=s@fu>D24L2`h3AtQe%*&SpQ9EonL`Q7AFmICb%(<8X(&L zyAWR<2a&J48LS?fCU)A+V5@^HRTOhb3oYpgBjXv6ZroWN#fSy_c6!{Kj9kpIK;bgl z?b-G){#)1w8=fEVT!m{7ulclF8MbPOppR*I?832qGsC=b+i)oMnaau`%=8Z^ z?M3XMxY^b`8%?0e!xc=!t%417c^qK z$DV^er41b%Z=PMN>7K?>^s2l;yEA-PKXoDsb7Cm?ISNbJ6pjMEQO<93)BP3viyp+b zCg#q@N2BtfZ3WpGq$evc#S9#v6AT-UT|*Xpu7&b(QIj0k6%xAv_+Zt_UvHJC^KjCD z{x-f|={K{n?bYyCzs|v`nZC{s!o;ysD2-vl;q@N-1it0pK+25#aw~j~c!_~M#4G?h zFdI3hXh1vTux=VynMW_-W@IBU!&&yE;f5xR%c4x7bMdTU&nk;NGnB+WE{6)Rz&!sw zUMefy-Ex+ny+!X>T|9hsQ6`&~ygq{Xax4^=qg3x2i}g`Ip4a(tYGv1|98rKhipZtE zk;4H@YR04Uvy@&^zu$#^!Px|6RGGtGMkUoLu%F`DEnxBC(OHCK^D+F*n7M-uh3?w( z*gwXq-IJ)s{sawydkhhv5ME}68+~pfp{Lni0UBzbMeZtRTWJ{F$W9wZE`kNi+5Z9= zDXKeaW0xi%QV>?$zOe!U3a+A$1kgcBIXgsPOzj3%#Uho#K7}Ta$>Vz3wv#;S9z=p9 zWIGv<; zo{}I9_D99}4jHo4#<>EqyxC42qsPTol*KC^J=WA&482dQ69#?bFr*?|)>3 zKls=5HsAk54^K7IH-$If|ML$1`1hCac>ICpAv|<1{vL>^g-_zWoA+mdO{_IDD!X=6 z3-{9tE}n%6FFGd*6S`XSAbyREb_je3i(up)3 zNcZ4R3y|~3AF{kMOB6c%P%N*RRsojv4zvc4m+*)gkwz|&HnBCJ4}y$y5A((Imq6!m z{7k;)^H|Ap49Diz`G+vuWn6SwnI)|ww`AZTSph53`$-=RO1MOmQh`? z^IGDv^-5}MjYaKFg7CVIoWfb%vxFGF>1^9~$o9N-o&J{kktj>HR}QHIInmjTAJRw8 z*!6Dc?IH$nsN4bCIjB7rygp?Gc}cyNZG?10Q=o&jR2)5F1@N;M$$9T% zg*B)R9bkTfO{caaa1-B)7hLAKS1E;Ci)xZLFvriD&G)l%HrDkWNMOgCj zD(UV{T4hZ%g+B5&|l0+N7N1`R`!r#>aXZ=j@g7iH2$RG*4F zJhA&b4!XUi_Sq5JItdrEuzY~A;)|3zxYi%`J_kweg(QbOA!jwdqzqw$9zW>r#7#*A zSKH80_(8hq)<%|xmP@O+d;iv})s7Uk_>8f++hYimwc=#F%o8T#`}9b-T8giPzl1E6 z4o}#3rm>4(m3z1Lx8;G&`6VCQnx=xTxMb+=v^5b2>zQhY2rfyEyh1hU+~|XyN%{x* z+-Rt~?Nt%52t#&=LWpU7D^*hn6=%4Gw@7n$ZoMjole#fkXxKQfLEY#QO#JZcoDAfy z6m%O;G}J1ug_aHph9 z0m%+?4JsGtr(me)-Izp}Ovy`37Nq_PBt3)NQ?>3?vP@U1 zXOeCA(| zf4?AVDQZ~ml)q?AU3Rm)Xj!d1f7y0<7R$kM6%+A)h6G_zC<5EQXd$z53e=G$I_bqp zU^Bepk8~9lwWbDebkjsJd*Qow{YLOWapT@iCepT7I@FPJ+XFuW>EvB1bK07Q@v5>Z za#^vwQe~O=E)|D0beH}?bJ!Bt<;5p?F12oOU5h$2{=lPz2 zr}4z6DyiB49qbQBaHHozynt8KKb}?lM%6<}Q@Szafd=HNbtCu-APKn6=s&3J2Kh#n zO_jaHat_AdP6~><@zzn}RZzyK8m~D;#orn^M1N*I`Yrev-{Hk&goIUBT!>?pOI%aeurPGz_&8B8cCa{)nuvH z+Y`I1DZpIsW0@ zYmEKT4OGq1*CWs!0A8W5--aT*EHIcngsautz?@mtH$T8sl3O6@$`)C^w9c;SmRs@HOS&<{xUN{cH(q4H!wW(u?!eYjDYjiL&_@*-?rQquYyd@$Ms= zoTcw~9qargNtU$P;cLY;%81&RET^{2E-Y5Q*swmLA3b#pu?Y*`c6F5LZ{yl3$}ELz zlrK7?)CQ2m>y(ij2P#0I5L^yN!Cq~2DHgGYm;VgJl;=Z<%Cl6KE?bM`WMsFCuw)|b z)A_H61tZcvjoxXg(TDg{yNqyAR=~&V50Ij_J>R2u;*Ue)FU@N8*3J*@Q#!--_NSkI z`UN_31KCh{;Tx|KkKnuXEq2fK%Bk>ubCG-n+5>qK^42M*;%iUiU=~7cX#c{*5*%9wX2yj=&zpTgrE2f8Mb{rwtdOC zS~zoIr^gq5IGxHv&NB95gwJg2N{bpvLa4{PaQ|(yhMVb2qv+3vzNxB@+_LQ8CUkeK z9QnwF9UDj#2hgaT?YxB;eO0UiHh*Ikf@Cf7N&#Leo9K4Gm%1UFW@^LQ)VcQ7`%?&P zbQ*2RGbqbRSpd{>e<~3yn%43-f1$Cy8Z9%)*xlR@Fh2ppu7j8Icl{B{2{%opM#;V5 z8=dNz+1n>Ktera79xip_*5Vhlw_7Rc443w`*rUl^f`H?>+OGKSa}8pYpmeRlJW{$T zbUrowAvT61yZJTd)m!Ab>aN@ISrdJG5GK9^v#=CSY8(o)xu_h$aqO>WLkaOc;PxN_ zY~8v1uJhG6mOc+gN#bPota&o)XPGaPN~B8K>Y&bRqZz7>KUXJZ68!-JanZp&nWW`n zE>k;9m2$dJbqh4BHn#(NVW=+U{O%Nb1sQO1(GT9C%go;RrKe@;*)NspuK2e}aM5fWvvS8R9ENNY<^#d~!?+6RK8ug;M%ZsKk+6$) z0~rhqx24)W7_1r10(Xqsky9`PJZt~lXs|CSN=in}MuYy6jID{j;ca`q8^$IBip2bW z%Ot z{K-^)CC#?42$FJe;3*W01M?`rn7j1b4(7lW6@J!7lZ2S*g{?(&W93rYzU8)k9r&7r zx39Hf849IUZbXd~SysD8wta$7LbWRi=7G|Si9;x=+J!H`^of8_JD_(1x9*kXm=pN< zX(&}&X~lOt!rCeTx^c69)n+XRmo(Ilq&3P3{d4vnJWK=h2R$3sCeIZ;?#^w)1iqf4 zhH^mk@XGUFI16YElH|EoIgKDUHVsVxRVzn$8v?pxI?Gg5_mHZJ{vtn@_{7$H0|3Lc zCOP2u0t$c61;G(qPl7Ot0~ocW&tL-|(Corb$H)t%*974tW_Ln(>9Ytc@dri&G!;$= zJqvtHa)H0|V{0Nm#S1OK4N{|@`TXbV0^D{&!{^YD0+RbMiOn=Yx`JS3gp|ajWSU+S zEHLH7$A(@&Wvx0`t{0GG81D@iZGj2<37QS3kaQv*==VrKLKe@Ai{MJJtrz3Ny4>~- ze_Gp);z?hk?^j1s>g=2KwJY%#2d&-%$o51TFDW3UU64@DZkraS_2lZ13Bszli6Z47?8WhB)qJU7NIsX3)EgaBv*TfJrJ?8h(j>&Z_0893c zf{{Bg)S!MJQ4AT?_&f49>h}@JkeY?m47jtOhtTb#R;=e{Okt&dAB}me!nejMEaw%B zeFTqPJeHq@S8CW{He3bB9{s)pNL@~%>||aq4F`V^@x!q;X?KC|N*iQixh%RcR zO8GUT2)SF0KR+1H4pFw+&8NEC&o)qU!W`r96oxaMZOBXThdA7)L&34A})ikp!OxxP#a1* zzN+%TY%4xy#jG!)mnw;yZ0--X-k>8CH0II8ooEIFshkB@L31G=?%Z^}u?HlEFLyl- zjz9yO-bk~DJI0vh(^5Bh9+f6U=Ra%wQStsF6HU3VaSK@9I zAKSc<_zTdcw|b>eQj2%ArRvKr?^*Z-GuVGXQ+EqEGr^^rma5S%@0UU$AmV&|i-?a- zhLZ7DFY)It{McC#RQ5(CS!>y}Zr%ZckRy4YcSN3K``_$+dq7mzwfBJ;U%I zB!VG94F)yffI@g`Kv58+ii$D_h(L#Pe55|c43jdPOkz{ho3u$AYtq^_z0GaoBWX1t z7SyDvnlv$uX-I36GacJtrHYX--*4@GW*Cq>?!Djl-9Nq$-Lv=E&$ZWH`?dDkYahzL z4s|dQZ5oIWvklZavXmGi#cDb(d*Df0u>VRAJOtGv39NK>;zox>VB6h;G3WraA*o|o z&>aBG^B1gAaM@~{bG80}QG3u~vBBQe?;HhICo;2lePTZu3^!t6U(1=F(^dIZ0N856 z72HU*nz_@=-7=IHMyls6zzMb@AfAK=;KXqgO{TbIZbOOSmMZgIxj|4Hvp71wcOi7r zm~ZTyR01Auq^e6N3=nt6lh66C#8ldbT{on^q4nrGX+6SDXNqzbs*jj5BTeg(rp!oh zlA>yY3k#R3RahENJx;>=V4B6E)Rufhv%xbCvW)D7W-4xPnyMX{)P`@=o8QmQ0Mbor;BEcAfx|q$>MTnJ)ld8~mZz!kLrB^c| z)9^4Hi8=Q{7VR65tpj;Q28DX&gULmLCp!~RQj0)Z=w4IzqRG9`UohW`%h(I<#*yD^ zFD_7b!jq!z`hy*kej#89Im3L6@7;Ox9_Nl4uzZ!n%SM~ z6v^qJb0&UjWT&tH3(`8SX)qzCxO&s2w!DRiv^?>2B)}VS1|$61&h7tej>_tG-9^ z#uJkhN~=g?)pg#^TxnIXa{Ovqj7@ZW9e5!vTVm4&xLU?&Cu}Zu!sa>xXqun+1iww^ z#HL4a=#qhT?=y6gmVEF6e#J+&!P9krSIUYlqIm4Mc+A!u2N=6V8t24gO>GD8SrgXQ zt1opr9zhClrN3!H8gGna&4Dzt-9?9Oz-==u=Rtm&ZE&^}M%j*K+0vKSJ%VLO?!XLLF8{!G-S+81X}RswDk;;}qx*pkJ$&MsMmNEcjb=8N68HGrvfy z^uQQ<5yO29a?C_3y%pkPhcIa3G8(!#V?MuvhL`f}YPw_u>BPVoa&tw;&#(ct9XEA4 zno$^12%PTSq$>Ct>*oo8S#*3KK>-+l44(tRa`-@y!YCW#EkrB{S7?78(MWY4ATT=D z7MuF@Sh;%Th<%Tc6uE;u753Z7MiBzY{W{{u@(Y;7rdZZ|7V!}s^WPvodKe(td#iChueVN`Y45GaQ6unjm9>?Pqk;nu zPz0$~YZ>I@S!;Jt|JEzaQX2Zys#pfRoz;`0XXbcPP#$UPqv zqhXwlC~3SjjBSF#Jg&6~HiEqi*i*uk5D+nK7c40d;vAtL6FchGOx zNRDxshIO=*Upc5``RA| zYN++8JplPr<-82RvccrRXyG}18LGEm?CytGN1LFW6{XAg{ zZArLvm4>+g;&FLN_M@~^0K)0Cfp<5;=^V5JJfso4t!8*`BPOi&74Lz_6f}SEFbwt7 zf`mFgi^sDn#A_=!s`%BmNI4dQe3Jqvm={e;)C9Uuc9aGOFD^xRcYWYxs8x>cg_rUS zo39wLV3?&?>b*$7smoAWD$V3hJu*K^<#@*P*$pezgeB^mkP-;Y{4e&SClCox5{e}m zSNguLFhn~YPr^q$9O`wEqo5{~-A8rop%1Xm)M6(1hQVE)o6LNrncjmGItWs_!^*)_ zSkaUhc4P97JX7sV;L7W{jVC|{rv}zy<8C0W*BKs!?e}VxlJ3$fbraS;g?K?=#Xhhf zJwioEW4s5+p?(6T^!DeOU#Y?t7A?AFwhRC-a*X1l^#bp+Eoa9V2Cdx^jiKA>FQ?`wu`x zTQv4`m#7|R-?U9z3yFAs%89)hlV(|5SORgAE^ykg&G}Sg#m6WyL_fir8DrlG;nk5P-Zx9s z?>`63Oaq&w!?3&mMa&=DFR++v*v0-46jKJX@XdknkLWCuhygoF@9f`Fw%)N-D1xzU zju1}ILXM6u5bn50uUnBsIdpD6jWr&0ZhwT$9v9>P!SASZfO+hi%>YiG4DH*Uo=r8; z>Xb7G!X1qpP%3urb=nC=0x_siK~1;{x?`<`NABVoE^rFK51Hj#aX)Q8lB&=66QN~2 z5zhG@y8lK&Lor_iSlf~7T^OkbWHpOjyk>TA?!h>lN`W9wL(OQ_Lg(P#xkJ)COH~oog%fkaADm%l zr=b}&wj{VRkQy-It{zx5$FdBikOu7fz^;ZtTz`>%>j)*BNm_-sFH;|W*AIUogvPz0 zDt6FVvyglx^eMOFNCeqXB|aPw;N5+R*1H4ydMJxPt5P2-ftZ0S8dJ5)wH?1s$13`D z72vni5rf~=sEhMx0{I@LDcyOr7Qg0eXlc`H{=It(`X6o7n;?S(S@4VKJZXipwLtxh zI{dJ^_492v_-_4~LA&*7UuCy0MXUQy`wJhb6&{Mh8IM8_2-W%Mw=JO^j+OX84I~Ep zZ2U5r9Ozh4`oVF5JYO+Gm$blpkm~MrQB2oC`cYp$C>iZH@?@!>mEtCGq?RQ?w(HmgyK;hUNwei~URE*=f(|Aj zQ|G}H{CYOot|!WoEXuvI9t(q2w(AvAiS2r|w9IzBUdp#!-zw$WuCI{Cd(!(IR5ees z{YI4(XTMPk*42$I(zt#H)zx!{D<{a7R4e@(hoRp=wf02zyQtp%F8Z<^rI@G!=`^+- zrQFb>nXu&Xii49z*j=Z=>R_eeQ2?}4p%l@Dcu(MbvXoDS+3pkA?Q zB1SQVm8vi(6&JNRwuB??N2z5{liz})Wxr7`KGuZ2li0Kd%XE|{HqmCUrecNpyx8;r z{KQ8eMY#ROhMhU~8`Tg8yHO`Pz5y={3ksuavFRt+Yq`(h$LS#Wm1h_%H)e>Ahp}Pm zU=$YQ-UWB!dv?}?XF!{XgSvT#Fe3vZd(1Olp5%2AgoA3g4SWQxc1Niq;5yn_ES#jW zN_#eHM96$Gyj8X^e}#=BUPkxL`UnWJBQ;i7+sVo(bRDJgT?b?Et3HGMCL0^YruR{g zK>+k3j03=WY%ea-&;Zw>F#TtWjSglM0aB0->QD1n*`njG|wU(ZDg>;-c2j&=9HnLNt75Am_J<2^I+JWrPKw;c|h72K&(> z!7M%MRH%&KZoT0^SHiy0HzwiG^jvFK!KPf z9GJuz$?@rd;}$C{ZO%AIs8+vC4T4>O)*9oGr`AnH$850SID}ruY(#ds^!QzhZ3G*f z^g1x<*chA(X2Av8-)q`W!I5%bL%+qg&*){S>10Da8W6d&0d6OTFq$xe1_7t^4*{=- z>HzRq7X~kUNY`l54MD*}*L*l@eYj^>-zUAs>P`fxY1`S81ZW9g$pI4I&>6IvL{u5^#d|MLK75v3xM-L?LE@dJaec zH;X=iSunJ)Idof4p3-ht8^osH!%19`re_g@*d)L8c^set3cU72%>8CFXo!5wVGfuxoT@1NorIP&|fr`YC~$&tS- z%kIef*yJWwYs(X~h+tE6cFGL->rkM+sb!SydYM$2J@0Izp_xsX9z*jJG;y|^oyY9P z=`D<`?mjLa`cyo0M)^IOMCtrh(7C^~sXA9?$OS`m&LUam%_1IRnczU|!?0flo%^#d zit*la9tgXfY&pY%2BqdHAu3%aI@V*Dqvh2E)Y*A36L9cp(7g`(RXc9B%;eLHJQ9;3 zco8(M2YJR1YS#$tW^q?qo52#e^z)z?ZtS*wF>E)sN^5L4RzO_&XdZIg+R0`c>K)QF zAFYqlN)6>pj!rg5)+360CL(IRhStx#I~S^_@~ErSB&>9kZqh-8*D}Tc>q9;mp!4A8 zG-(F&**$2-pmMfSIUV?E4$bCE5%*Rs7joQI{Ay)mcj;eY=CiVKBGUASzz%W+bjXJe zwobT+Pp!X5M#V*gNMdWHGsyiK0u%=uR8a0wd}%94|C&Gs;%UVhT z6bG%96&F?N+Ijm~;o7@S=H+Bw?vtpvhC3~p>*a7@ zZ^!z!k9D5djoxq%UO~aOuTqQkKw;a*diD9sH{n35yKDQDGoMrEJuHz{XA&3~rq2IP z#rWzh1z!W}iuzqP)`ZWqiEm*3V+6t$>v9q&T|OFUBm_Pd$4RK-AVd)h$Y?uCqZbsc zU@Nbybk64s=zg|~%i(K&Pen?s9Ewer9F#Mt$<9J03TNr{eF)3gU z$I*RYJ3oy?;vrGX+k8^KPpdRrK0zh6Z9%NOSaHx`X4@K6C*QC1wuI4rg=4^$XSTK! z@QkB8TvBKd-2jpQR-?~>QlevM#a_tnr0xMj32dy_cn*c0L_8CP1i121>RJ&b-9hp= zcOW+6l7f!~#f1gxG(=$QOgRUK54tNPl6lh0Kv2K?Eri7qGy=pWIz#9_5NH(J^il}W zLx&0#s7fprIq4Rg2STh|LG*H5CF0sB@ZK&&aa)U>VNfT(JhGD{2ys8h0D(DNQqMBz zons)NVVi%4Y=i`CR^PAg5cjrblL$(RHw?n?hL+IgVBBDiY?(}inXR@GRiFlAykR7n z0qKYQ$d*uVR%CNfHVQy-P47wf(i@BNPi!|#5-y33kbi)j^d0wmnX*3pj%S_Oc$HV&niCy+P11O4o0)({1xtN!JP5X*eN(8fbcw0RrvV zl;44^eYa;M-6cRZPzluGtQ%AJEel!U!K>~^g-*$rsV-wS!*>s%$tlSn`kx)R&K8sb{PleUvq@a9P=J7{ekMNC_IKEXNX zS+q1{-bkhPBVVNJ2qsNyFwTl_HGf<8xR zZZO^X160LFUQC599r`I5R+kRD(NKKk2*skGFNlSKr&yivOTrUg*lW5My+&EQ3Or1u ztt8oq4Qp$p>*YNlRS5onvb&AB+8Xr;f&dL#It)+6JI=9(G5$pa{b>kpm9K>gJ3NJY zk$Hgab{-DURH3qZt#k2O9K_qN8$<`OzG`Ahm7S~X70Cvi=SA+mPWf;DJ1$P`tVn%S z5L)FCo!J$3czSlGB8-3Urti8`3|aiUiN05-f=|Z39rV38)#dwsh`#5iKIZ#=n7(JG zKJNQ&q3_A52ZOcrNGNzlrM^VpxLI2PKyZbkqQ>AoSL)nZ0ksUMAk+{-7<%nWMlTx2 z_y|)~3SKk`$l)1aP-!V%lpzi@@ZnQkMRy!YyNd6{*TRxl7k`xYYple;!tInsI@+ZX z*Us!OKopM!w{$@yWA)Glq{w}Vco}!B0C!?He{+NEKF~>GH`CHNwwKXNPhwVgBHr(i z!;URM&K{%V3K&ZrBS)hvMu+9uA^*nA^m*8|d6rM)J&G`>x`1I7RYx16Ew{skx#;_m0^texhmA`s{? z0&ySxc$Ry&tWw@o%PO4 zbmm`BMm`OPj(sNQU)V8T$-e-EDkZC&nWGKftP7s^)%iciaxBz$gfdpkV~Tf6MWJ_j zS1ERE&=e1~RrH`EvSe52{vSA~V^6)j{u_{f2fIUO@J@o-S3Qy-4oDwTi-kHFwD5cHViNT7<8qxKBUPx;y5as%`{ zMd6K^_hcgmZ)5WENck2vy_B`nypGi;QjbyJdeH~W0tSrdeWYM;1bfb4&i6qTjHgtO zV_hvr<1w1c9GFoWFn0nN&mGF;_GW2@*2(tk!8;+l ztdpbm#bG5|*3K;FNdBQdf^?cZ?NzJ*Fpdq3sA#WSASk*!>3!UtA-R9&!|1kU?FE{) zFIQ$vWPC*oRv{(MI7QWZCKP>jW4VCA0C@01tiq?_i$-zGHB8kQ8-n>3gY7SHvWP~* zEfA$mIjie1_ir|sd&P&IMQ`1G-G=eRI??xX>6nsY`^TdFBhlQydW{_7?oEXpVJBE0 zkcq+*leqASDcpM3mFK-NPb8d%fI{ah6lizrtq>*G=}tm^HuDtJK*qSz5WENW34HD; z!jBE+Ihd(uvE&ZJO|IsgpqA`lWZRq*j9cXPPL}!W{>-rl^2cSdg1{dnMJWK`NB&rQ zcpU7I2tYh|h|p$#DDt=yfJDJW!suc807DPVC76paO6H>%otckagss9>VPArM33fN^ zZrDArdtmp%?uFe4yU&G}cJZg{*7f?Z;iXFF!W6+&!O+4OyRbb}<3KmBz2-xEy+Dir z9lp4Df}qc}J-JV7gP4If82Q#vcR$hCKY>FsbLFJGHn=WP;CZE^;%AO=O= z(*?I4j_EKh*}AD`n{#ybe=zKQ!m#(tfUF5NEzUq&{UaE!P%=CR#M~1Q4>dpywKn?) zUaF*)6(6GgLqH1TZ37I=1Qg7ZFwepqfO!$79R|3b2wYEu9Su7gb``2%K*ap~o*!sb3!*O&0`CWwRfib)u&^FmRU?89^*f(k$&<>~@;&8t~ZO29fu2^dS zi+DK0Ir0Vi9eaR&Cp|~MbDpK&)Ti-V`N-Il%o_O{W=(pMSs{Cw6}yL7GaiBU^kX5d zu)uBK{}QwH`;Wke{`dVS=$ome!mb%^QVz9`0{6d!S*SDQ0Deb6fm3J53vkhbh7BHE zf7L!(_;KA;TvOEkUPOWrOw?%X2yq#iDUGVi#jMO#M%hy-f&eLuAhjD)WN8)UJxC!` z08azs4F;^`q*Agf_jjN42S@*(m>0Y*+e9~KcSj&uupJ{OEJ?o&wy3|CGuBJyw^%<1-AbRdIfG}cTkngUl~;J)u3+?jx}(24wD)IO@*SS zSRk>rLV-{LM$m0~f&nwv(nw`lWb#sj9Kuu$v==V@HOcmPA~XjwiF7_-aAxS88zYx5 zEm%G9)UEA)Yf-DT%pWtQB2oOPKa&EM^_qcL=kcLU$RI22r=uV1<)1wND z#lv3@O*~hEYXi}AZ47Gy=yWq*w~hcNb?-tGYWV&3);ROqR$SR+7ts97EI3$xXqH|q z_^X)i%6){S0{bNcT8*{PtgK!rtn_QAbh792C{mRmKxgdT7$dl1#v*jd8RQ26aSAD5 zA#}fOo{|>RrcSwb23Nhbb#b7MOO4d%VZOw3yOVMJ(aLI0uas!fX;n6$6jMvUc0%kC zqzN@$iRV^ayKK&iY!ubsLU_d|3{}=H{(>GCz6=IhP&O7V{aste6l061>F`{O#V_{s z_u5lmBBm87Vyxebi5-6DxUQ>EUse#YqotG-+8Gpy>ibnRk(O?}WdmjIJK2hWB!f^I z_Lc^vvZq4K4)Vzrz2nLyekfV%lLu=(g) zy$qQ~A0V{WRJ-7zU{|>U6~GhO_=1K*&!5$kgZ#I0e@Kj-)<}ET$f;I~G{EYEe@Z6B@gF^LN4-p|m zk{;ES1Is2XUR$@8nwcJ`#-((Y83N_9A5C$kup2~*2z^TSlu=%Jj`o5YX*R_Phl+P! z=t_k=rm&{RV<@comq%AvbJaW6NGJ<)P7F;@*RE<#0L0U8~GZ?rks4&35byd!_rzCixw1>Z;Cr^rhO)@T&3=2O83VUQI z*1@=1SU3R1N;sXwsvU#|T%dx?*8&cq8sm@7mYBehfnx}&Hz#Ou1b-a02Fqd3A2{wJ z8QSO~Ru^D4Kt%C(iXN)6aS=2+6PxyL`~=N|l_P1pVtTIzR9YrT~Wa#Pw!wRGJ`0sCL0-Dl|;2TcmPca{h-8txKI*g@3?>o$h8_ei&(uWPiX=^s3K6M<*{Rn z55<_szvmBx0hZt+s0a(PkMhQIINSO|fy}NDT{l!6fFIzMx8=B}qk}OuYE9I4`K5oU z+!e{{;SADLswty)AE(PPQ1f3R+ry}7Cd2ue!#mKUtMf^3TM5F?rLV3-X=CZf)Dl1XV8<< zY7H=38jjA+X@t&cXpU^**i8G;}EIf6Pwl|w)wIYnZ!U7n+os^COM5$&oGp* z#3ar*osg1c6d#_7InL=w!)J?w>O&`D8$iD;5z0ZTWn!!CdN>^!I40st3DtGlx8nZ7 z*p`CX&C7e5^Z#XEn*?p^B&P3qKs?q~pguR19}vt_TvTTKYr1@#pQM>jiVr_e{UzAt z$b>%*d8Xb&b;o$RGC%c4KwW92nPC#5VN?#w6tW8p zPU$W@X;9!~;p(;N;~62i9Jz>O&NntrYZ;S~ z?tF$C&GujdVi=E)ppa}I}SRukx+vM0G*34`}0H$fSp55BulWbCg3x~!(()R z(!Igqw*&s$f(}xv){I

5NubwR9ap2Pq5wTj@0FI(8o=kAAAzk^gMXs%b(QQZt%+ z2GuNwYW4t&$@@C%Kwp; zW^GNpT3lSU9D5p-H|L%+6s!RNHdVuGtZmqe2%y8W0I*QXrNmo3NNDlS zPV#kpoFFiq+Mg%t#VAO9VsQR;Hirmut^FvABh9D@S)I(fpd6)s{5}7Q?-Mwk2_6Wa zQ#|zwK1)5be4`Bw=4m+oU}R`Zx{aL(#;8AL=_dje>M!85o7hP;U&(osK@<&s@hk5<0Xi~rHDyqZu zV`-YywFkut)jBSF2|mB)R`s3l`tk7roK&A-G^-!@0UaBVX7#UAwsf<{Ms<1s{#u>J zsE_!wqPpxGT$fwaP5xl@o##=9KYp$@_)tA|deR$(s^wn+bqK{0X;z`CLI{i$-A}{} ziPcAhMp~#0H1}M@$_nQqgV z(bKC&(oa&mnN`%45tK?dOty$n{h`=SqK>44#3K)@Ph=d(WRO0Q-sZCF9a*13pGY_< z5$Wy7y6#sZ5=DAM@QCA5Itqja5gb^khsS{~PMAsGO(JYZWn3I_~;V_vT6j1?EtU zC{YouavWs>cO*1cU)B;{hD=yHk{gwiN(b4xvz{EdSHY(!1}wT5!&&#)_s;(9?D>dO za?iCZN;egT7@0A~Yai*(T1S}?Z;Qbynh|&Nh{f>;m{1fGmG~Z92Dl=x{Sgvee-xC{ zc#Pp)DrYqSWQ$2?6jzoTY3*3kzXAs~c=8oj;U=gPp5&`I0XE;*5iRb(f{8Y+SGF6> zOx3M*ihB9q(EFp+cVKBdz;u#dLF~nd%~q2oLw0#Bc?q~v8-!8hC7$@Z{=}ZD-JfEh z+O=gdG})Tp6q`bk3GR7{j?b`ANiK_&=Couc#00mV>21#HhhRo-jlNVGp9{@x$FH3s zoh|l1_dA#4&FV-}g8Lx%mB*`#cu5JYB#?ukei!Rs&s^pBS-iAigam{RuUUdh)x|{e z5WOqw#%arBwf{R*F=92Sp)4_$`)rV*6&Zg9hBoBR$*8R8%p4VGKVfthjhe2Ax;OCF zU#`+FJ=n4k%j9s$%9M!Ldh?C89sNRcgd(CJXc}faGDn4kO9hJ9k~b=rB4@G43z`jz zn8s63R7}tUqQ-{fwkbuOMp18LQKNiO5e>^2iZ(4AtA~7*W`F`E%sV^OJJ!UyyV$gq zRyz4Al=(Jqf)lg5_{|FP3k%Bcab^|qYza!aO>FuFK2o5uvRQ{E4`f~-f`Cm;PpT{(i+YWEI z^m2!8q!QMW?`_Tt4e`X9%ev)I7Vs?E$%`{Ew9|(eOVC2hTaWk|0EjjN4`qYwJY$tG zUiUPrBvjeA1Oa%=(OKOw%Vtrc+x(Gu#j30}Fkq<@1R4Uj42y zDBL>g0r5~on(gIoFd+p=Z5bmTIxQY^(kIRWN2>e5;^L~1Jm5N=l=Zsvo-{?gnmG$q zip^*)niT?#)Z0h2j8VkqqEWFKb||IxeND@VKkvEa+WDvO3QGaiER5F-yTql(?5`(P)Dgflo_VKH7iN|KozXai)ZZPfWa6Wk>yznG8SS6xEp~X{HkK4{| z&e zQAu1S)I^6%zr^;S(y1d#=_N`b$8|Vjm9UP?&}reGyNPnbcw`47oqj^_kFf6s>2UuM zJQKk0BcR)efX1UwOQZBxLy3S!1$#zRDgw$vG&Bl^H233>a^dL5YRcRJl~m6>?jJdy zhtrwhu0b4o?I+_bT{+Z%o?#v1E9bmJHDtjQq=>S|r4hLtX06iw59BK-HjS zP?i?$Zhtg&FZS18z6?4-V=|VO6I#>oPC!427oxPkz~)22ttWP2)a47MT*{WS`uXi__J*8#fJhgNMQ1v(wny3* zMjATPnO1+#Xng2h=}`!R7mb)oy1`zK2VsIVj;Q@o0;aL6Sw77|; zXqb1Fy(NusmYwg&@*1Hlc+2Q^Z zB0BSXJQDyLWHBjQ0oh){kdBZvsKs2~10CEoMw0!x59V%|NiascnkGM=yu61=I9~Eh z?##MGlYnO|9E1W-Bpg%|NagZa7fn3$CsREKo zMX7YfMV`@_MeoN6o+3DqK=3>O2P@$IQ~^`8G&@xQMv(NlbeH=6W4;=;!o_PCkEJ)s z5MXhIq(}laxo{9jfCj4GZE!g{p~`He4Wr?;vs3es??xQ`?tCC4 z2?XlES)B$~ zrx1+{)d_Gaf_p899ET@LY7FK`oDRs{+AU~Vb!DBwczOxqhZt2!La__EHDI_pg7mFZ zPh#+nN0S9fvAZo;S9^D{e&5jibCPUScjK2m_vN+# z>t4Cb_hf;b`K5W#^M)HJ7nY2@XLVKnxjGYGodPzjg6CQO-a)?C|K35q7t%Rh-nnW! zWVDn}1xH0wpi@qXVhZKxv5itpueMV`&3VE4o5C3%IXK2j+nn!}cV2D7 zLgL4u9v~=Ks)r&vo2@m3rvQ zLK>(H98qjME==u|Lq_C7t?~#wq?2Ww+6j56Oo(m-3DRAuLK>_)@DJSlz zbI-}pXc&a2Sn`cW==lUj1mW-t_UK91q1JcBrWZisiFo$Kn+86x=y(R7m@?S7FtrUi z3Te=L1&f?E>FeNSI<~Pms<~5qxDHM<)8_fWoL8 zSU6em_7juQeG9&7f=fz(ipyZSVA6^>F1=pDJi6e)Q~+WoZ+eW7tfQxX5Y=;qA(;HP zuo);=s=WP+K(SRXFgYr#Vl2-?o_l9#3}c>>2_!;RZ^Z% zQWK0g?US^Y7Mt3^z+>p2&+7RT9^&~f&_a;c=vHDK*NJoPR94%cf5K|Z7_g)zOxJ7v zVAuN?DL~fjd@S&c2gf5ZErxsZ`)wcYN`Tzt@G)rNYix5HTR#l5{drgTY1@v^gl2<$ zI~&X=P%7$9IC={_cG24mra=SAPBxHi_4iueP*Ov$zGLL>0h+wK;08B{MkTLU@_J2FRVyty zp2yI^L{V`LEJvHK;l&~xD2!3xb81bbW+S@N;VH%BhHC>m3@nE9r{o;Aul`HPI37^XiEw{{jQ^tW>ucxT(L!>=d8F892Iee;8xr{6- z%?(CtBz|w%5?ZNii1N&Wdz>{MztLM_;d7g3ig0@tvAL|+Tvlu@D>j!G z+c$i%eU*?Jtu((O-(HDZ3?opU=y(?-7l=K2_!(;udh97Umjb#W)4=W`eayu$NdJb` zs2^ioz~Jep4kK-}iGg{ly@b(8xB9*Hp!gj<_FeQy_&`e1p@BIG6P3UjzM3w3w*vIz zaNPjj!c_H#5Bo_X5`$f!;(A6Bo;8{jLyWp*AnJ!$HdDsL$Lb~ZqCD=s*lYr;;-R(- zoKj5EOQ{T6+^h>tJjH!V2PFe0Rzk|IMTdJ!^o-3&))=jo5fEuPm4RfqYny#Fa~`rX z`6})i*D?-;;NtETDBopdb6h;!nq7%kutt*z=ra^kbTpt}dA`Mw%nIG>Q|7PSgk}DS zZUB}8&NY`ubIE}>cTS7P5-RN+1K)MXxJ2SWp%QZ}C z*85zU3k<2WK;AM&?ZvF6oWLSuVkdZeAauObn7s-^3%o{j3M7w;m$9)grUiCSG6?Gh z&?7Z&mejN0C&TQ8V-+YrpwGGESXOkoVz%nySt)f*fi9J-0z}cI8mu`75W0 zxBz!;P((L_pM!@@)*Xd~$z>*4Us&h~h3 zE@IJ-ewp|?^?N(~qTIOFL8E?tw^~Z;ZaEI3O_Y;w42{comCSE zU%GUFRv4i$Dwr5Z1rrCTz(iCK#i+nIKm`+t3P1wr)}CEEQ+9j1iT^k|ux5<53SiwOdJkP#NQ=pjP+Qj;#m~6s1&*2Y1TYuN2;03HmWJi zj#6hcJ6fGiHWp&+)1*#fc8off*>UPfW=~f`n4O@0wt}*qt^SMI6V<;nJ4yX3vs2Xf zVcSonc{iu2=a^TfdYaj}>Tzc0sjo1*K>a1Ni`1VodxiQ#X0KAe%j~u4e)pP2JEkKtq>pP{d(SO9H1)km50JUQ*md4Zf;nX`+Wo0#(=IoC0#N=~ef0p}%h z<}v46EwKrITOffXU^H= z+{&Cu`$DG*Gq5jO7NzOdx%q3?!oDAeV`buO01>}rlPP#~?PGZg#p)`504Es zdg!pCQ=HU~aHyCbE7-8H=If2hJ-T)ncwR@>JheO1xHyeVyd=*bj2q=6 z?8k$|pXpRC{{j6XCrsef4&?aXy-#ugnzlagK8dXl zGWo;YC)s<0-Cfv&V7gBdMfP*>I|I`L4xcr5m59P zs@eaR`y^DD;+>A)*)W+fE6B&!HvjGWBunY=0edSWzjo*TE(U;NTr9Q9uEstH<=5es z97=1!O?17zO^-dyvUyAUtVT%UQc2}|pPtIre1OT#r}&&U?qFpZu! zT85NYy7`Lr6WV&6Y8MX)*uBTMdHy*tR4~_98-En&hQz=Vi91|u;JNI|#_U5Q58Glb zU8+fiVucCrW(h9W_o@FphZ*Yk*tB%Yqt&TfY5U1UO*@r$Jd3bWrKeZeMfb4J-`1v{`F^A@&Pc;)QaMeT=9`fCi?qvb;*e~>znD)FbAIfCLbFs|%fX}A>0ZoQujg6M0= z1qjnXJW^@nWnspnSD+&C{*$u9XucwkHs9Dh5)fc78tjb5M&=v*LkEH6-I(CKyEcze zXQOm}7V`u6flY^-1kp5YzO#&WAKl3-qD1z@ZY8$bFM|s!U{}9+E;uP7vX3Y!ELIZ{ z6KoCDEmIvKwTo3PoQl9%7kqkUXFNzX&3t2vNj-+}nmblI6V$sNusVu7zLpa(SgH#$SE1j zuSrLpL7ta6#oBux6deT!F<%jz8p*yPK8*8iFIA;#DXWSbyI_7bmX-qnkSIi6U zaNsLCpQD#I7SX=!5gojd9SKs=B-b~i{=Ta;Wd`#H(m&}T`5@WQ)Vl5C1HtlN*i{9* z>9p!YfP!^?wm~LE)Pj5}%^B()MUX0?(g<*^!rN3{N_^!8>+k2NlREepy$eywSFWX8io7efviNxrFdQ= zIsr?sKt0t%bcMlu2O3amegU*$zaF$R7E;UGO^N5gs}`R)z6?#dw76yj>uAJ8bF?Bh z-7`0uSrV%$X*F(IC^kyZI&CHOBR&AQu?+XBzx}#zj0gmV~4W5iXl z;1S)l;b^i(&qxm%A-)R;829(}r7pZ=91l&9qONVisfe~xcMZ0Ce%~;kFYOXbln(aj zu;^$5YLv6~4|lcwEljd_LS5g32VN$w4~1Ebmxt?%@$zu}YI=D%3}y+uc9pjBJYD3P8RN2u`k~6m3jWhR z`oO819Cn0``>;-ch*}@rXvjCXr6Sa*Or|BOk<;M+qHruFeBC$wHWGxel$B31y4 z&V14uuC$fz#qqd4rhNtp0yqSZTkA%65w9fiJ=~=Lqs;(OKCoofkFG*0AxmY4pU&lw zaPmr}^eh?;Tc;7GoSb?Z?M;uWrPJmA9me?X37?A19l*dY1LhF+<|2Cspb%FV$L6A6 z0ARYih@}ghVjDN2(lnz`hQI%p*UNCijzTlhe&l=VBpML4 z%R|<5Vt4I)?o-aJ?y1KifkLf!m-^RDR9DJg{X3k#TaeCBz&cg#!QEl8=_-0Fih}%u zN|{y+DvC~Kz;-8#wHmQYiq!%tm`X6Jc27p8~P9Z-)pz^t1>($UB z)QD827-sNXdk0;=)3bX_e1XV?EIy+lT^m8@q9YZ|;<}>vou_afTlYpwIz&xN#6#Qk z5H;n`-JI>+eS?GuqypGzSLuG(;Dt%k$cB`_WU?^>q}mqhZA!Q+Z&pmpXxpE6+fD~H zkM`U-*!LmZ>0pm)E7$Mxj2sBD-EMQx%|-MPDx$2NS|CWb~Y4vCEf-j@pl za!FRC-5Xm3i*HPhYwkchz9V>%}D1io(MdK7@(2l zSs>?Sa=1IO76sP+|KEQK1IHnb@)FG3B$k4|E(}`#fYIYS8s=`8)A(Kny9#DA%p)*I z;P)e#Ot|;LP6IPG0mcXx?Hw>PVdlduf+>cngLxR{X_x~rM_}H7`6G-9a}`E_?(k@s z=`blUMKJ4N8en$9JPh+V%)i6D4$}qG17lbeB-{pbKTHA4I+zDxz60|^m=|D3H+2fpYb{z-f%(bR1L0Z#k6T-9 zsgvf;zS)oYSl8harqxm|Sr*ozK9%L`Ekf=C8Os0y?5xr?8F}f2g;|AbmMvLQ#QZXr z4}>jWwk&IL(VFFjS(G66fxLWwSl*J1^t?6s=^42T7iVd8&S0=)QUwd^E2S;vR?Dj5 z^4iUoRSZ?D($`DXn=J*_`t_E^M!c?E-q286F4wKEGR4ZsconPAOv_fw@ad`Sg>{V* z5M59%RdKwmK_=A|Go`H(Z;$kbhJ_V^5Zkya7DZ@nRA`a%tLv&Ol7*S`OeT0r z)pZ+8%*VvMVry$F!oMg@M)~@xVbYjZf;2!#2LsJu>C-bmoBLyK>0D6cTBx0W|nnX1a`Drzm(aKcAXR(gJJQBlE~g^P=_ zmSv}BWUVRAT2{Dl$>M~Bd$sVwjAdC_iwkp?6cr8^ZI&;eWm)-4in0oemMlxp$r>i+ ztOQ>7#TIExy>%lXV+dd{q!$znn>i4~!inYzi_(XMVAd?2Z+^M7zAC?*GA^`O(VKu^ zssr_*fUtywWbT)3MPI3COqi9(zn3>!tO>K`GQ2m&t|x+FX*nGy%tBuDx3X{zHE(wM z!n`sQi-6BH3+t+-xVuc1<<+&83bRSBD_>V@!GHoXSdZ>zDmPi>x;ko&YNFY?^%hfo zB~L!xRBuH%MXWV7vL4TR4)xfX;a{!10XQ0&a~Utp57Af7XItZ%JP>YveT5A8d3AU- z$}8r9n6>^u{U;OshpG*nurf=m7$bcF=uR2+n>JxEBAneE&L}f$>v~IrR9#=Uu&%Pc zq*|)FU#_mLK!>G~l5lmuM!Ei6w>3(ZO;l*O;0s&BGWW&c01XZUEHn;e3PaMspQWXc zp<$n2nZbDviuc8pLK%7W^+cW~xnZDFR{KWcMpLD=ep4U?P!|=l>#gf4%{pH%-UQs! z*ab?`#_&d83$Z?}4P-aRXGk!mVt8foh|+Q}@c`c#>1fCmXyE-y^j%kP!brO?(^Oe6 z*Hz36&qCu_tR`*zhTB9_8m|z;F(dK@Su#;rB{~VO=fHSv!Zat9qiU!s#aUl(wOZCo zS~1mirfv1IRm-)$7E>fhn$uMV5`xZnpJ!d3`%~SxXQ5OsVKC6fi2?rv3>`uj)&qO6 zPGD<=lmYkl0Qc)~Kf92}SzfoXu6|3M$>Jkk;H?YceF$HNK^CM-T^>{|2&DWqaFqkr zfM5#w_ISdz@6Rg8LY*K9)xsvhBA8&T_*V~OVo^p4j0}V#Ax~H$6yjfC93EOIEEEKgyA(s76SgFcWbW zvRZPeH^H}&eN)VhfQ`d0pY0O7M7=4MRQF&K$*C>5s_{yUH|lfjga90(IL zS?dx(`P%zle|y&<2Wn>v;t{qspspsA(15h-S*yhBEhYuzn-iE6|#Snbo zDaD27)+k&!&FY)F!3@mT%f1y0; zNz_OGE9K4cm)8KAi?mEC*@>`s4MO zHH3}`8p?^r0Y0|SI7Kuw+*lu&&j9@pd^hK_30S64j%r@T@L$fxE-2m|AFCEBH);f6*HnoAq-O>P>+X?CKS zj$?*q4?eo{G(=qkxFC8U-bvLR>1G3LBWz+tAGtlYN5eiaCEZMmnia5dfml!{r<*6h-U@pn>^RuCzy|5Ubn_J0CfFv}M<%A5Z-;&I zwsiAW*au*5gZ&8X2VpnBCTYwn*uaOER;BT>P5{9Bjfbt?1~lLi;xzHOkli(a2RHkk2;lpTI)y zVgC0pKT2BwU;0be>`XvIV;!v%Y3)mYivcIC3j_U@uraRQAFB}Iv_1`tm5vstenj&Q z{Vjr<)^9#HjdS#u&f1yQV+147!+MM!*lQu2D1<1VWSeKua+i1N=%*eg$%% z^{Fpq5n=^?=L4^_YWC$@i15MRR5rmx&ACgQw+pgSS;r-r#Rxug@cZ z&m}hkFz~uq9^iMeh6KN>nzdoMbvx>zK2!T#~I7V2j)zJPcF;s^*Af`WDWkkBy0i13KWk)uT8 z=v&4_jU9Ju^!VE*Oq?`%is|+{rpClhyEE>tyW^+Nn0XKQNQtxO%)Kuud7e2Xb^e01 z^!qb1v$At?7cK%rb@7sdrC@X|FD_Y8`n8p-%2uygTfT06g{5*sRdvnA+D&!!4PUo5 zO7i9{Tem&9v>#=`XHMuC3)xy0IRLqdS}(>q3RlV52@OD=UQl z<|LpmQe;z7!HO`0a9=_~NdfN5n@ltn2!^#)Yw?FcykRT;42U6w2?hf!1OCw``wPM4 zaER`*KU_y`)obqW1h`#r`{F+u;C?K?y(hr^tpNAq0q$=HxalnxU!Dg8+_cB0ISlzR zjW#Cmp&Du};K40fS3?|yJldYuTkk};DWkT$vC))U4ctF?R^5(WAVL^qX7rZ~Y=w5`E1B$Ks1#vXVA>%rOp8>hmw0i;=Rr?7TYd0qJi zaEUhqFmM6a*Eehuc*9WvhkPZ)kWx=-T>Cb=4;DWNRC%H&DC#av-{?vus&e1~_=z zZmyIVyEm}q{KX88gEn7QRJ4$Ao0Ti9l`ABZ)q(+v_+ALR2|NC5ga91+@I7p$1L6&f zzJTyRcn9NmbG22H%WF*))r|uv!fDtrbT}LkK3W|X0IIv6-iJ$#@J8Uh+{#f-9KnH% zG`h4@mgCfIP+u89l|O&hWW%NB7#x)AT97|$1cGl+pVc}m`Ag{E^_3ik%|sh$v(4*R z>yzhNjS|ScIu-9$!AyfmNl6vv&rcO%;l2lE224E6-7wp?BhEC~lm=!eOdQ7U>9CQ6 ztu&DwYg6!NVW8_%m@)ru0ZFjRg_{h1;_-1e3loI;2JNsC-$bXkBYi5&?f6bXM)R?J z)##bgGQ5Q~Yj9{$TfLzU^V^y=RvHbeam)mFgJhjM8@8o69L#o@ zBADqg0?fs`fg_lwVH#jEVd7v2e^Ib|@v_uKm=iDuV6cJE_6a4`brtnnh+$3)Z1~fu z7@s)lkjA=+1(cxO5Jm^x+9_^*gWSOU_&3i+$j8Yp=C}Lnx0VRYv09{^&Cop!y-7iD zRS+%wzx-#y&S~(!IPf+2zrp^)f8}C@_eKAjgq!~jj=x(N_(v~?e3gHJIXol`{0jzO z;j8@fr8oV*-1J)AZ*JGB|JxK0wA=qL=qvvDT9E9Af(HHt2Yt1FzVtWO{y*#UWj%mO zio!o%iS#w#HVR*{!dkSU@xNMa2Vxn80XKIAVV5Qdw%rfen;Z{+v)S3AJmPxvu|3~< z{M&n<_|CsQ`P6s6_w+O0|G~5Sez^a+=YRC$13&rc&tCZXzyIRJ|M=yvUOIT_@R65a z`Sov(9(%R5?Rfi%-*$AKJaziD*MIlM@6Vh)_vTxFc>A66@BZ<<3-ABwgRT$%{FjS= z{pe%W{Ws60zyITt?#utY((|vY*LtsidZX_%C?@*vZfHM$!}^srwExrf|DP`Zzm5Md zV<>!nIAbXMPuD-xW_#GS+XjY(?qS=*580wZLcpR!BqZ1hY|Y?4#NC-xP+|i= z0!)j7f@X9ZQ=F~YhExLB7FAVM21D4^hK4N-4TJa<8Q|6}hFK0yRt)0OUoN-)OTTn` z%?4gB@jsRoW)_wuey8gD|6G#$!)M(u&-urxx2Z#0=B-*sVl9oe zqDfS5&6euA#Cv&+RgKp5T7>e3>Q&3IW5p_Yz-MMd1?2Yv|0367Z98vZ?L@r%r}2FN z=7i=?aoE6uFfaZneHsjxc^uI4^ObW1-zQ*v4#|(=4VPbFTFQ@TBC!3*uNi530?MFz>OuFBFuriI=`Rr0z%&#VgZ`4D zrJ-+vClB8%V0?I_IK$yFFde0R=K(?ZFc0S`*f_U>!C3G+K{yiunP`~FkwL<0n4K`q zFrW8lgp4qSok95o%LUlIFyu%5hHPJbBH^};=J9>~CNQiM@;_;mK>K^wgnRJ#qfejh z3nPfgM9oh(-vN0bDmw;l@|z7Cmj93ZD1BE1k4xXRL*n=%`{D|bJP!kG@*4x2${|{N z@(a>Z91OEU?-#@&SQ51SleGLZU{f6y!=~_J&2E5Ac@hjJTv&j0(;tP=UmR$RY)Vfy z;rrbjj_x;b|9JV}@H0d5{|3%4DPAh<92j4{0^yjt0dn^+X%tcW3#t0@{t%Ns&>v>Q zO|+2-+m{E~K6>$$`_d5jQmZ+9KSz0oV0`fc>lw2VXRt7opD#QR{-X$M)51T%IW5KO z0USi*!u%4aECZfIBeW$<1lz*I_9B zaP^4Zl4hO=6Byn)1Yd_A92`Ehy-(~K96pquf4rNAQyGnL``{Rw&+V?k`2@BHr44(0 zaQM)2-hE9pP}`<_9fvt9}P}F6whn_@x|eP6|h#z^7TSN z_z~{$7@_zoFTn33_zCcP1oxYKe|p?gN*g`!?ei!5|KFwh-*cBLD_G;?rdL#egOBt0 zR2_-)=T)!60q3@?t?A(X5B32ocY`h;XDQY9Z<8!V5W}yqWK@+~g>^yfE)!2FjG>(Q zt$=JuZ!d;yHS!ue;G4^CmB8=eAjBlue|Y3o*CE<_0cwzYd;KvYl^FrtnDFrl3$bWis*2q+=~0xGTn5Qd-#NHC%TV!|x0X$`2DQBg61 zYh1-Fii*k_am_2b=4JJr>X{*}-n;+(_x|s`_dEL0-Bs1qRp*>Kb*igQwKKd8c7fSA zt?pjzwwMm)B3)uaEB%6!jlE;F(S~I#GvM><39ydbRXa2>+)tdbfoJxU!g81|KB1SJ zua}!AMd}=)a3f!BxcJCk+OgOObk!$O8#h*5JtI;l2!){sLIM=v?Aj09I}G=?l=wwx zqoUl#XhRYcp!|OBZk~qBcNqHyN5*R_d>UYNl+-sNs&6!m@Io;oL@D&X+$}B+oXD^X zM(*0+SaC5Ac1ApR78maPin*ax{Vw235ebtfelRaAt|VuSJ+&}?{8RW(BDE7?t$cKX zzc{xn`a7A3ehG+ESSWh3UqYy!$e48{&kURd8Td)+9~G}F0(KIe!%ez1MFr@pVzto; zbR`!1g^}n(1~X;DwV^$uL*m4FR;YDl{<=p(?(v8}RcimV>bz(Y2WAwQ4B*XxByiIa$?vzRD!QZ z8~2PCB`RDS=K~D~hzScB{Izl5YXLB<8hKz+D6RhKF>&32Rxq7y zD0Q4zLLZa?7J<&4U0{)i66Njf)*GGIfxCgTk)dKMgV`A@SZwK4nvbqs#rMY=m>AT7 ze@umrz;2*?zmy!?U@SH#A8;*1Q$^tAB-Rudkbz3z9~m-SPopDZIdyWYuL}t7Sdj*z zlaGHSXqb4BI&g*wRkapK)FqMczFM8gPD4DXBIC=%+;x7FsLt6{u0e@`tn`<3k4lV> zK>2q|3=0EiF&IS}`@-4`6a*s-y`Lnya>g8uJzaVSgSQ}>A%>?%>Uf2&5bq!)43z*S z_K6YQa$r2CYlGmOg1k5TV}2-wTXd**nC=N4C=Y$rkuJcnxmBJCS;EiY-@4BW&Beeb zBzjEu1fSyG63iXKeL7=U4g=#~{ZXcb_cfps?*N==7_)*8T@b($hnwN(B%rYvq_>3k zX)q6*31P8-I{*yA(ZusSG_l+b?g7XE^IRYvjyVvX1Lqe3uq+X~1IIGJVSrB$NDpB$ zKrEck1Nd}@YXA=C$#8Unye~o?cL0`fE(73zOt>xs90pv3avTPfLD@^=CD;k5V-esU z-~+(YTY@!r0g3?60Of%CeiBRu=m=l{ zu7E&55@0R>jcAPEEszv5!Avn&VFjy~>R@$Y{A+>L!|KBfMFXrMW(9Ketc>KI{tfv?Wvx+2f2aiY(4l^F1~j1#^8!n|O;A2Q$4}=rSdkuL41R_N=fRxF9wE9->mFYvK<7TGr+!WP`f5kSBxwC$-6Ap~#FG1gC8v#!kBCXo-&08s zbXJ8ARj6M{Ta?B{XA|i13p6xs(bPoS6?BIU0`z$YR;zA!pw5|JC*PIz2L1YP`k{Bn z0Hnb!o9W&IbrGEV!Fv8cV0BE06Rd%9a;g?rvCjVsaiV~rmfj5}eQMk%w5y19>Q`~v zJ3P+GsjoJ{XO~MkPVjA5at;G=$Hl=0|*6p0yqE)Gf*0( zF`QSWO;k*HWJsVE4T1C&s7|{mZFG1-MD+w!?~h4L2#g5}j0=tq*BUaY8jqIe1xAAH z3k8;?>dJtQx|wx-iNNlu`7?q5#K*7wP&~r7-!}^URSF<^sVbXDFVt-R=)E!edHv#) zx1;GHu$(J@NFEyj46E((@mV2>C{&9XqD2c?cpZLKH7`rEpb z)$4S}lvQ`i(V5f4WbwEW(jQrSW35aV{inYvpL9V^`s41unBG~Reh;L-u%>iPGwi{d zM{5RtJ^zWT#XI^y2h``rkQ*{A@W!wk zAPX=LkOYVV1OR*h?f@r%3V;LJ17v_E084-w00X?Y1AhlV5ugB&4?yX2;Ftwi2uKFR z0tNxx0ZsrFpdFyR9o!E*?Nrj<{41kO=n5RjGgZR_M!x{$&gRxSwJ{Uvcx;tSF z=NH0J>~!=;|I?*MBN$l22S9z(MmRpol!)WIQe6V946bvaFE?CgW=XL3aGT*;3Vv8F zu;-O4jEelkwa_pN51v_p@E5I)_J@(2H|#eND5in_TY;-ogwiL+7$#(}esE79{6(Hz zXdf_i2TJLMb%%5GJ1Bht_5tie3uu4^KnS7^1~V7BA1bD<7Wx1}wDOwLp98j1_Z2 zJ6XYm>=(jhFi+wF<3}0Hjo|Q438~POR|CikJrnIK5eG+8>#9mWU-q zdxfFBAjVdCGNL>xi*C0xRL3|-h5lCV+Jt;W(X(~Cj-cJv(9RS!OQ3r`s&f~y=IAd0 zXK44CKn(3Vg?2fLg7Ts|ApQly zwSk`1&(R(w;3W#rucWad59B}S^u_!-i1g=RG>>FSx9=O;Sp@M4Q6EVc+GPpt_~t66 zB}6_TE*N-F5AO9AYYn>q>-lexMZ;b&u%4kxxzS!rkw8nsekwW{s?LK-3Hoa?gh~gy zKLf2`FISP0Ra*kgEsNU2A7YW5=%`wiN42Fn()ULHXYJL{P7TL@)L#3EZ4pU=VL!h= zmy-NSd;L4)+(T@qhG+ikvWkR20dIpU<-TTX0sRLvsWOn)%DE9vuKF+SLJ-vDa1n5uxUDq%%FTTHQh_}c4TsXR-*M}Am-T7E@-M;@a{Qmj&xDn==b}hQ-HMyFPnnpr9p_|ZC=qpSR<_U|1!@_ByRQMo(IAdiJ z*h>JH<34yQJ`JCRAH+}LFYy^f7O{iaPn;mii6*2y=}Pt@`;yUQ8u>lBiabhQBX5zV z(li7pQa957ZW13*dnVH;^03MR2pZHQaXY z0C$4B!QJ7?xDVVXt}buQH|6d5t~|{<^B%l6AHaw4WBEz^RDKqp!7t%6`Stu^{xo02 zU+3@f5Bb;pAH0#qOk<-VG_1x|6$s3g_>oWOwD>tj^;KCG+~vnNw_II5#9;VVPde%1+&1daT#uhcfz~l zeR22#51xjn_!fLOegVG;^7;mENVFxo5$=R9F@Q)XBxD1S1B&z|hmcw_h8#<# zkh94pAPpPH?c{#)6nT&QNYPOV5y3!+*001-csI0PRliNH+gS) zKlvbem^@0JAWxOAlJACg^hExfJXNtwu|bieIG{MMxU9ILc&2y-vSFrdt|XMc$|1@) z}j@;y~93ZKd>#-UDdqW z7yRH-)w{t#`B6uhFF!X5O)NX2NyT*Vf}J5d50m6TGYT&moyEC&9!QFT!%K_|GVyg@4r zQE64vROO%t8Z&Je2Zmu>7+ zqfS&$RHv(tsn4p5)izv9t|J%Djo?zamE0@tEVSikd@aoo%~Z`X%{geB^#mtqk-(f} z-FWUgUXIryIuc`vqeKyrOa4fnA!|eHX+gE6=F6AJhbR(3jxnXF5?3ZFla%wJ{P&a= zDmy59xN5O#lj@r4qY7he7&-GD6UA7mIrTvGIQ13vAL>?6mLM*cTgGkS_Hl=}3*24q z7tW3E!w=Fp32wqR;i-TGHw}togvWuT90cAL5%-9vz}XHYO=`&gWH6Zk@^b;Cr!h5+ z%A%fAgFs%&=yJNgytSN@yUIP~A@U?B>uUK1kweGjPvzDMI|ZYdq9{_>Dr1$DDp+-0 z^&3!_XHwNO)RQ@T-jyE)y6!q?In+6ZLK$ikpNS0WDrH2srE4hyRUuHr;i?!_ylS*+ zyedz1PUXwQGfB)^CWqP09AjQF9~fiShV2ac*@+Edhe5kt4DEJ3yPy3TTF^-KeDy%C z2>8&1$8ykE3;ZkT+VnB*5?2SbabG?N$}k@EZ+D@;5GZJcVM44>BHTm#ISfl0K}TZH zpC{nSVw>KLAHaRccrqDU^+Iwvxsfa+uai&7GV%@RygH(k_keycgE~iDqOMc7s0Y*& z>OD1p9!f_5#jHSswF3>t$UQ*D1LQ;H5%M_s7?ALpAm2ZLRj^IIU;bKNPtjh{5&A5p zDqZzNWy{cD2Ox>`WPF&h%qr#}bDSvviM+@ZfzB#n?l2vpkD^%>%dufo8Y3``mBbd+5ugd^5f^&+)7It-PH^01G2lGf|VKN!O?Z zUho!12r0re0lTPsk6 z3Dg#9KXnvjz?$}<6X{fXGiZrYx((3kqHK#75zKXFDdr~gocYW&VB4~Cwg)?aWr6x>>Y3^c^%5v=ruvln1y~H$TocZg zlX301_FQKU=f-i#K=4 zYGj&rn)aIGLLv0)P(HBuW8tqE?h3t71A->H6MYCRIhnMh2x=3xo9aj_=n-@}y`4TU z=MRLHwm=K z4lbWN%>Be6pB{I3o<9*l3?hPvC?b|vPGo}3xDhyMsLyy&t>P*oTN4bI};ZF^sLa8V!fl|>N z?L@oM?t-V_Blrse!XP0?2nF351#LJ%7y~v>GFUy+g;`+hE)yhtd9c7F$~;YY$Vp-gx!ycf#BE|y>cq7IPaX1F5@?S!d^*_F^S~}xf-lE2 z@hp5Jo(&d4F1`=X#}DJj@dDhPfbaOSW^5Weon68%XEWK2>|ypewBl!M87ozrfp2|# zwF>mRr`kvD50(LH&GSH-vcLk}r_Ki}p+x;mU8cr3DQCu6f>fzEj`QSvIDakx+V&Vx zww6Py&f+$5Ia~o(%$0D@z&^!zDQ^zaM)NA(o%iH@z&4EqIYa$dF@FbibUAMc(&no1 z(F8zSPtq(0s~}smPg9~P2W!(@uoi5=;>3X$p}>IzJ@sb+%{KzQb<{2Z8ox(!>Lfwk zAJzn@7XTDmBGRE4e-E#oq=YRYBXGhWlN;V-?Fct|S zqhKU5oy-DFTtGe|%|Kpo%7==j=21D+MHq3I)0SXw_|SvsG4v98AJ~-d(QA+(2@*Nb z?NZ=sd*EIW@S_ZW4J9ZS%V0*B6P8et_F(r$5YwR)8;N$bibd3i?|7@-^*jgwF4WYn z$T*5b%z<+?H3Kbj(us5B z+$;Dw2sj!FV~r^2;S+$jNfp{-9%$|*pr_6FCZIo5{2)Gpj{<%s@MHKSKABJBr^ATj zFpL)pG-ovzVbo9ze7vJ6)re9Li*eAKRULh*%KevR9wq$t`$mCp6!=DgZxr}Ofo~M} zMuBe>_(p;MzbH`F9O`RigyE^pZ<*HaIMsdXI}1rIqs-Li7a-`2kwik&#cP|IbgE}; z)XW6KBTVabGL=XrsY)Y>H1j(c2T@f*>f?6C;6o}~(=yo>rt#4~Z~zlWWjF zymgg4rPgyV{kS;y%#^Sr^?v_db+q3TB5Y)%%+$sic&hO#Jk@AgrZH?SX=FKe&AKTc z3T?VsUEim9yJz-u+@hky5)&w!pIB7mzEV>wqrQGbW8B6RF6vm->!*#2^n*R2JIlbs zzYEa`?|>qVt=bqOWXMlj298}Lz^xs=o(dn{j08VRnTs>tvatn0!UPim!)Ew>hc4mc z2k;->hcVybL#scu1>RiuP;0-j;5we54S}8e<6^7|vR+yGg>M_Z zy^j$vT(UOhKAv(1H;1~lu#!kVOO0S<28FI#Nju{m@%EYaneC>wiAYF@WxI9_iHqt2 zA2yAI9qFUHgv5;Knh+oF7!uqC!tqAvCOedcIbO%q3}ns3q?WN6P8-f85@~zf9&cy3 z#wAmm=<|&UiI1(8F)gFBXY{lWdZ>L8zpdo5>fE9J3u3A=0p!g%RRVjoE!pg_cg$|H-KXM4?7e-s z-jen5QOUwFW>&}-(FH!<3? z;kDN!C;2|AXMA<|xDzH#o)u(wORCj*18){qf<6CZVT<@zaZ56GG`KqV#hfSEuNU<( zzc~9g;p;tQ`-BZ1iNAQA@3g8zr-v5?uQHw(?J&OW)}bB3wl8?p`TW7gP(#96-0?j7;3xBEQzl%=n-b>Q zbnvQ-r>O@*R$fjD{#?-fdfR|W_}Z}5jQx-W$G9^}^5dJevrDeztbJ^!=zA^YBQ(+D z07rcj?Qy8-_qS*Jc6WJqbA-DEkyV3ac*@Kw&E-31!UnfO95Ayo?++VfXyc+~F2S){ z!WwUgf@@jTbxn*L8VsARL`7*0?5bmB>K_q2Izdb58(Uo~Yh8fMMH`n883tR9h>fk4 z$WLhJjr7r|sevoCu9557HV!QrUWZk*ZFET)+V;Oip`=RMRHX`P&8d?5pnxTHjF3ca zI=wUN>^a%?IumAOPfIMz^?G^xNc}_M!3Wod+TO_faGKhZhR+C?IP2!{pA{?XA1Zt{ z=GEx+6JxkT8QU!mM7)k#c>18P;}&=R&7LcR1DhMI`q*`N%dB^6m#uGBV03qqr|6QC+@enC7jH?J?&uNxM4&WdPtgN6Y?Q#lfja;hr- zks<*#?lJtslYpbHw#1CFOFJz(l$tHMYU_C}Cp{qgwpoX@Lkdo3SUr^bTD<7t&=phV zl%C4)T2|C%sLeY;+1fjnNPam}HEq|UM~ksf7y2&pYIkXqgV(ridxM>S>v;a*sp~_2 z&g(QqvwOwv>v#Kq{xSEbiEl2LuPj^qsncb(Z}a9Vhj)Spo+`Zz?Kn^0j+@*lTxmby zQJzQZfOBVut37Iz7*9D}r5*pHzEsmFc>}%uTD@ZcEA2tCT0g_4US`qC-I><;I zSI7)0b=@^|f!)!kr4th(V&Y(joKRUJd^sj2I%+K8hP$A9jjcGtE&8wAP%@vyp;7Qv z7@xSv5wKZ8b;Tfa*5#Ej7Im+3)Wzcpf&kGlr~yiWD+z@`4g9aF>_1aK+uNC$br>gK z8DzfsVK22;Nm4%NW}DaP&ZiDWANrfE4V_}+@aE;#0%FGCHjg@PUf*rk-1qzY?%lDs z*RD@JTUVk3A)C>wb6&5pd$rwmL3on~uT7;d z=It-VN`Gc|H~nmM;5GN_otaOSGoQV_mi_8&8NdDK#Q9Xy7Pd}j652IwopIgzQ+7w+ zlXI^~dzQ`)=`o#)oP6d}kAs~idjItOwt6dy3SAC|$KSU$oA^Lj6~B+Fb78PRPg|7! ztKTC#8@>A3iKlGG>!Zdj+A}7&F({Ji_5`%{5e6$nVlEBF16L2u9EcBqbyR&D)dsl> z*LDq$3Y!*m@L zFNUFe=xPnPVDm9a_&VHuR^5i^Ck3)Sei){p#8F+ERQFjxoQ5hozcy#nN3|U zIgc}m^a$_{Iz2IUSY4ydc8!_cHzz$z({}tm{ovGFLsA+|cCyM489Y?fpWl{I| zgNM!Ro8EohAjWd{_vH_}nUFWnujn(R{hpOmE)RUMZi1Ur+?>7jhSxLwoszqc+_%DE z=5cMH#ne&DUB|use$d;&FnyBczo&^1G3Zq{k0~nu$$^EBI={+paCPJJkYRYLi2$n2 z!C;)HtJ4Yb4r#D_#~8CaNv?z7}G1JXpb_ zM~|+~=(yNm8R$TmMCyWf*6B67Kj}5J-IWZD4bV7+gi%T57=(h?e+)73!k8W|p$0H0BU52fqAG)95m z>>U{r7ZV>7mLT(kKcj==v@&r&F46RojUo;C8SC={`{p0pJsaNlO7#tl-r=x`Gc})m zz22iX+UcE!20ZF8A!Kr6`}|cF`OoRvu9KD@BJu~j2VQs_ImO|5`Wm;pmXdi}4#p&u zVfpDBXC5j}`a=^XOBrGFQ)E(pI`ugGMK{g(jE@aNT25L})@s=y`5^4=d^Xp{Q0;23O+pOe&L@+SOpn#D`FhNG2TrG{SQ6bJ0bKmW(UP zK_=y4bpvBsH)yK6Wa@i2Nv+1lXsBjTX-1Mpw*N?0Ma#X0J!FiJG~5p3G%X(T7sqL8 z!(F)17itq68C<=kRH=!+^bK(FwXUFlbd{Z_C-` zbpGX4Matxi;tf0PTmCj=YD#ZDFS0!9x!;O$OMBNj)cIik-d&ypUhHw7)O6k3Wj~%g zaI_yA@kW{=YdRn@WVADt^R9OsN_ZZCT9Q|ZEySNlp%V)hHu}Wwemlph{c*qMw};Z7TNb|lE~EXF2cC_+CJy`~ zD`V-T+vi?nCBArJ^R~ys_f6x9yU@+n=Wg(vcree~obUe1XGUTaBRqW+2_6t=zj=yS9_iOVDopn6;jQf7c)_xm9 z>tCNW|9IY6^9NhUWwx1gyNAldF{*IV$Yx2;VmIw5^DeD#?)TAV$ftxQJ=;x5vA3OX z-6O{{WLDm4y6A-4Ba12a@x~W7%?ce+GIGH$ZYDuC1Nt!K0oKDm6=gjiI~+cH5cg2o z#Z5=>yQGAA0iP0^hY071q#x!sU$pWkzfoxe zmv5c_G5dMOfx!i>{f?&kg=}wV;WMp4bKc)~QF`a){DNj?%S^hQ%vk3>|1yzkya(PB z>@<={@RU>kLk(sl%N{ic0+mx7nNE1qig|_F#)NqlQ$dQit&EZq@SZrjW!mS~O%s0} zvc1ij1qCfPo{5;at7?}BulJ;>5=;|#KoLZQ9QXYACaB|6$7Hh;ja#mhZ@Dsh;r2J{ z9$*Kb*R4IwdR9;eA|(IDv_Qq}i@`g)eK-Gy#*wXLZ{pYZCdfZK4Z{43n&scm)@&{D z>KC29?vE8)8@Jp?zdqH;bWp9{V+z}KJuv?FE4y~t=A?`t z(DrV$(aQteg0+uk*J*adEXA(H_{rF{Q+qFWHl0&2qL_{Nw9K!T{L;&99WHM8(B3Aa zV@52@7PRPTcfFp;Rqc#YRfOPD%lod`o{=^^4;0^Mc$3P~7!!3XE^0||+lq_YCPaPRln=ZZCU7|kQ$96iV3b9dZhzzz zv>mjwyUqFN+|IX$+w7?+11ZUNeM;h*jAPz~e7aWu*g>7Ph zy}=>xA6~sYt(~*ojWdI`*Irac_p|d{xcGv@d&Tn;D*yU3mULL^mg*E``$PJ}haXCIMV)TwGWV=* HUh}^IMEwD^ literal 0 HcmV?d00001 diff --git a/rehlds/lib/steam_api.lib b/rehlds/lib/steam_api.lib new file mode 100644 index 0000000000000000000000000000000000000000..2d77e960e80078c3a5bd4109e3f5e422eb3b87fc GIT binary patch literal 15118 zcmcgzJ#1XZ5gt-eEHjctOZ1<9kAI>lQ51jfj+7z@5>K&3n4%dTsWb*oC*GrY5P3)3 zJ;t_RAb<-aMQXuC>^3e8!<7rUapB4^5CJieRzO_1P^rp=o!Q;@c6aveF7Np!FQxfpGGu}Po#m51mzwB zFzUzlG8(=sXyjY$C(>v!qA&4@bOv=f-Nq-<;0F=);S=e6cSIpR89fy=_5%Q?8a|OO zKg99+PSC^=07m23PDU58Z=62CC(`&Af+l`OJ*3I^1x;@NFq(QMDE~H&9nv(82cwA( z1x@~h`bbj`7*#6sx0c>oUa8#pL%Fm(zqIn!a-|&x)vZc(yAGAg;_AXeQU(4Zb%e&s z&DF&>D>tsMT!%`T6~DeTUnvLSO6$E+HC)>$RW~>9R@d&gvC8_^c4apuUPo!O9yCHy zB4%;n$u>qi~WZN{97LDqj^GF1^KCy;Z$mZ`>mggl}q=gVvve7Ohk( zAjJY7TVD>VAysExh`3zq`t~+e5DYF`48nJstwa-bHrHDYwwhs34x6p&y@2$_kZ|qt zS}O<|?Tx0{K}u=X!T9rSUcvHCqhU_6P0W=msBJf8Ln7PeEWj|RP?ZVp)!Sjvijl||^KuCV zS$4J2N(hY=XH${om$lN%L3?MDu0In!R*~gt<+0e?f>?>yQHdKc-@p-AudW5J?=;q^ z{Wx_*4bq6%gqL<&Ez^l8Gb0+Z4_E>JKHq4E=(m=t;YMN#tU3}|H(!G(Uv*7Ws32V)F8i|5RAa$`-bFH9yf4f>MwW{rno7F~b z({QuQ2%LJdra!gnVQ{P7sNdMx+DMSP3>M~TU5xm`ZuauK|ErdtuwTGb+)0G96Y70@9&D6*kMhPfuL`% z);8%1M%mU&oZrm4mgN7WElg)1=rehc179sl>MUQgg>R#_wY&J5xj* zqywn)eIDRle16t1Vz+057?WKFcrpy|BgQz7&H`-W^9nvcy@W9i(nkXTk8@Zrmbr_1 z-y&vl6yQsw#~3r-M*0Bj=|k#1kKrlOQ=}ip0BT4NvHtI{ZAT`sUX1gGE&_al^aXzZ z8F}wd0&GkJJevY|8{78;zki7QpOF6mc_H@s6r6@5a1>6$2%LdFcnw~G9J~y}Fa*DW zemDlN!T=1yLD&yxVHD267@UXaU>qi38YW>1F2ZHVLjisdS6~K;a0zCi7oLY6I0P@i zVR#XK3%`Q{Z~~6QOV9<~|98v_un$bn;X0E@zHl(ywAi*R`NC=Fd|`h2X-Z19Et6HE zyoS;+&goJRpA^{|B4gyr zK9`AVd6db&k_ej|JZvW$eM=?Ex~HZB%kWYK!&}p+UHP@BIf|i0#)_$hq>8!w4$X%` z70|n>xD}ss*W*~DHtSN+s!iqd&APP(rB!LHD@|gV4ozyzg*KX6UL%?bjUx_m7`5@% zC5C&~v;!|@PZMa~g?-geP5La+F_uvvuUI+s)ltd2Ei0KRrn}bfO zSlqO!B%QS(u)A!pl65d}TH~I0!*3&e)`84~VeHT~9pZ1vQJYAj_2eoTxp=3TdKRae zaxt2Ubov@kxh2wM#r8yUo-j)HPF6Hu(3Tt`)f}}wSgTbYDzVbFI^52JDs>o32=_p< zB3eZW=U~VZ*%3|doNi6WI@gK0(KZq?(;8oHFxt>MCeqk!v;rift??5Zk1oSKhcrst zgmksU<${`SRzhw_S{diIM06~E(3wQ>+|sn;JD%~{<|c-PyWIm8CMKgB!8<(*UHjls z`>%gI+=Y=HMo9SS8m|R+ckT_9#VbGwzx*wJiJsS>cW%61tA^DfjIG3{4Chjee1=)`}sG51J~A?Tie*);~)PWe)%N^ zWM$ZgHLx4vZeIi7P2Pw(yn_sBU(Crf9b|yiDJTx(53oPcht&=kSgKDq+{Tx^zt-y^ zo$kP5rV7!;agJF`H@BFtuxX;nc8jU0e(-Oa#b9JEKFnhN5x+!FW-+YZ|A8fRGP@@c z+Idx)dfaC9aT6=;-w5CvH_uALY>fCYgJdgB|7a@>vmfHa^!^pUM9)1Q-%iF9Gfci) z=Cq@lzZAJIv_{~|bfJs+FgA6}iz)ZacVkjLq_%w@S{Fg%=lG0h1^L?z+BZy&q19mD z%JGf7JWW_SNgC0?`u3sjv!hx%n-;Yg?T;YRurMQT(a}>(YZmt59THgiPVdTL-pWn6aZ{lAY(GmCqpOdIFQ)ri-4@ zK1lkU$hKxh_So1V6WP3h&Wc^Ik2PLQVE$j9Y3y|}36T-q=SL1x^fNh1Nt5?L2wwWK}!x*-79i!KVo%f|GtrvTj03w zaT=6@k+)9l%CYOR5bK1*Qfa!ZtF++o2ZM-r(t^kHwxm6j7IcbYkE z!PF9z8IcQ)v*QqsaL$4(QrHxfymewl9?X6Vrp+~_#`Jim0Sl%~xf7uD*5o_E4BBvg zfpzL#&WAqaMYjal>Cru2dDwwYZXdFaeVqO>A~O6r5&r%r_KeC~vCK`GB{=XGP!yWH zWwh`S8?q(LPm5WM|Ix417jO8&z%PTZ~RZBZY-a44IqQgqqo>h=Y>W+c+FunpN vSag6pL3XSN=EsW)IZm7!zj(@q?Te6SG;ICKIvb*Ix17a%ZN+&NPI3PW{%$4i literal 0 HcmV?d00001 diff --git a/rehlds/msvc/PostBuild.bat b/rehlds/msvc/PostBuild.bat new file mode 100644 index 0000000..aa8a294 --- /dev/null +++ b/rehlds/msvc/PostBuild.bat @@ -0,0 +1,39 @@ +@echo OFF +:: +:: Post-build auto-deploy script +:: Create and fill PublishPath.txt file with path to deployment folder +:: I.e. PublishPath.txt should contain one line with a folder path +:: Call it so: +:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +:: + +SET targetDir=%~1 +SET targetName=%~2 +SET targetExt=%~3 +SET projectDir=%~4 +SET destination= + +IF NOT EXIST "%projectDir%\PublishPath.txt" ( + ECHO No deployment path specified. Create PublishPath.txt near PostBuild.bat with paths on separate lines for auto deployment. + exit /B 0 +) + +FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath.txt") DO ( + ECHO Deploying to: %%a + IF NOT "%%a" == "" ( + copy /Y "%targetDir%%targetName%%targetExt%" "%%a" + IF NOT ERRORLEVEL 1 ( + IF EXIST "%targetDir%%targetName%.pdb" ( + copy /Y "%targetDir%%targetName%.pdb" "%%a" + ) + ) ELSE ( + ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a' + ) + ) +) + +IF "%%a" == "" ( + ECHO No deployment path specified. +) + +exit /B 0 \ No newline at end of file diff --git a/rehlds/msvc/PostBuild_swds.bat b/rehlds/msvc/PostBuild_swds.bat new file mode 100644 index 0000000..d7547ec --- /dev/null +++ b/rehlds/msvc/PostBuild_swds.bat @@ -0,0 +1,39 @@ +@echo OFF +:: +:: Post-build auto-deploy script +:: Create and fill PublishPath.txt file with path to deployment folder +:: I.e. PublishPath.txt should contain one line with a folder path +:: Call it so: +:: IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") +:: + +SET targetDir=%~1 +SET targetName=%~2 +SET targetExt=%~3 +SET projectDir=%~4 +SET destination= + +IF NOT EXIST "%projectDir%\PublishPath_swds.txt" ( + ECHO No deployment path specified. Create PublishPath_swds.txt near PostBuild_swds.bat with paths on separate lines for auto deployment. + exit /B 0 +) + +FOR /f "tokens=* delims= usebackq" %%a IN ("%projectDir%\PublishPath_swds.txt") DO ( + ECHO Deploying to: %%a + IF NOT "%%a" == "" ( + copy /Y "%targetDir%%targetName%%targetExt%" "%%a" + IF NOT ERRORLEVEL 1 ( + IF EXIST "%targetDir%%targetName%.pdb" ( + copy /Y "%targetDir%%targetName%.pdb" "%%a" + ) + ) ELSE ( + ECHO PostBuild.bat ^(27^) : warning : Can't copy '%targetName%%targetExt%' to deploy path '%%a' + ) + ) +) + +IF "%%a" == "" ( + ECHO No deployment path specified. +) + +exit /B 0 \ No newline at end of file diff --git a/rehlds/msvc/PreBuild.bat b/rehlds/msvc/PreBuild.bat new file mode 100644 index 0000000..5ec0c3e --- /dev/null +++ b/rehlds/msvc/PreBuild.bat @@ -0,0 +1,205 @@ +@echo OFF +:: +:: Pre-build auto-versioning script +:: + +SET srcdir=%~1 +SET repodir=%~2 + +set old_version= +set old_specialbuild="" +set version_revision=0 +set version_specialbuild= +set version_date=? +set version_pdate= +set version_pdate_1= +set version_pdate_2= +set version_major= +set version_minor= +set version_maintenance= + +:: +:: Check for SubWCRev.exe presence +:: +SubWCRev.exe 2>NUL >NUL +set errlvl="%ERRORLEVEL%" + +:: +:: Read old appversion.h, if present +:: +IF EXIST "%srcdir%\appversion.h" ( + FOR /F "usebackq tokens=1,2,3" %%i in ("%srcdir%\appversion.h") do ( + IF %%i==#define ( + IF %%j==APP_VERSION_C SET old_version=%%k + IF %%j==APP_VERSION_SPECIALBUILD SET old_specialbuild=%%k + ) + ) +) + +IF NOT %errlvl% == "1" ( + echo can't locate SubWCRev.exe - auto-versioning step won't be performed + + :: if we haven't appversion.h, we need to create it + IF "%old_version%" == "" ( + set version_revision=0 + set version_date=? + goto _readVersionH + ) + exit /B 0 +) + +:: +:: Create template file for SubWCRev +:: + +:GETTEMPNAME +:: Use current path, current time and random number to create unique file name +SET TMPFILE=svn-%CD:~-15%-%RANDOM%-%TIME:~-5%-%RANDOM% +:: Remove bad characters +SET TMPFILE=%TMPFILE:\=% +SET TMPFILE=%TMPFILE:.=% +SET TMPFILE=%TMPFILE:,=% +SET TMPFILE=%TMPFILE: =% +:: Will put in a temporary directory +SET TMPFILE=%TMP%.\%TMPFILE% +IF EXIST "%TMPFILE%" GOTO :GETTEMPNAME + +echo #define SVNV_REVISION ^$WCREV^$ >"%TMPFILE%.templ" +echo #define SVNV_DATE ^$WCDATE=^%%Y-^%%m-^%%d__^%%H-^%%M-^%%S^$ >>"%TMPFILE%.templ" +echo #define SVNV_PDATE_1 ^$WCDATE=^%%Y-^%%m-^%%d^$ >>"%TMPFILE%.templ" +echo #define SVNV_PDATE_2 ^$WCDATE=^%%H:^%%M:^%%S^$ >>"%TMPFILE%.templ" +echo . >>"%TMPFILE%.templ" + +:: +:: Process template +:: +SubWCRev.exe "%repodir%\." "%TMPFILE%.templ" "%TMPFILE%.h" >NUL + +IF NOT "%ERRORLEVEL%" == "0" ( + echo SubWCRev.exe done with errors [%ERRORLEVEL%]. + echo Check if you have correct SVN repository at '%repodir%' + echo Auto-versioning step will not be performed. + + DEL /F /Q "%TMPFILE%.templ" 2>NUL + DEL /F /Q "%TMPFILE%.h" 2>NUL + + :: if we haven't appversion.h, we need to create it + IF "%old_version%" == "" ( + set version_revision=0 + set version_date=? + goto _readVersionH + ) + exit /B 0 +) + +DEL /F /Q "%TMPFILE%.templ" 2>NUL + +:: +:: Read revision and release date from it +:: +FOR /F "usebackq tokens=1,2,3" %%i in ("%TMPFILE%.h") do ( + IF %%i==#define ( + IF %%j==SVNV_REVISION SET version_revision=%%k + IF %%j==SVNV_DATE SET version_date=%%k + IF %%j==SVNV_PDATE_1 SET version_pdate_1=%%k + IF %%j==SVNV_PDATE_2 SET version_pdate_2=%%k + ) +) + +DEL /F /Q "%TMPFILE%.h" 2>NUL +SET version_pdate=%version_pdate_1% %version_pdate_2% + +:: +:: Detect local modifications +:: +SubWCRev.exe "%repodir%\." -nm >NUL + +IF "%ERRORLEVEL%" == "7" ( + set version_specialbuild=m +) ELSE ( + set version_specialbuild= +) + +:_readVersionH +:: +:: Read major, minor and maintenance version components from Version.h +:: +FOR /F "usebackq tokens=1,2,3" %%i in ("%srcdir%\version.h") do ( + IF %%i==#define ( + IF %%j==VERSION_MAJOR SET version_major=%%k + IF %%j==VERSION_MINOR SET version_minor=%%k + IF %%j==VERSION_MAINTENANCE SET version_maintenance=%%k + ) +) + +:: +:: Now form full version string like 1.0.0.1 +:: +IF "%version_maintenance%" == "" ( + set new_version=%version_major%,%version_minor%,0,%version_revision% +) ELSE ( + set new_version=%version_major%,%version_minor%,%version_maintenance%,%version_revision% +) + +:: +:: Update appversion.h if version has changed or modifications/mixed revisions detected +:: +IF NOT "%new_version%"=="%old_version%" goto _update +IF NOT "%version_specialbuild%"==%old_specialbuild% goto _update +goto _exit + +:_update +echo Updating appversion.h, new version is "%new_version%", the old one was "%old_version%" +echo new special build is "%version_specialbuild%", the old one was %old_specialbuild% + +echo #ifndef __APPVERSION_H__>"%srcdir%\appversion.h" +echo #define __APPVERSION_H__>>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" +echo // >>"%srcdir%\appversion.h" +echo // This file is generated automatically.>>"%srcdir%\appversion.h" +echo // Don't edit it.>>"%srcdir%\appversion.h" +echo // >>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" +echo // Version defines>>"%srcdir%\appversion.h" + +IF "%version_maintenance%" == "" ( + echo #define APP_VERSION_D %version_major%.%version_minor%.%version_revision% >>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRD "%version_major%.%version_minor%.%version_revision%">>"%srcdir%\appversion.h" + echo #define APP_VERSION_C %version_major%,%version_minor%,0,%version_revision% >>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRCS "%version_major%, %version_minor%, 0, %version_revision%">>"%srcdir%\appversion.h" +) ELSE ( + echo #define APP_VERSION_D %version_major%.%version_minor%.%version_maintenance%.%version_revision% >>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRD "%version_major%.%version_minor%.%version_maintenance%.%version_revision%">>"%srcdir%\appversion.h" + echo #define APP_VERSION_C %version_major%,%version_minor%,%version_maintenance%,%version_revision% >>"%srcdir%\appversion.h" + echo #define APP_VERSION_STRCS "%version_major%, %version_minor%, %version_maintenance%, %version_revision%">>"%srcdir%\appversion.h" +) + +echo.>>"%srcdir%\appversion.h" +echo #define APP_VERSION_DATE %version_date%>>"%srcdir%\appversion.h" +echo #define APP_VERSION_DATE_STR "%version_date%">>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" +echo #define APP_VERSION_PDATE_STR "%version_pdate%">>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" +echo #define APP_VERSION_YMD_STR "%version_pdate_1%">>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" + +IF NOT "%version_specialbuild%" == "" ( + echo #define APP_VERSION_FLAGS VS_FF_SPECIALBUILD>>"%srcdir%\appversion.h" + echo #define APP_VERSION_SPECIALBUILD "%version_specialbuild%">>"%srcdir%\appversion.h" + echo #define APP_VERSION APP_VERSION_STRD "" APP_VERSION_SPECIALBUILD "" VERSION_POSTFIX>>"%srcdir%\appversion.h" +) ELSE ( + echo #define APP_VERSION_FLAGS 0x0L>>"%srcdir%\appversion.h" + echo #define APP_VERSION APP_VERSION_STRD "" VERSION_POSTFIX>>"%srcdir%\appversion.h" +) +echo.>>"%srcdir%\appversion.h" + +echo #endif //__APPVERSION_H__>>"%srcdir%\appversion.h" +echo.>>"%srcdir%\appversion.h" + +:: +:: Do update of version.cpp file last modify time to force it recompile +:: +copy /b "%srcdir%\version.cpp"+,, "%srcdir%\version.cpp" + +:_exit +exit /B 0 \ No newline at end of file diff --git a/rehlds/msvc/ReHLDS.vcxproj b/rehlds/msvc/ReHLDS.vcxproj new file mode 100644 index 0000000..5855d57 --- /dev/null +++ b/rehlds/msvc/ReHLDS.vcxproj @@ -0,0 +1,873 @@ + + + + + Debug Play + Win32 + + + Debug Record + Win32 + + + Debug Swds Play + Win32 + + + Debug Swds + Win32 + + + Debug + Win32 + + + Release Play + Win32 + + + Release + Win32 + + + Tests + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + true + + + true + true + true + + + true + true + + + true + true + true + true + true + false + true + + + false + + + + + + + + + + true + true + true + true + true + true + true + true + + + + + + + + + + + Create + Create + precompiled.h + precompiled.h + Create + Create + precompiled.h + precompiled.h + Create + precompiled.h + Create + Create + precompiled.h + precompiled.h + Create + precompiled.h + + + + + + + + + + true + true + true + true + true + true + true + + + true + true + true + true + false + + + true + true + true + true + true + true + true + + + true + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + true + true + true + true + + + true + true + true + true + true + true + + + + + {792df067-9904-4579-99b9-46c17277ade3} + + + {ceb94f7c-e459-4673-aabb-36e2074396c0} + + + + {70A2B904-B7DB-4C48-8DE0-AF567360D572} + ReHLDS + + + + DynamicLibrary + true + v120_xp + MultiByte + + + DynamicLibrary + true + v120_xp + MultiByte + + + DynamicLibrary + true + v120_xp + MultiByte + + + DynamicLibrary + true + v120_xp + MultiByte + + + DynamicLibrary + true + v120_xp + MultiByte + + + Application + true + v120_xp + MultiByte + + + DynamicLibrary + false + v120_xp + true + MultiByte + + + DynamicLibrary + false + v120_xp + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + filesystem_stdio + + + swds + + + filesystem_stdio + + + swds + + + filesystem_stdio + + + filesystem_stdio + + + filesystem_stdio + + + filesystem_stdio + + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + Setup version from SVN revision + + + $(ProjectDir)\..\;$(ProjectDir)\..\hookers\;$(ProjectDir)\..\metamod\include\;$(ProjectDir)\..\public\rehlds\;$(ProjectDir)\..\common;$(ProjectDir)\..\engine;$(ProjectDir)\..\public;$(ProjectDir)\..\pm_shared;$(ProjectDir)\..\rehlds\;$(ProjectDir)\..\testsuite\;$(VCInstallDir)UnitTest\include;$(SolutionDir)..\dep\bzip2\include\;$(SolutionDir)..\dep\cppunitlite\include\;%(AdditionalIncludeDirectories) + Level3 + Disabled + true + REHLDS_SELF;HOOK_ENGINE;REHLDS_FIXES;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + Precise + /arch:IA32 %(AdditionalOptions) + MultiThreadedDebug + Use + precompiled.h + + + true + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + + + + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + subversion.always.run + subversion.always.run + + + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + Setup version from SVN revision + + + $(ProjectDir)\..\;$(ProjectDir)\..\hookers\;$(ProjectDir)\..\metamod\include\;$(ProjectDir)\..\public\rehlds\;$(ProjectDir)\..\common;$(ProjectDir)\..\engine;$(ProjectDir)\..\public;$(ProjectDir)\..\pm_shared;$(ProjectDir)\..\rehlds\;$(ProjectDir)\..\testsuite\;$(VCInstallDir)UnitTest\include;$(SolutionDir)..\dep\bzip2\include\;$(SolutionDir)..\dep\cppunitlite\include\;%(AdditionalIncludeDirectories) + Level3 + Disabled + true + REHLDS_SELF;REHLDS_FIXES;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + Precise + /arch:IA32 %(AdditionalOptions) + MultiThreadedDebug + Use + precompiled.h + + + true + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + + + + + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + IF EXIST "$(ProjectDir)PostBuild_swds.bat" (CALL "$(ProjectDir)PostBuild_swds.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + subversion.always.run + subversion.always.run + + + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + Setup version from SVN revision + + + $(ProjectDir)\..\;$(ProjectDir)\..\hookers\;$(ProjectDir)\..\metamod\include\;$(ProjectDir)\..\public\rehlds\;$(ProjectDir)\..\common;$(ProjectDir)\..\engine;$(ProjectDir)\..\public;$(ProjectDir)\..\pm_shared;$(ProjectDir)\..\rehlds\;$(ProjectDir)\..\testsuite\;$(VCInstallDir)UnitTest\include;$(SolutionDir)..\dep\bzip2\include\;$(SolutionDir)..\dep\cppunitlite\include\;%(AdditionalIncludeDirectories) + Level3 + Disabled + true + REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + Precise + /arch:IA32 %(AdditionalOptions) + MultiThreadedDebug + Use + precompiled.h + + + true + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + + + + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + subversion.always.run + subversion.always.run + + + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + Setup version from SVN revision + + + $(ProjectDir)\..\;$(ProjectDir)\..\hookers\;$(ProjectDir)\..\metamod\include\;$(ProjectDir)\..\public\rehlds\;$(ProjectDir)\..\common;$(ProjectDir)\..\engine;$(ProjectDir)\..\public;$(ProjectDir)\..\pm_shared;$(ProjectDir)\..\rehlds\;$(ProjectDir)\..\testsuite\;$(VCInstallDir)UnitTest\include;$(SolutionDir)..\dep\bzip2\include\;$(SolutionDir)..\dep\cppunitlite\include\;%(AdditionalIncludeDirectories) + Level3 + Disabled + true + REHLDS_SELF;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + Precise + /arch:IA32 %(AdditionalOptions) + MultiThreadedDebug + Use + precompiled.h + + + true + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + + + + + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + 0x4970000 + false + + + IF EXIST "$(ProjectDir)PostBuild_swds.bat" (CALL "$(ProjectDir)PostBuild_swds.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + subversion.always.run + subversion.always.run + + + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + Setup version from SVN revision + + + $(ProjectDir)\..\;$(ProjectDir)\..\hookers\;$(ProjectDir)\..\metamod\include\;$(ProjectDir)\..\public\rehlds\;$(ProjectDir)\..\common;$(ProjectDir)\..\engine;$(ProjectDir)\..\public;$(ProjectDir)\..\pm_shared;$(ProjectDir)\..\rehlds\;$(ProjectDir)\..\testsuite\;$(VCInstallDir)UnitTest\include;$(SolutionDir)..\dep\bzip2\include\;$(SolutionDir)..\dep\cppunitlite\include\;%(AdditionalIncludeDirectories) + Level3 + Disabled + true + REHLDS_SELF;HOOK_ENGINE;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + Precise + /arch:IA32 %(AdditionalOptions) + MultiThreadedDebug + Use + precompiled.h + + + true + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + + + + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + subversion.always.run + subversion.always.run + + + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + Setup version from SVN revision + + + $(ProjectDir)\..\;$(ProjectDir)\..\hookers\;$(ProjectDir)\..\metamod\include\;$(ProjectDir)\..\public\rehlds\;$(ProjectDir)\..\common;$(ProjectDir)\..\engine;$(ProjectDir)\..\public;$(ProjectDir)\..\pm_shared;$(ProjectDir)\..\rehlds\;$(ProjectDir)\..\testsuite\;$(VCInstallDir)UnitTest\include;$(SolutionDir)..\dep\bzip2\include\;$(SolutionDir)..\dep\cppunitlite\include\;%(AdditionalIncludeDirectories) + Level3 + Disabled + true + REHLDS_SELF;_BUILD_FROM_IDE;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) + MultiThreadedDebug + Use + precompiled.h + + + true + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + + + + + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + copy /Y $(ProjectDir)..\lib\steam_api.dll $(OutDir) + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + subversion.always.run + subversion.always.run + + + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + Setup version from SVN revision + + + $(ProjectDir)\..\;$(ProjectDir)\..\hookers\;$(ProjectDir)\..\metamod\include\;$(ProjectDir)\..\public\rehlds\;$(ProjectDir)\..\common;$(ProjectDir)\..\engine;$(ProjectDir)\..\public;$(ProjectDir)\..\pm_shared;$(ProjectDir)\..\rehlds\;$(ProjectDir)\..\testsuite\;$(VCInstallDir)UnitTest\include;$(SolutionDir)..\dep\bzip2\include\;$(SolutionDir)..\dep\cppunitlite\include\;%(AdditionalIncludeDirectories) + Level3 + MaxSpeed + true + true + true + REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + /arch:IA32 %(AdditionalOptions) + Use + precompiled.h + + + true + true + true + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + + + + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + subversion.always.run + subversion.always.run + + + + + IF EXIST "$(ProjectDir)PreBuild.bat" (CALL "$(ProjectDir)PreBuild.bat" "$(ProjectDir)..\version\" "$(ProjectDir)..\") + Setup version from SVN revision + + + $(ProjectDir)\..\;$(ProjectDir)\..\hookers\;$(ProjectDir)\..\metamod\include\;$(ProjectDir)\..\public\rehlds\;$(ProjectDir)\..\common;$(ProjectDir)\..\engine;$(ProjectDir)\..\public;$(ProjectDir)\..\pm_shared;$(ProjectDir)\..\rehlds\;$(ProjectDir)\..\testsuite\;$(VCInstallDir)UnitTest\include;$(SolutionDir)..\dep\bzip2\include\;$(SolutionDir)..\dep\cppunitlite\include\;%(AdditionalIncludeDirectories) + Level3 + MaxSpeed + true + true + true + REHLDS_SELF;HOOK_ENGINE;REHLDS_CHECKS;USE_BREAKPAD_HANDLER;DEDICATED;SWDS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + /arch:IA32 %(AdditionalOptions) + Use + precompiled.h + + + true + true + true + psapi.lib;ws2_32.lib;$(ProjectDir)../lib/steam_api.lib;%(AdditionalDependencies) + + + + + $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories) + + + IF EXIST "$(ProjectDir)PostBuild.bat" (CALL "$(ProjectDir)PostBuild.bat" "$(TargetDir)" "$(TargetName)" "$(TargetExt)" "$(ProjectDir)") + Automatic deployment script + + + echo Empty Action + Force build to run Pre-Build event + subversion.always.run + subversion.always.run + + + + + + \ No newline at end of file diff --git a/rehlds/msvc/ReHLDS.vcxproj.filters b/rehlds/msvc/ReHLDS.vcxproj.filters new file mode 100644 index 0000000..f527489 --- /dev/null +++ b/rehlds/msvc/ReHLDS.vcxproj.filters @@ -0,0 +1,1041 @@ + + + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + false + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {7be88557-a49b-4c62-8df3-d7134a578201} + + + {eeaac718-712b-453f-9d34-4cefc9e0fe59} + + + {bcd7bb13-9910-4e5d-bb7a-b13b6b813fe8} + + + {66f51dad-107e-440d-9d17-f940a5f097b6} + + + {572aedd9-6d8e-4099-86dc-aae0d6dce836} + + + {be634138-1bc8-4547-b84f-8885675922d6} + + + {fe7a8e81-b7d4-4540-ab5b-457ed93672ce} + + + {9de0de20-070f-4fae-a9df-3dca942e65a7} + false + + + {d74cb79e-afd5-4215-af0e-029e38925be0} + + + {e39a67b3-80ba-4cf5-b400-47b81b798984} + + + {f1a6df08-3b16-4524-b67e-21f6f4e16fa1} + + + {a54a9aa9-f95b-4199-bdf0-9640fdb5590b} + + + {10ba586f-5f90-4a4b-940c-287810a7e9bc} + + + {a49f0aeb-4e6b-4939-a396-1599d2a7d971} + + + {b9870aee-d852-4d90-98d7-317ec1283872} + + + {c91850f0-8e81-47e5-9a5f-53215766e960} + + + + + hookers + + + hookers + + + hookers + + + engine\common + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + hookers + + + public + + + engine\common + + + engine\common + + + public + + + engine\server + + + engine\common + + + engine\common + + + engine\server + + + engine\server + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + testsuite + + + testsuite + + + testsuite + + + testsuite + + + rehlds + + + rehlds + + + engine\common + + + unittests + + + engine\common + + + engine\common + + + engine\common + + + hookers + + + unittests + + + rehlds + + + engine\common + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + engine\common + + + engine\common + + + public + + + public\tier0 + + + public\tier0 + + + engine + + + public\tier0 + + + engine\common + + + rehlds + + + unittests + + + engine\common + + + unittests + + + public + + + engine\common + + + engine\server + + + engine\server + + + engine\common + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + hookers + + + rehlds + + + rehlds + + + rehlds + + + testsuite + + + public\rehlds + + + public\rehlds + + + engine\common + + + rehlds + + + rehlds + + + + + hookers + + + version + + + engine\common + + + hookers + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + engine\common + + + engine\common + + + engine\client + + + engine\common + + + engine\client + + + engine\client + + + engine\common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + common + + + engine\client + + + engine\client + + + common + + + engine\common + + + engine\common + + + public + + + public + + + public + + + public\steam + + + engine\common + + + engine\common + + + engine\common + + + public + + + engine\server + + + engine\common + + + engine\server + + + public + + + public + + + engine\common + + + engine\server + + + engine\server + + + engine\common + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + public\steam + + + common + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + testsuite + + + testsuite + + + testsuite + + + testsuite + + + rehlds + + + rehlds + + + engine\common + + + engine\common + + + engine\common + + + hookers + + + rehlds + + + hookers + + + engine\common + + + engine\common + + + engine\common + + + engine\server + + + engine\common + + + engine\common + + + engine\common + + + public + + + public\tier0 + + + public\tier0 + + + public\tier0 + + + public + + + public + + + public + + + public + + + public + + + public\tier0 + + + public\tier0 + + + public\tier0 + + + public\tier0 + + + public + + + common + + + engine + + + engine\common + + + engine\common + + + public + + + engine\server + + + engine\server + + + public + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + engine\common + + + public + + + public + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + rehlds + + + rehlds + + + rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + engine\common + + + public\rehlds + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + dlls + + + testsuite + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + engine\common + + + public\rehlds + + + rehlds + + + rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + public\rehlds + + + engine\common + + + engine\common + + + public\rehlds + + + + + linux + + + linux + + + \ No newline at end of file diff --git a/rehlds/pm_shared/pm_debug.h b/rehlds/pm_shared/pm_debug.h new file mode 100644 index 0000000..b9be095 --- /dev/null +++ b/rehlds/pm_shared/pm_debug.h @@ -0,0 +1,26 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PM_DEBUG_H +#define PM_DEBUG_H +#ifdef _WIN32 +#pragma once +#endif + +void PM_ViewEntity( void ); +void PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life); +void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert); +void PM_ShowClipBox( void ); + +#endif // PMOVEDBG_H diff --git a/rehlds/pm_shared/pm_defs.h b/rehlds/pm_shared/pm_defs.h new file mode 100644 index 0000000..1a5f01d --- /dev/null +++ b/rehlds/pm_shared/pm_defs.h @@ -0,0 +1,228 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// pm_defs.h +#if !defined( PM_DEFSH ) +#define PM_DEFSH +#ifdef _WIN32 +#pragma once +#endif + +#include "archtypes.h" // DAL +#define MAX_PHYSENTS 600 // Must have room for all entities in the world. +#define MAX_MOVEENTS 64 +#define MAX_CLIP_PLANES 5 + +#define PM_NORMAL 0x00000000 +#define PM_STUDIO_IGNORE 0x00000001 // Skip studio models +#define PM_STUDIO_BOX 0x00000002 // Use boxes for non-complex studio models (even in traceline) +#define PM_GLASS_IGNORE 0x00000004 // Ignore entities with non-normal rendermode +#define PM_WORLD_ONLY 0x00000008 // Only trace against the world + +// Values for flags parameter of PM_TraceLine +#define PM_TRACELINE_PHYSENTSONLY 0 +#define PM_TRACELINE_ANYVISIBLE 1 + + +#include "pm_info.h" + +// PM_PlayerTrace results. +#include "pmtrace.h" + +#if !defined ( USERCMD_H ) +#include "usercmd.h" +#endif + +#include "const.h" + + +// physent_t +typedef struct physent_s +{ + char name[32]; // Name of model, or "player" or "world". + int player; + vec3_t origin; // Model's origin in world coordinates. + struct model_s *model; // only for bsp models + struct model_s *studiomodel; // SOLID_BBOX, but studio clip intersections. + vec3_t mins, maxs; // only for non-bsp models + int info; // For client or server to use to identify (index into edicts or cl_entities) + vec3_t angles; // rotated entities need this info for hull testing to work. + + int solid; // Triggers and func_door type WATER brushes are SOLID_NOT + int skin; // BSP Contents for such things like fun_door water brushes. + int rendermode; // So we can ignore glass + + // Complex collision detection. + float frame; + int sequence; + byte controller[4]; + byte blending[2]; + + int movetype; + int takedamage; + int blooddecal; + int team; + int classnumber; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; +} physent_t; + + +typedef struct playermove_s +{ + int player_index; // So we don't try to run the PM_CheckStuck nudging too quickly. + qboolean server; // For debugging, are we running physics code on server side? + + qboolean multiplayer; // 1 == multiplayer server + float time; // realtime on host, for reckoning duck timing + float frametime; // Duration of this frame + + vec3_t forward, right, up; // Vectors for angles + // player state + vec3_t origin; // Movement origin. + vec3_t angles; // Movement view angles. + vec3_t oldangles; // Angles before movement view angles were looked at. + vec3_t velocity; // Current movement direction. + vec3_t movedir; // For waterjumping, a forced forward velocity so we can fly over lip of ledge. + vec3_t basevelocity; // Velocity of the conveyor we are standing, e.g. + + // For ducking/dead + vec3_t view_ofs; // Our eye position. + float flDuckTime; // Time we started duck + qboolean bInDuck; // In process of ducking or ducked already? + + // For walking/falling + int flTimeStepSound; // Next time we can play a step sound + int iStepLeft; + + float flFallVelocity; + vec3_t punchangle; + + float flSwimTime; + + float flNextPrimaryAttack; + + int effects; // MUZZLE FLASH, e.g. + + int flags; // FL_ONGROUND, FL_DUCKING, etc. + int usehull; // 0 = regular player hull, 1 = ducked player hull, 2 = point hull + float gravity; // Our current gravity and friction. + float friction; + int oldbuttons; // Buttons last usercmd + float waterjumptime; // Amount of time left in jumping out of water cycle. + qboolean dead; // Are we a dead player? + int deadflag; + int spectator; // Should we use spectator physics model? + int movetype; // Our movement type, NOCLIP, WALK, FLY + + int onground; + int waterlevel; + int watertype; + int oldwaterlevel; + + char sztexturename[256]; + char chtexturetype; + + float maxspeed; + float clientmaxspeed; // Player specific maxspeed + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; + // world state + // Number of entities to clip against. + int numphysent; + physent_t physents[MAX_PHYSENTS]; + // Number of momvement entities (ladders) + int nummoveent; + // just a list of ladders + physent_t moveents[MAX_MOVEENTS]; + + // All things being rendered, for tracing against things you don't actually collide with + int numvisent; + physent_t visents[ MAX_PHYSENTS ]; + + // input to run through physics. + usercmd_t cmd; + + // Trace results for objects we collided with. + int numtouch; + pmtrace_t touchindex[MAX_PHYSENTS]; + + char physinfo[ MAX_PHYSINFO_STRING ]; // Physics info string + + struct movevars_s *_movevars; + vec3_t _player_mins[ 4 ]; + vec3_t _player_maxs[ 4 ]; + + // Common functions + const char *(*PM_Info_ValueForKey) ( const char *s, const char *key ); + void (*PM_Particle)( float *origin, int color, float life, int zpos, int zvel); + int (*PM_TestPlayerPosition) (float *pos, pmtrace_t *ptrace ); + void (*Con_NPrintf)( int idx, char *fmt, ... ); + void (*Con_DPrintf)( char *fmt, ... ); + void (*Con_Printf)( char *fmt, ... ); + double (*Sys_FloatTime)( void ); + void (*PM_StuckTouch)( int hitent, pmtrace_t *ptraceresult ); + int (*PM_PointContents) (float *p, int *truecontents /*filled in if this is non-null*/ ); + int (*PM_TruePointContents) (float *p); + int (*PM_HullPointContents) ( struct hull_s *hull, int num, float *p); + pmtrace_t (*PM_PlayerTrace) (float *start, float *end, int traceFlags, int ignore_pe ); + struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehulll, int ignore_pe ); + int32 (*RandomLong)( int32 lLow, int32 lHigh ); + float (*RandomFloat)( float flLow, float flHigh ); + int (*PM_GetModelType)( struct model_s *mod ); + void (*PM_GetModelBounds)( struct model_s *mod, float *mins, float *maxs ); + void *(*PM_HullForBsp)( physent_t *pe, float *offset ); + float (*PM_TraceModel)( physent_t *pEnt, float *start, float *end, trace_t *trace ); + int (*COM_FileSize)(char *filename); + byte *(*COM_LoadFile) (const char *path, int usehunk, int *pLength); + void (*COM_FreeFile) ( void *buffer ); + char *(*memfgets)( byte *pMemFile, int fileSize, int *pFilePos, char *pBuffer, int bufferSize ); + + // Functions + // Run functions for this frame? + qboolean runfuncs; + void (*PM_PlaySound) ( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); + const char *(*PM_TraceTexture) ( int ground, float *vstart, float *vend ); + void (*PM_PlaybackEventFull) ( int flags, int clientindex, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); + + pmtrace_t (*PM_PlayerTraceEx) (float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe ) ); + int (*PM_TestPlayerPositionEx) (float *pos, pmtrace_t *ptrace, int (*pfnIgnore)( physent_t *pe ) ); + struct pmtrace_s *(*PM_TraceLineEx)( float *start, float *end, int flags, int usehulll, int (*pfnIgnore)( physent_t *pe ) ); +} playermove_t; + +#endif diff --git a/rehlds/pm_shared/pm_info.h b/rehlds/pm_shared/pm_info.h new file mode 100644 index 0000000..3525e79 --- /dev/null +++ b/rehlds/pm_shared/pm_info.h @@ -0,0 +1,25 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Physics info string definition + +#ifndef PM_INFO_H +#define PM_INFO_H +#ifdef _WIN32 +#pragma once +#endif + +#define MAX_PHYSINFO_STRING 256 + +#endif // PM_INFO_H diff --git a/rehlds/pm_shared/pm_materials.h b/rehlds/pm_shared/pm_materials.h new file mode 100644 index 0000000..c5816d7 --- /dev/null +++ b/rehlds/pm_shared/pm_materials.h @@ -0,0 +1,36 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#if !defined( PM_MATERIALSH ) +#define PM_MATERIALSH +#ifdef _WIN32 +#pragma once +#endif + +#define CBTEXTURENAMEMAX 13 // only load first n chars of name + +#define CHAR_TEX_CONCRETE 'C' // texture types +#define CHAR_TEX_METAL 'M' +#define CHAR_TEX_DIRT 'D' +#define CHAR_TEX_VENT 'V' +#define CHAR_TEX_GRATE 'G' +#define CHAR_TEX_TILE 'T' +#define CHAR_TEX_SLOSH 'S' +#define CHAR_TEX_WOOD 'W' +#define CHAR_TEX_COMPUTER 'P' +#define CHAR_TEX_GLASS 'Y' +#define CHAR_TEX_FLESH 'F' +#define CHAR_TEX_SNOW 'N' + +#endif // !PM_MATERIALSH diff --git a/rehlds/pm_shared/pm_movevars.h b/rehlds/pm_shared/pm_movevars.h new file mode 100644 index 0000000..3bea8b3 --- /dev/null +++ b/rehlds/pm_shared/pm_movevars.h @@ -0,0 +1,47 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// pm_movevars.h +#if !defined( PM_MOVEVARSH ) +#define PM_MOVEVARSH + +// movevars_t // Physics variables. +typedef struct movevars_s movevars_t; + +struct movevars_s +{ + float gravity; // Gravity for map + float stopspeed; // Deceleration when not moving + float maxspeed; // Max allowed speed + float spectatormaxspeed; + float accelerate; // Acceleration factor + float airaccelerate; // Same for when in open air + float wateraccelerate; // Same for when in water + float friction; + float edgefriction; // Extra friction near dropofs + float waterfriction; // Less in water + float entgravity; // 1.0 + float bounce; // Wall bounce value. 1.0 + float stepsize; // sv_stepsize; + float maxvelocity; // maximum server velocity. + float zmax; // Max z-buffer range (for GL) + float waveHeight; // Water wave height (for GL) + qboolean footsteps; // Play footstep sounds + char skyName[32]; // Name of the sky map + float rollangle; + float rollspeed; + float skycolor_r; // Sky color + float skycolor_g; // + float skycolor_b; // + float skyvec_x; // Sky vector + float skyvec_y; // + float skyvec_z; // +}; + +extern movevars_t movevars; + +#endif diff --git a/rehlds/pm_shared/pm_shared.h b/rehlds/pm_shared/pm_shared.h new file mode 100644 index 0000000..5a73495 --- /dev/null +++ b/rehlds/pm_shared/pm_shared.h @@ -0,0 +1,38 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +// +// pm_shared.h +// +#if !defined( PM_SHAREDH ) +#define PM_SHAREDH +#ifdef _WIN32 +#pragma once +#endif + +void PM_Init( struct playermove_s *ppmove ); +void PM_Move ( struct playermove_s *ppmove, int server ); +char PM_FindTextureType( char *name ); + +// Spectator Movement modes (stored in pev->iuser1, so the physics code can get at them) +#define OBS_NONE 0 +#define OBS_CHASE_LOCKED 1 +#define OBS_CHASE_FREE 2 +#define OBS_ROAMING 3 +#define OBS_IN_EYE 4 +#define OBS_MAP_FREE 5 +#define OBS_MAP_CHASE 6 + +#endif diff --git a/rehlds/public/FileSystem.h b/rehlds/public/FileSystem.h new file mode 100644 index 0000000..4a3c621 --- /dev/null +++ b/rehlds/public/FileSystem.h @@ -0,0 +1,189 @@ +//========= Copyright � 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef FILESYSTEM_H +#define FILESYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" +#include +#include + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +typedef FILE * FileHandle_t; +typedef int FileFindHandle_t; +typedef int WaitForResourcesHandle_t; + + +//----------------------------------------------------------------------------- +// Enums used by the interface +//----------------------------------------------------------------------------- +#ifndef FILESYSTEM_INTERNAL_H +typedef enum +{ + FILESYSTEM_SEEK_HEAD = 0, + FILESYSTEM_SEEK_CURRENT, + FILESYSTEM_SEEK_TAIL, +} FileSystemSeek_t; + +enum +{ + FILESYSTEM_INVALID_FIND_HANDLE = -1 +}; + +typedef enum +{ + // Don't print anything + FILESYSTEM_WARNING_QUIET = 0, + + // On shutdown, report names of files left unclosed + FILESYSTEM_WARNING_REPORTUNCLOSED, + + // Report number of times a file was opened, closed + FILESYSTEM_WARNING_REPORTUSAGE, + + // Report all open/close events to console ( !slow! ) + FILESYSTEM_WARNING_REPORTALLACCESSES +} FileWarningLevel_t; + +#define FILESYSTEM_INVALID_HANDLE ( FileHandle_t )0 +#endif + +// turn off any windows defines +#undef GetCurrentDirectory + +//----------------------------------------------------------------------------- +// Purpose: Main file system interface +//----------------------------------------------------------------------------- +class IFileSystem : public IBaseInterface +{ +public: + // Mount and unmount the filesystem + virtual void Mount( void ) = 0; + virtual void Unmount( void ) = 0; + + // Remove all search paths (including write path?) + virtual void RemoveAllSearchPaths( void ) = 0; + + // Add paths in priority order (mod dir, game dir, ....) + // If one or more .pak files are in the specified directory, then they are + // added after the file system path + // If the path is the relative path to a .bsp file, then any previous .bsp file + // override is cleared and the current .bsp is searched for an embedded PAK file + // and this file becomes the highest priority search path ( i.e., it's looked at first + // even before the mod's file system path ). + virtual void AddSearchPath( const char *pPath, const char *pathID ) = 0; + virtual bool RemoveSearchPath( const char *pPath ) = 0; + + // Deletes a file + virtual void RemoveFile( const char *pRelativePath, const char *pathID ) = 0; + + // this isn't implementable on STEAM as is. + virtual void CreateDirHierarchy( const char *path, const char *pathID ) = 0; + + // File I/O and info + virtual bool FileExists( const char *pFileName ) = 0; + virtual bool IsDirectory( const char *pFileName ) = 0; + + // opens a file + // if pathID is NULL, all paths will be searched for the file + virtual FileHandle_t Open( const char *pFileName, const char *pOptions, const char *pathID = 0L ) = 0; + + virtual void Close( FileHandle_t file ) = 0; + + virtual void Seek( FileHandle_t file, int pos, FileSystemSeek_t seekType ) = 0; + virtual unsigned int Tell( FileHandle_t file ) = 0; + + virtual unsigned int Size( FileHandle_t file ) = 0; + virtual unsigned int Size( const char *pFileName ) = 0; + + virtual long GetFileTime( const char *pFileName ) = 0; + virtual void FileTimeToString( char* pStrip, int maxCharsIncludingTerminator, long fileTime ) = 0; + + virtual bool IsOk( FileHandle_t file ) = 0; + + virtual void Flush( FileHandle_t file ) = 0; + virtual bool EndOfFile( FileHandle_t file ) = 0; + + virtual int Read( void* pOutput, int size, FileHandle_t file ) = 0; + virtual int Write( void const* pInput, int size, FileHandle_t file ) = 0; + virtual char *ReadLine( char *pOutput, int maxChars, FileHandle_t file ) = 0; + virtual int FPrintf( FileHandle_t file, char *pFormat, ... ) = 0; + + // direct filesystem buffer access + // returns a handle to a buffer containing the file data + // this is the optimal way to access the complete data for a file, + // since the file preloader has probably already got it in memory + virtual void *GetReadBuffer( FileHandle_t file, int *outBufferSize, bool failIfNotInCache ) = 0; + virtual void ReleaseReadBuffer( FileHandle_t file, void *readBuffer ) = 0; + + // FindFirst/FindNext + virtual const char *FindFirst( const char *pWildCard, FileFindHandle_t *pHandle, const char *pathID = 0L ) = 0; + virtual const char *FindNext( FileFindHandle_t handle ) = 0; + virtual bool FindIsDirectory( FileFindHandle_t handle ) = 0; + virtual void FindClose( FileFindHandle_t handle ) = 0; + + virtual void GetLocalCopy( const char *pFileName ) = 0; + + virtual const char *GetLocalPath( const char *pFileName, char *pLocalPath, int localPathBufferSize ) = 0; + + // Note: This is sort of a secondary feature; but it's really useful to have it here + virtual char *ParseFile( char* pFileBytes, char* pToken, bool* pWasQuoted ) = 0; + + // Returns true on success ( based on current list of search paths, otherwise false if it can't be resolved ) + virtual bool FullPathToRelativePath( const char *pFullpath, char *pRelative ) = 0; + + // Gets the current working directory + virtual bool GetCurrentDirectory( char* pDirectory, int maxlen ) = 0; + + // Dump to printf/OutputDebugString the list of files that have not been closed + virtual void PrintOpenedFiles( void ) = 0; + + virtual void SetWarningFunc( void (*pfnWarning)( const char *fmt, ... ) ) = 0; + virtual void SetWarningLevel( FileWarningLevel_t level ) = 0; + + virtual void LogLevelLoadStarted( const char *name ) = 0; + virtual void LogLevelLoadFinished( const char *name ) = 0; + virtual int HintResourceNeed( const char *hintlist, int forgetEverything ) = 0; + virtual int PauseResourcePreloading( void ) = 0; + virtual int ResumeResourcePreloading( void ) = 0; + virtual int SetVBuf( FileHandle_t stream, char *buffer, int mode, long size ) = 0; + virtual void GetInterfaceVersion( char *p, int maxlen ) = 0; + virtual bool IsFileImmediatelyAvailable(const char *pFileName) = 0; + + // starts waiting for resources to be available + // returns FILESYSTEM_INVALID_HANDLE if there is nothing to wait on + virtual WaitForResourcesHandle_t WaitForResources( const char *resourcelist ) = 0; + // get progress on waiting for resources; progress is a float [0, 1], complete is true on the waiting being done + // returns false if no progress is available + // any calls after complete is true or on an invalid handle will return false, 0.0f, true + virtual bool GetWaitForResourcesProgress( WaitForResourcesHandle_t handle, float *progress /* out */ , bool *complete /* out */ ) = 0; + // cancels a progress call + virtual void CancelWaitForResources( WaitForResourcesHandle_t handle ) = 0; + // returns true if the appID has all its caches fully preloaded + virtual bool IsAppReadyForOfflinePlay( int appID ) = 0; + + // interface for custom pack files > 4Gb + virtual bool AddPackFile( const char *fullpath, const char *pathID ) = 0; + + // open a file but force the data to come from the steam cache, NOT from disk + virtual FileHandle_t OpenFromCacheForRead( const char *pFileName, const char *pOptions, const char *pathID = 0L ) = 0; + + virtual void AddSearchPathNoWrite( const char *pPath, const char *pathID ) = 0; +}; + +// Steam3/Src compat +#define IBaseFileSystem IFileSystem + +#define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" + +#endif // FILESYSTEM_H diff --git a/rehlds/public/archtypes.h b/rehlds/public/archtypes.h new file mode 100644 index 0000000..deb438f --- /dev/null +++ b/rehlds/public/archtypes.h @@ -0,0 +1,21 @@ +// +// Word size dependent definitions +// DAL 1/03 +// +#ifndef ARCHTYPES_H +#define ARCHTYPES_H + +#include "steam/steamtypes.h" + +#ifndef _WIN32 +#define MAX_PATH PATH_MAX +#include +#include +#include +#include +#define _S_IREAD S_IREAD +#define _S_IWRITE S_IWRITE +typedef long unsigned int ulong; +#endif + +#endif // ARCHTYPES_H diff --git a/rehlds/public/basetypes.h b/rehlds/public/basetypes.h new file mode 100644 index 0000000..5f3a677 --- /dev/null +++ b/rehlds/public/basetypes.h @@ -0,0 +1,300 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef BASETYPES_H +#define BASETYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "protected_things.h" +#include "commonmacros.h" + + +// For backward compatibilty only... +#include "tier0/platform.h" + +// stdio.h +#ifndef NULL +#define NULL 0 +#endif + + +#define ExecuteNTimes( nTimes, x ) \ + { \ + static int __executeCount=0;\ + if ( __executeCount < nTimes )\ + { \ + x; \ + ++__executeCount; \ + } \ + } + + +#define ExecuteOnce( x ) ExecuteNTimes( 1, x ) + + +// Pad a number so it lies on an N byte boundary. +// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4 +#define PAD_NUMBER(number, boundary) \ + ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary) + +// In case this ever changes +#define M_PI 3.14159265358979323846 + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifdef __cplusplus +template +inline T clamp2(T const &val, T const &minVal, T const &maxVal) //renamed to clamp2 to avoid conflicts with clamp defined in mathlib +{ + if (val < minVal) + return minVal; + else if (val > maxVal) + return maxVal; + else + return val; +} +#endif + +#ifndef FALSE +#define FALSE 0 +#define TRUE (!FALSE) +#endif + + +typedef int BOOL; +typedef int qboolean; +typedef unsigned long ULONG; +typedef unsigned char BYTE; +typedef unsigned char byte; +typedef unsigned short word; + +#include "string_t.h" + +typedef float vec_t; + + +// FIXME: this should move +#ifndef __cplusplus +#define true TRUE +#define false FALSE +#endif + +//----------------------------------------------------------------------------- +// look for NANs, infinities, and underflows. +// This assumes the ANSI/IEEE 754-1985 standard +//----------------------------------------------------------------------------- + +#ifdef __cplusplus + +inline unsigned long& FloatBits(vec_t& f) +{ + return *reinterpret_cast(&f); +} + +inline unsigned long const& FloatBits(vec_t const& f) +{ + return *reinterpret_cast(&f); +} + +inline vec_t BitsToFloat(unsigned long i) +{ + return *reinterpret_cast(&i); +} + +inline bool IsFinite(vec_t f) +{ + return ((FloatBits(f) & 0x7F800000) != 0x7F800000); +} + +inline unsigned long FloatAbsBits(vec_t f) +{ + return FloatBits(f) & 0x7FFFFFFF; +} + +inline float FloatMakeNegative(vec_t f) +{ + return BitsToFloat(FloatBits(f) | 0x80000000); +} + +#if defined( WIN32 ) + +//#include +// Just use prototype from math.h +#ifdef __cplusplus +extern "C" +{ +#endif + double __cdecl fabs(double); +#ifdef __cplusplus +} +#endif + +// In win32 try to use the intrinsic fabs so the optimizer can do it's thing inline in the code +#pragma intrinsic( fabs ) +// Also, alias float make positive to use fabs, too +// NOTE: Is there a perf issue with double<->float conversion? +inline float FloatMakePositive(vec_t f) +{ + return fabs(f); +} +#else +inline float FloatMakePositive(vec_t f) +{ + return BitsToFloat(FloatBits(f) & 0x7FFFFFFF); +} +#endif + +inline float FloatNegate(vec_t f) +{ + return BitsToFloat(FloatBits(f) ^ 0x80000000); +} + + +#define FLOAT32_NAN_BITS (unsigned long)0x7FC00000 // not a number! +#define FLOAT32_NAN BitsToFloat( FLOAT32_NAN_BITS ) + +#define VEC_T_NAN FLOAT32_NAN + +#endif + +// FIXME: why are these here? Hardly anyone actually needs them. +struct valve_color24 +{ + byte r, g, b; +}; + +typedef struct valve_color32_s +{ + bool operator!=(const struct valve_color32_s &other) const; + + byte r, g, b, a; +} valve_color32; + +inline bool valve_color32::operator!=(const valve_color32 &other) const +{ + return r != other.r || g != other.g || b != other.b || a != other.a; +} + +struct valve_colorRGBExp32 +{ + byte r, g, b; + signed char exponent; +}; + +struct valve_colorVec +{ + unsigned r, g, b, a; +}; + + +#ifndef UNUSED +#define UNUSED(x) (x = x) // for pesky compiler / lint warnings +#endif + +#ifdef __cplusplus + +struct vrect_t +{ + int x, y, width, height; + vrect_t *pnext; +}; + +#endif + + +//----------------------------------------------------------------------------- +// MaterialRect_t struct - used for DrawDebugText +//----------------------------------------------------------------------------- +struct Rect_t +{ + int x, y; + int width, height; +}; + + +//----------------------------------------------------------------------------- +// Declares a type-safe handle type; you can't assign one handle to the next +//----------------------------------------------------------------------------- + +// 32-bit pointer handles. + +// Typesafe 8-bit and 16-bit handles. +template< class HandleType > +class CBaseIntHandle +{ +public: + + inline bool operator==(const CBaseIntHandle &other) { return m_Handle == other.m_Handle; } + inline bool operator!=(const CBaseIntHandle &other) { return m_Handle != other.m_Handle; } + + // Only the code that doles out these handles should use these functions. + // Everyone else should treat them as a transparent type. + inline HandleType GetHandleValue() { return m_Handle; } + inline void SetHandleValue(HandleType val) { m_Handle = val; } + + typedef HandleType HANDLE_TYPE; + +protected: + + HandleType m_Handle; +}; + +template< class DummyType > +class CIntHandle16 : public CBaseIntHandle < unsigned short > +{ +public: + inline CIntHandle16() {} + + static inline CIntHandle16 MakeHandle(HANDLE_TYPE val) + { + return CIntHandle16(val); + } + +protected: + inline CIntHandle16(HANDLE_TYPE val) + { + m_Handle = val; + } +}; + + +template< class DummyType > +class CIntHandle32 : public CBaseIntHandle < unsigned long > +{ +public: + inline CIntHandle32() {} + + static inline CIntHandle32 MakeHandle(HANDLE_TYPE val) + { + return CIntHandle32(val); + } + +protected: + inline CIntHandle32(HANDLE_TYPE val) + { + m_Handle = val; + } +}; + + +// NOTE: This macro is the same as windows uses; so don't change the guts of it +#define DECLARE_HANDLE_16BIT(name) typedef CIntHandle16< struct name##__handle * > name; +#define DECLARE_HANDLE_32BIT(name) typedef CIntHandle32< struct name##__handle * > name; + +#define DECLARE_POINTER_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name +#define FORWARD_DECLARE_HANDLE(name) typedef struct name##__ *name + +#endif // BASETYPES_H diff --git a/rehlds/public/cl_dll/IGameClientExports.h b/rehlds/public/cl_dll/IGameClientExports.h new file mode 100644 index 0000000..f324878 --- /dev/null +++ b/rehlds/public/cl_dll/IGameClientExports.h @@ -0,0 +1,34 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef IGAMECLIENTEXPORTS_H +#define IGAMECLIENTEXPORTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +//----------------------------------------------------------------------------- +// Purpose: Exports a set of functions for the GameUI interface to interact with the game client +//----------------------------------------------------------------------------- +class IGameClientExports : public IBaseInterface +{ +public: + // returns the name of the server the user is connected to, if any + virtual const char *GetServerHostName() = 0; + + // ingame voice manipulation + virtual bool IsPlayerGameVoiceMuted(int playerIndex) = 0; + virtual void MutePlayerGameVoice(int playerIndex) = 0; + virtual void UnmutePlayerGameVoice(int playerIndex) = 0; +}; + +#define GAMECLIENTEXPORTS_INTERFACE_VERSION "GameClientExports001" + + +#endif // IGAMECLIENTEXPORTS_H diff --git a/rehlds/public/commonmacros.h b/rehlds/public/commonmacros.h new file mode 100644 index 0000000..d6a6aec --- /dev/null +++ b/rehlds/public/commonmacros.h @@ -0,0 +1,30 @@ +#ifndef COMMONMACROS_H +#define COMMONMACROS_H +#pragma once + + +// ------------------------------------------------------- +// +// commonmacros.h +// +// This should contain ONLY general purpose macros that are +// appropriate for use in engine/launcher/all tools +// +// ------------------------------------------------------- + +#include "osconfig.h" +// Makes a 4-byte "packed ID" int out of 4 characters +#define MAKEID(d,c,b,a) ( ((int)(a) << 24) | ((int)(b) << 16) | ((int)(c) << 8) | ((int)(d)) ) + +// Compares a string with a 4-byte packed ID constant +#define STRING_MATCHES_ID( p, id ) ( (*((int *)(p)) == (id) ) ? true : false ) +#define ID_TO_STRING( id, p ) ( (p)[3] = (((id)>>24) & 0xFF), (p)[2] = (((id)>>16) & 0xFF), (p)[1] = (((id)>>8) & 0xFF), (p)[0] = (((id)>>0) & 0xFF) ) + +#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + +// Keeps clutter down a bit, when using a float as a bit-vector +#define SETBITS(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits)) +#define CLEARBITS(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits)) +#define FBitSet(flBitVector, bit) ((flBitVector) & (bit)) + +#endif // COMMONMACROS_H diff --git a/rehlds/public/engine_hlds_api.h b/rehlds/public/engine_hlds_api.h new file mode 100644 index 0000000..ac88496 --- /dev/null +++ b/rehlds/public/engine_hlds_api.h @@ -0,0 +1,47 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + +#include "maintypes.h" +#include "interface.h" + + +/* <8f5d0> ../public/engine_hlds_api.h:11 */ +class IDedicatedServerAPI : public IBaseInterface +{ +public: + + virtual bool Init(char *basedir, char *cmdline, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) = 0; + virtual int Shutdown(void) = 0; + virtual bool RunFrame(void) = 0; + virtual void AddConsoleText(char *text) = 0; + virtual void UpdateStatus(float *fps, int *nActive, int *nMaxPlayers, char *pszMap) = 0; +}; + +#define VENGINE_HLDS_API_VERSION "VENGINE_HLDS_API_VERSION002" diff --git a/rehlds/public/engine_launcher_api.h b/rehlds/public/engine_launcher_api.h new file mode 100644 index 0000000..1a2acad --- /dev/null +++ b/rehlds/public/engine_launcher_api.h @@ -0,0 +1,47 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef ENGINE_LAUNCHER_API_H +#define ENGINE_LAUNCHER_API_H +#ifdef _WIN32 +#pragma once +#endif + +#include "maintypes.h" +#include "interface.h" + + +/* <8f7fd> ../public/engine_launcher_api.h:17 */ +class IEngineAPI : public IBaseInterface +{ +public: + + virtual int Run(void *instance, char *basedir, char *cmdline, char *postRestartCmdLineArgs, CreateInterfaceFn launcherFactory, CreateInterfaceFn filesystemFactory) = 0; +}; + +#endif // ENGINE_LAUNCHER_API_H diff --git a/rehlds/public/idedicatedexports.h b/rehlds/public/idedicatedexports.h new file mode 100644 index 0000000..509cbbd --- /dev/null +++ b/rehlds/public/idedicatedexports.h @@ -0,0 +1,25 @@ +//========= Copyright 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef IDEDICATEDEXPORTS_H +#define IDEDICATEDEXPORTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "interface.h" + +class IDedicatedExports : IBaseInterface +{ +public: + virtual ~IDedicatedExports() { }; + virtual void Sys_Printf(char *text) = 0; +}; + +#define VENGINE_DEDICATEDEXPORTS_API_VERSION "VENGINE_DEDICATEDEXPORTS_API_VERSION001" + +#endif // IDEDICATEDEXPORTS_H diff --git a/rehlds/public/interface.cpp b/rehlds/public/interface.cpp new file mode 100644 index 0000000..bb7a19e --- /dev/null +++ b/rehlds/public/interface.cpp @@ -0,0 +1,263 @@ +#include "precompiled.h" + + +#if !defined ( _WIN32 ) +// Linux doesn't have this function so this emulates its functionality +// +// +void *GetModuleHandle(const char *name) +{ + void *handle; + + if (name == NULL) + { + // hmm, how can this be handled under linux.... + // is it even needed? + return NULL; + } + + if ((handle=dlopen(name, RTLD_NOW)) == NULL) + { + //printf("Error:%s\n",dlerror()); + // couldn't open this file + return NULL; + } + + // read "man dlopen" for details + // in short dlopen() inc a ref count + // so dec the ref count by performing the close + dlclose(handle); + return handle; +} +#endif + +// ------------------------------------------------------------------------------------ // +// InterfaceReg. +// ------------------------------------------------------------------------------------ // +InterfaceReg *InterfaceReg::s_pInterfaceRegs = NULL; + + +InterfaceReg::InterfaceReg( InstantiateInterfaceFn fn, const char *pName ) : m_pName(pName) +{ + m_CreateFn = fn; + m_pNext = s_pInterfaceRegs; + s_pInterfaceRegs = this; +} + + + +// ------------------------------------------------------------------------------------ // +// CreateInterface. +// ------------------------------------------------------------------------------------ // +EXPORT_FUNCTION IBaseInterface *CreateInterface( const char *pName, int *pReturnCode ) +{ + InterfaceReg *pCur; + + for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) + { + if(strcmp(pCur->m_pName, pName) == 0) + { + if ( pReturnCode ) + { + *pReturnCode = IFACE_OK; + } + return pCur->m_CreateFn(); + } + } + + if ( pReturnCode ) + { + *pReturnCode = IFACE_FAILED; + } + return NULL; +} + +#ifdef LINUX +static IBaseInterface *CreateInterfaceLocal( const char *pName, int *pReturnCode ) +{ + InterfaceReg *pCur; + + for(pCur=InterfaceReg::s_pInterfaceRegs; pCur; pCur=pCur->m_pNext) + { + if(strcmp(pCur->m_pName, pName) == 0) + { + if ( pReturnCode ) + { + *pReturnCode = IFACE_OK; + } + return pCur->m_CreateFn(); + } + } + + if ( pReturnCode ) + { + *pReturnCode = IFACE_FAILED; + } + return NULL; +} +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#endif + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to a function, given a module +// Input : pModuleName - module name +// *pName - proc name +//----------------------------------------------------------------------------- +//static hlds_run wants to use this function +void *Sys_GetProcAddress( const char *pModuleName, const char *pName ) +{ + return GetProcAddress( GetModuleHandle(pModuleName), pName ); +} + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to a function, given a module +// Input : pModuleName - module name +// *pName - proc name +//----------------------------------------------------------------------------- +// hlds_run wants to use this function +void *Sys_GetProcAddress( void *pModuleHandle, const char *pName ) +{ +#if defined ( _WIN32 ) + return GetProcAddress( (HINSTANCE)pModuleHandle, pName ); +#else + return GetProcAddress( pModuleHandle, pName ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Loads a DLL/component from disk and returns a handle to it +// Input : *pModuleName - filename of the component +// Output : opaque handle to the module (hides system dependency) +//----------------------------------------------------------------------------- +CSysModule *Sys_LoadModule( const char *pModuleName ) +{ +#if defined ( _WIN32 ) + HMODULE hDLL = LoadLibrary( pModuleName ); +#else + HMODULE hDLL = NULL; + char szAbsoluteModuleName[1024]; + szAbsoluteModuleName[0] = 0; + if ( pModuleName[0] != '/' ) + { + char szCwd[1024]; + char szAbsoluteModuleName[1024]; + + getcwd( szCwd, sizeof( szCwd ) ); + if ( szCwd[ strlen( szCwd ) - 1 ] == '/' ) + szCwd[ strlen( szCwd ) - 1 ] = 0; + + _snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s/%s", szCwd, pModuleName ); + + hDLL = dlopen( szAbsoluteModuleName, RTLD_NOW ); + } + else + { + _snprintf( szAbsoluteModuleName, sizeof(szAbsoluteModuleName), "%s", pModuleName ); + hDLL = dlopen( pModuleName, RTLD_NOW ); + } +#endif + + if( !hDLL ) + { + char str[512]; +#if defined ( _WIN32 ) + _snprintf( str, sizeof(str), "%s.dll", pModuleName ); + hDLL = LoadLibrary( str ); +#elif defined(OSX) + printf("Error:%s\n",dlerror()); + _snprintf( str, sizeof(str), "%s.dylib", szAbsoluteModuleName ); + hDLL = dlopen(str, RTLD_NOW); +#else + printf("Error:%s\n",dlerror()); + _snprintf( str, sizeof(str), "%s.so", szAbsoluteModuleName ); + hDLL = dlopen(str, RTLD_NOW); +#endif + } + + return reinterpret_cast(hDLL); +} + +//----------------------------------------------------------------------------- +// Purpose: Unloads a DLL/component from +// Input : *pModuleName - filename of the component +// Output : opaque handle to the module (hides system dependency) +//----------------------------------------------------------------------------- +void Sys_UnloadModule( CSysModule *pModule ) +{ + if ( !pModule ) + return; + + HMODULE hDLL = reinterpret_cast(pModule); +#if defined ( _WIN32 ) + FreeLibrary( hDLL ); +#else + dlclose((void *)hDLL); +#endif + +} + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to a function, given a module +// Input : module - windows HMODULE from Sys_LoadModule() +// *pName - proc name +// Output : factory for this module +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ) +{ + if ( !pModule ) + return NULL; + + HMODULE hDLL = reinterpret_cast(pModule); +#if defined ( _WIN32 ) + return reinterpret_cast(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME )); +#else +// Linux gives this error: +//../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory +//(CSysModule *)) (const char *, int *)': +//../public/interface.cpp:154: ISO C++ forbids casting between +//pointer-to-function and pointer-to-object +// +// so lets get around it :) + return (CreateInterfaceFn)(GetProcAddress( hDLL, CREATEINTERFACE_PROCNAME )); +#endif +} + + + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of this module +// Output : interface_instance_t +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactoryThis( void ) +{ +#ifdef LINUX + return CreateInterfaceLocal; +#else + return CreateInterface; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: returns the instance of the named module +// Input : *pModuleName - name of the module +// Output : interface_instance_t - instance of that module +//----------------------------------------------------------------------------- +CreateInterfaceFn Sys_GetFactory( const char *pModuleName ) +{ +#if defined ( _WIN32 ) + return static_cast( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) ); +#else +// Linux gives this error: +//../public/interface.cpp: In function `IBaseInterface *(*Sys_GetFactory +//(const char *)) (const char *, int *)': +//../public/interface.cpp:186: invalid static_cast from type `void *' to +//type `IBaseInterface *(*) (const char *, int *)' +// +// so lets use the old style cast. + return (CreateInterfaceFn)( Sys_GetProcAddress( pModuleName, CREATEINTERFACE_PROCNAME ) ); +#endif +} diff --git a/rehlds/public/interface.h b/rehlds/public/interface.h new file mode 100644 index 0000000..980a5af --- /dev/null +++ b/rehlds/public/interface.h @@ -0,0 +1,150 @@ + +// This header defines the interface convention used in the valve engine. +// To make an interface and expose it: +// 1. Derive from IBaseInterface. +// 2. The interface must be ALL pure virtuals, and have no data members. +// 3. Define a name for it. +// 4. In its implementation file, use EXPOSE_INTERFACE or EXPOSE_SINGLE_INTERFACE. + +// Versioning +// There are two versioning cases that are handled by this: +// 1. You add functions to the end of an interface, so it is binary compatible with the previous interface. In this case, +// you need two EXPOSE_INTERFACEs: one to expose your class as the old interface and one to expose it as the new interface. +// 2. You update an interface so it's not compatible anymore (but you still want to be able to expose the old interface +// for legacy code). In this case, you need to make a new version name for your new interface, and make a wrapper interface and +// expose it for the old interface. + +//#if _MSC_VER >= 1300 // VC7 +//#include "tier1/interface.h" +//#else + +#ifndef INTERFACE_H +#define INTERFACE_H + +#if !defined ( _WIN32 ) + +#include // dlopen,dlclose, et al +#include + +#define HMODULE void * +#define GetProcAddress dlsym + +#define _snprintf snprintf + +#endif + +void *Sys_GetProcAddress(const char *pModuleName, const char *pName); +void *Sys_GetProcAddress(void *pModuleHandle, const char *pName); + +// All interfaces derive from this. +class IBaseInterface +{ +public: + + virtual ~IBaseInterface() {} +}; + + +#define CREATEINTERFACE_PROCNAME "CreateInterface" +typedef IBaseInterface* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); + + +typedef IBaseInterface* (*InstantiateInterfaceFn)(); + + +// Used internally to register classes. +class InterfaceReg +{ +public: + InterfaceReg(InstantiateInterfaceFn fn, const char *pName); + +public: + + InstantiateInterfaceFn m_CreateFn; + const char *m_pName; + + InterfaceReg *m_pNext; // For the global list. + static InterfaceReg *s_pInterfaceRegs; +}; + + +// Use this to expose an interface that can have multiple instances. +// e.g.: +// EXPOSE_INTERFACE( CInterfaceImp, IInterface, "MyInterface001" ) +// This will expose a class called CInterfaceImp that implements IInterface (a pure class) +// clients can receive a pointer to this class by calling CreateInterface( "MyInterface001" ) +// +// In practice, the shared header file defines the interface (IInterface) and version name ("MyInterface001") +// so that each component can use these names/vtables to communicate +// +// A single class can support multiple interfaces through multiple inheritance +// +// Use this if you want to write the factory function. +#define EXPOSE_INTERFACE_FN(functionName, interfaceName, versionName) \ + static InterfaceReg __g_Create##className##_reg(functionName, versionName); + +#define EXPOSE_INTERFACE(className, interfaceName, versionName) \ + static IBaseInterface* __Create##className##_interface() {return (interfaceName *)new className;}\ + static InterfaceReg __g_Create##className##_reg(__Create##className##_interface, versionName ); + +// Use this to expose a singleton interface with a global variable you've created. +#define EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, globalVarName) \ + static IBaseInterface* __Create##className##interfaceName##_interface() {return (IBaseInterface *)&globalVarName;}\ + static InterfaceReg __g_Create##className##interfaceName##_reg(__Create##className##interfaceName##_interface, versionName); + +// Use this to expose a singleton interface. This creates the global variable for you automatically. +#define EXPOSE_SINGLE_INTERFACE(className, interfaceName, versionName) \ + static className __g_##className##_singleton;\ + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(className, interfaceName, versionName, __g_##className##_singleton) + + +#ifdef _WIN32 + #define EXPORT_FUNCTION __declspec(dllexport) +#else + #define EXPORT_FUNCTION __attribute__ ((visibility("default"))) +#endif + + +// This function is automatically exported and allows you to access any interfaces exposed with the above macros. +// if pReturnCode is set, it will return one of the following values +// extend this for other error conditions/code +enum +{ + IFACE_OK = 0, + IFACE_FAILED +}; + + +extern "C" +{ + EXPORT_FUNCTION IBaseInterface* CreateInterface(const char *pName, int *pReturnCode); +}; + + +extern CreateInterfaceFn Sys_GetFactoryThis( void ); + + +//----------------------------------------------------------------------------- +// UNDONE: This is obsolete, use the module load/unload/get instead!!! +//----------------------------------------------------------------------------- +extern CreateInterfaceFn Sys_GetFactory( const char *pModuleName ); + + +// load/unload components +class CSysModule; + +//----------------------------------------------------------------------------- +// Load & Unload should be called in exactly one place for each module +// The factory for that module should be passed on to dependent components for +// proper versioning. +//----------------------------------------------------------------------------- +extern CSysModule *Sys_LoadModule( const char *pModuleName ); +extern void Sys_UnloadModule( CSysModule *pModule ); + +extern CreateInterfaceFn Sys_GetFactory( CSysModule *pModule ); + + +#endif +//#endif // MSVC 6.0 + + diff --git a/rehlds/public/iregistry.h b/rehlds/public/iregistry.h new file mode 100644 index 0000000..e17b5b7 --- /dev/null +++ b/rehlds/public/iregistry.h @@ -0,0 +1,40 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( UTIL_REGISTRY_H ) +#define UTIL_REGISTRY_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Interface to registry +//----------------------------------------------------------------------------- +class IRegistry +{ +public: + // Init/shutdown + virtual void Init(void) = 0; + virtual void Shutdown(void) = 0; + + // Read/write integers + virtual int ReadInt(const char *key, int defaultValue = 0) = 0; + virtual void WriteInt(const char *key, int value) = 0; + + // Read/write strings + virtual const char *ReadString(const char *key, const char *defaultValue = NULL) = 0; + virtual void WriteString(const char *key, const char *value) = 0; +}; + + +#ifdef HOOK_ENGINE +#define registry (*pregistry) +#endif // HOOK_ENGINE + +extern IRegistry *registry; + +#endif // UTIL_REGISTRY_H diff --git a/rehlds/public/keydefs.h b/rehlds/public/keydefs.h new file mode 100644 index 0000000..3e335bc --- /dev/null +++ b/rehlds/public/keydefs.h @@ -0,0 +1,124 @@ +// keydefs.h +#ifndef KEYDEFS_H +#define KEYDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +// +// these are the key numbers that should be passed to Key_Event +// +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 + +// normal keys should be passed as lowercased ascii + +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 + +#define K_ALT 132 +#define K_CTRL 133 +#define K_SHIFT 134 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 + +#define K_KP_HOME 160 +#define K_KP_UPARROW 161 +#define K_KP_PGUP 162 +#define K_KP_LEFTARROW 163 +#define K_KP_5 164 +#define K_KP_RIGHTARROW 165 +#define K_KP_END 166 +#define K_KP_DOWNARROW 167 +#define K_KP_PGDN 168 +#define K_KP_ENTER 169 +#define K_KP_INS 170 +#define K_KP_DEL 171 +#define K_KP_SLASH 172 +#define K_KP_MINUS 173 +#define K_KP_PLUS 174 +#define K_CAPSLOCK 175 +#define K_KP_MUL 176 +#define K_WIN 177 + + +// +// joystick buttons +// +#define K_JOY1 203 +#define K_JOY2 204 +#define K_JOY3 205 +#define K_JOY4 206 + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +#define K_AUX1 207 +#define K_AUX2 208 +#define K_AUX3 209 +#define K_AUX4 210 +#define K_AUX5 211 +#define K_AUX6 212 +#define K_AUX7 213 +#define K_AUX8 214 +#define K_AUX9 215 +#define K_AUX10 216 +#define K_AUX11 217 +#define K_AUX12 218 +#define K_AUX13 219 +#define K_AUX14 220 +#define K_AUX15 221 +#define K_AUX16 222 +#define K_AUX17 223 +#define K_AUX18 224 +#define K_AUX19 225 +#define K_AUX20 226 +#define K_AUX21 227 +#define K_AUX22 228 +#define K_AUX23 229 +#define K_AUX24 230 +#define K_AUX25 231 +#define K_AUX26 232 +#define K_AUX27 233 +#define K_AUX28 234 +#define K_AUX29 235 +#define K_AUX30 236 +#define K_AUX31 237 +#define K_AUX32 238 +#define K_MWHEELDOWN 239 +#define K_MWHEELUP 240 + +#define K_PAUSE 255 + +// +// mouse buttons generate virtual keys +// +#define K_MOUSE1 241 +#define K_MOUSE2 242 +#define K_MOUSE3 243 +#define K_MOUSE4 244 +#define K_MOUSE5 245 + +#endif // KEYDEFS_H \ No newline at end of file diff --git a/rehlds/public/particleman.h b/rehlds/public/particleman.h new file mode 100644 index 0000000..ab65b13 --- /dev/null +++ b/rehlds/public/particleman.h @@ -0,0 +1,101 @@ +#ifndef PARTICLEMAN_H +#define PARTICLEMAN_H + +#include "interface.h" +#include "pman_triangleffect.h" + +#define PARTICLEMAN_INTERFACE "create_particleman" + +#ifdef _WIN32 +#define PARTICLEMAN_DLLNAME "cl_dlls/particleman.dll" +#elif defined(OSX) +#define PARTICLEMAN_DLLNAME "cl_dlls/particleman.dylib" +#elif defined(LINUX) +#define PARTICLEMAN_DLLNAME "cl_dlls/particleman.so" +#else +#error +#endif + +class CBaseParticle; + +class IParticleMan : public IBaseInterface +{ + +protected: + virtual ~IParticleMan() {} + +public: + + virtual void SetUp( cl_enginefunc_t *pEnginefuncs ) = 0; + virtual void Update ( void ) = 0; + virtual void SetVariables ( float flGravity, Vector vViewAngles ) = 0; + virtual void ResetParticles ( void ) = 0; + virtual void ApplyForce ( Vector vOrigin, Vector vDirection, float flRadius, float flStrength, float flDuration ) = 0; + virtual void AddCustomParticleClassSize ( unsigned long lSize ) = 0; + + //Use this if you want to create a new particle without any overloaded functions, Think, Touch, etc. + //Just call this function, set the particle's behavior and let it rip. + virtual CBaseParticle *CreateParticle( Vector org, Vector normal, model_s * sprite, float size, float brightness, const char *classname ) = 0; + + //Use this to take a block from the mempool for custom particles ( used in new ). + virtual char *RequestNewMemBlock( int iSize ) = 0; + + //These ones are used along a custom Create for new particles you want to override their behavior. + //You can call these whenever you want, but they are mainly used by CBaseParticle. + virtual void CoreInitializeSprite ( CCoreTriangleEffect *pParticle, Vector org, Vector normal, model_s *sprite, float size, float brightness ) = 0; //Only use this for TrianglePlanes + virtual void CoreThink( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreDraw( CCoreTriangleEffect *pParticle ) = 0; + virtual void CoreAnimate( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreAnimateAndDie( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreExpand ( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreContract ( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreFade ( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreSpin ( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreCalculateVelocity( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreCheckCollision( CCoreTriangleEffect *pParticle, float time ) = 0; + virtual void CoreTouch ( CCoreTriangleEffect *pParticle, Vector pos, Vector normal, int index ) = 0; + virtual void CoreDie ( CCoreTriangleEffect *pParticle ) = 0; + virtual void CoreForce ( CCoreTriangleEffect *pParticle ) = 0; + virtual bool CoreCheckVisibility ( CCoreTriangleEffect *pParticle ) = 0; + virtual void SetRender( int iRender ) = 0; +}; + +extern IParticleMan *g_pParticleMan; + +class CBaseParticle : public CCoreTriangleEffect +{ +public: + virtual void Think( float time ){ g_pParticleMan->CoreThink( this, time ); } + virtual void Draw( void ) { g_pParticleMan->CoreDraw( this ); } + virtual void Animate( float time ) { g_pParticleMan->CoreAnimate( this, time ); } + virtual void AnimateAndDie( float time ) { g_pParticleMan->CoreAnimateAndDie( this, time ); } + virtual void Expand( float time ) { g_pParticleMan->CoreExpand( this, time ); } + virtual void Contract( float time ) { g_pParticleMan->CoreContract( this, time ); } + virtual void Fade( float time ) { g_pParticleMan->CoreFade( this, time ); } + virtual void Spin( float time ) { g_pParticleMan->CoreSpin( this, time ); } + virtual void CalculateVelocity( float time ) { g_pParticleMan->CoreCalculateVelocity( this, time ); } + virtual void CheckCollision( float time ) { g_pParticleMan->CoreCheckCollision( this, time ); } + virtual void Touch(Vector pos, Vector normal, int index) { g_pParticleMan->CoreTouch( this, pos, normal, index ); } + virtual void Die ( void ) { g_pParticleMan->CoreDie( this ); } + virtual void Force ( void ) { g_pParticleMan->CoreForce( this ); } + virtual bool CheckVisibility ( void ) { return g_pParticleMan->CoreCheckVisibility( this ); } + + virtual void InitializeSprite( Vector org, Vector normal, model_s *sprite, float size, float brightness ) + { + g_pParticleMan->CoreInitializeSprite ( this, org, normal, sprite, size, brightness ); + } + + void * operator new( size_t size ) //this asks for a new block of memory from the MiniMem class + { + return( g_pParticleMan->RequestNewMemBlock( size ) ); + } +#ifdef POSIX + void * operator new( size_t size, const std::nothrow_t&) throw() //this asks for a new block of memory from the MiniMem class + { + return( g_pParticleMan->RequestNewMemBlock( size ) ); + } +#endif +}; + + +#endif //PARTICLEMAN_H diff --git a/rehlds/public/pman_particlemem.h b/rehlds/public/pman_particlemem.h new file mode 100644 index 0000000..05f79bc --- /dev/null +++ b/rehlds/public/pman_particlemem.h @@ -0,0 +1,197 @@ +#ifndef PARTICLEMEM_H__ +#define PARTICLEMEM_H__ + +#ifdef _WIN32 +#pragma once +#endif + +#include + +class CCoreTriangleEffect; + +#define TRIANGLE_FPS 30 + +typedef struct visibleparticles_s +{ + CCoreTriangleEffect *pVisibleParticle; +} visibleparticles_t; + +//--------------------------------------------------------------------------- +// Memory block record. +class MemoryBlock +{ +private: + char *m_pData; + //bool m_bBlockIsInUse; +public: + MemoryBlock(long lBlockSize) + : next(NULL), prev(NULL) + //m_bBlockIsInUse(false) // Initialize block to 'free' state. + { + // Allocate memory here. + m_pData = new char[lBlockSize]; + } + + virtual ~MemoryBlock() + { + // Free memory. + delete[] m_pData; + } + + inline char *Memory(void) { return m_pData; } + + MemoryBlock * next; + MemoryBlock * prev; +}; + +class MemList +{ +public: + MemList() : m_pHead(NULL) {} + + ~MemList() { Reset(); } + + void Push(MemoryBlock * newItem) + { + if(!m_pHead) + { + m_pHead = newItem; + newItem->next = NULL; + newItem->prev = NULL; + return; + } + + MemoryBlock * temp = m_pHead; + m_pHead = newItem; + m_pHead->next = temp; + m_pHead->prev = NULL; + + temp->prev = m_pHead; + } + + + MemoryBlock * Front( void ) + { + return(m_pHead); + } + + MemoryBlock * Pop( void ) + { + if(!m_pHead) + return(NULL); + + MemoryBlock * temp = m_pHead; + + m_pHead = m_pHead->next; + + if(m_pHead) + m_pHead->prev = NULL; + + temp->next = NULL; + temp->prev = NULL; + + return(temp); + } + + void Delete( MemoryBlock * pItem) + { + + if(m_pHead == pItem) + { + MemoryBlock * temp = m_pHead; + + m_pHead = m_pHead->next; + if(m_pHead) + m_pHead->prev = NULL; + + temp->next = NULL; + temp->prev = NULL; + return; + } + + MemoryBlock * prev = pItem->prev; + MemoryBlock * next = pItem->next; + + if(prev) + prev->next = next; + + if(next) + next->prev = prev; + + pItem->next = NULL; + pItem->prev = NULL; + } + + void Reset( void ) + { + while(m_pHead) + Delete(m_pHead); + } + +private: + MemoryBlock * m_pHead; +}; + + +// Some helpful typedefs. +typedef std::vector VectorOfMemoryBlocks; +typedef VectorOfMemoryBlocks::iterator MemoryBlockIterator; + +// Mini memory manager - singleton. +class CMiniMem +{ +private: + // Main memory pool. Array is fine, but vectors are + // easier. :) + static VectorOfMemoryBlocks m_vecMemoryPool; + // Size of memory blocks in pool. + static long m_lMemoryBlockSize; + static long m_lMaxBlocks; + static long m_lMemoryPoolSize; + static CMiniMem *_instance; + + int m_iTotalParticles; + int m_iParticlesDrawn; + +protected: + // private constructor and destructor. + CMiniMem(long lMemoryPoolSize, long lMaxBlockSize); + virtual ~CMiniMem(); + + // ------------ Memory pool manager calls. + // Find a free block and mark it as "in use". Return NULL + // if no free blocks found. + char *AllocateFreeBlock(void); +public: + + // Return a pointer to usable block of memory. + char *newBlock(void); + + // Mark a target memory item as no longer "in use". + void deleteBlock(MemoryBlock *p); + + // Return the remaining capacity of the memory pool as a percent. + long PercentUsed(void); + + void ProcessAll( void ); //Processes all + + void Reset( void ); //clears memory, setting all particles to not used. + + static int ApplyForce( Vector vOrigin, Vector vDirection, float flRadius, float flStrength ); + + static CMiniMem *Instance(void); + static long MaxBlockSize(void); + + bool CheckSize( int iSize ); + + int GetTotalParticles( void ) { return m_iTotalParticles; } + int GetDrawnParticles( void ) { return m_iParticlesDrawn; } + void IncreaseParticlesDrawn( void ){ m_iParticlesDrawn++; } + + void Shutdown( void ); + + visibleparticles_t *m_pVisibleParticles; +}; + + +#endif//PARTICLEMEM_H__ \ No newline at end of file diff --git a/rehlds/public/pman_triangleffect.h b/rehlds/public/pman_triangleffect.h new file mode 100644 index 0000000..7ab40da --- /dev/null +++ b/rehlds/public/pman_triangleffect.h @@ -0,0 +1,209 @@ +#ifndef TRIANGLEEFFECT_H__ +#define TRIANGLEEFFECT_H__ + +#ifdef _WIN32 +#pragma once +#endif + +#define TRI_COLLIDEWORLD 0x00000020 +#define TRI_COLLIDEALL 0x00001000 // will collide with world and slideboxes +#define TRI_COLLIDEKILL 0x00004000 // tent is removed upon collision with anything +#define TRI_SPIRAL 0x00008000 +#define TRI_ANIMATEDIE 0x00016000 //animate once and then die +#define TRI_WATERTRACE 0x00032000 + + +#define CULL_FRUSTUM_POINT ( 1 << 0 ) +#define CULL_FRUSTUM_SPHERE ( 1 << 1 ) +#define CULL_FRUSTUM_PLANE ( 1 << 2 ) +#define CULL_PVS ( 1 << 3 ) + +#define LIGHT_NONE ( 1 << 4 ) +#define LIGHT_COLOR ( 1 << 5 ) +#define LIGHT_INTENSITY ( 1 << 6 ) + +#define RENDER_FACEPLAYER ( 1 << 7 ) // m_vAngles == Player view angles +#define RENDER_FACEPLAYER_ROTATEZ ( 1 << 8 ) //Just like above but m_vAngles.z is untouched so the sprite can rotate. + + +#include "pman_particlemem.h" + +//pure virtual baseclass +class CCoreTriangleEffect +{ +private: + int m_iRenderFlags; + float m_flNextPVSCheck; + bool m_bInPVS; + + int m_iCollisionFlags; + float m_flPlayerDistance; //Used for sorting the particles, DO NOT TOUCH. + +public: + + void * operator new(size_t size) + { + // Requested size should match size of class. + if ( size != sizeof( CCoreTriangleEffect ) ) +#ifdef _WIN32 + throw "Error in requested size of new particle class instance."; +#else + return NULL; +#endif + + return((CCoreTriangleEffect *) CMiniMem::Instance()->newBlock()); + + }//this asks for a new block of memory from the MiniMen class + + virtual void Think( float time ) = 0; + virtual bool CheckVisibility ( void ) = 0; + virtual void Draw( void ) = 0; + virtual void Animate( float time ) = 0; + virtual void AnimateAndDie( float time ) = 0; + virtual void Expand( float time ) = 0; + virtual void Contract( float time ) = 0; + virtual void Fade( float time ) = 0; + virtual void Spin( float time ) = 0; + virtual void CalculateVelocity( float time ) = 0; + virtual void CheckCollision( float time ) = 0; + virtual void Touch(Vector pos, Vector normal, int index) = 0; + virtual void Die ( void ) = 0; + virtual void InitializeSprite( Vector org, Vector normal, model_s * sprite, float size, float brightness ) = 0; + virtual void Force ( void ) = 0; + + float m_flSize; //scale of object + float m_flScaleSpeed; //speed at which object expands + float m_flContractSpeed; //speed at which object expands + + float m_flStretchX; + float m_flStretchY; + + float m_flBrightness; //transparency of object + float m_flFadeSpeed; //speed at which object fades + + float m_flTimeCreated; //time object was instanced + float m_flDieTime; //time to remove an object + + float m_flGravity; //how effected by gravity is this object + float m_flAfterDampGrav; + float m_flDampingVelocity; + float m_flDampingTime; + + int m_iFramerate; + int m_iNumFrames; + int m_iFrame; + int m_iRendermode; + + Vector m_vOrigin; //object's position + Vector m_vAngles; //normal angles of object + + Vector m_vAVelocity; + + Vector m_vVelocity; + + Vector m_vLowLeft; + Vector m_vLowRight; + Vector m_vTopLeft; + + Vector m_vColor; + float m_flMass; + + model_s * m_pTexture; + + float m_flBounceFactor; + + char m_szClassname[32]; + + bool m_bInWater; + bool m_bAffectedByForce; + + int m_iAfterDampFlags; + + void SetLightFlag ( int iFlag ) + { + m_iRenderFlags &= ~( LIGHT_NONE | LIGHT_INTENSITY | LIGHT_COLOR ); + m_iRenderFlags |= iFlag; + } + + void SetCullFlag( int iFlag ) + { + m_iRenderFlags &= ~( CULL_PVS | CULL_FRUSTUM_POINT | CULL_FRUSTUM_PLANE | CULL_FRUSTUM_SPHERE ); + m_iRenderFlags |= iFlag; + } + + int GetRenderFlags( void ) + { + return m_iRenderFlags; + } + + bool GetParticlePVS ( void ) + { + return m_bInPVS; + } + + void SetParticlePVS ( bool bPVSStat ) + { + m_bInPVS = bPVSStat; + } + + float GetNextPVSCheck( void ) + { + return m_flNextPVSCheck; + } + + void SetNextPVSCheck( float flTime ) + { + m_flNextPVSCheck = flTime; + } + + void SetCollisionFlags ( int iFlag ) + { + m_iCollisionFlags |= iFlag; + } + + void ClearCollisionFlags ( int iFlag ) + { + m_iCollisionFlags &= ~iFlag; + } + + int GetCollisionFlags ( void ) + { + return m_iCollisionFlags; + } + + void SetRenderFlag( int iFlag ) + { + m_iRenderFlags |= iFlag; + } + + float GetPlayerDistance ( void ) { return m_flPlayerDistance; } + void SetPlayerDistance ( float flDistance ) { m_flPlayerDistance = flDistance; } + +protected: + float m_flOriginalSize; + Vector m_vOriginalAngles; + float m_flOriginalBrightness; + Vector m_vPrevOrigin; + + float m_flNextCollisionTime; + +protected: + static bool CheckSize(int size) + { + // This check will help prevent a class frome being defined later, + // that is larger than the max size MemoryPool is expecting, + // from being successfully allocated. + if (size > (unsigned long) CMiniMem::Instance()->MaxBlockSize()) + { +#ifdef _WIN32 + throw "New particle class is larger than memory pool max size, update lMaxParticleClassSize() function."; +#endif + return(false); + } + + return(true); + } +}; + + +#endif//TRIANGLEEFFECT_H__ diff --git a/rehlds/public/protected_things.h b/rehlds/public/protected_things.h new file mode 100644 index 0000000..ab10bbb --- /dev/null +++ b/rehlds/public/protected_things.h @@ -0,0 +1,187 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef PROTECTED_THINGS_H +#define PROTECTED_THINGS_H +#ifdef _WIN32 +#pragma once +#endif + + +// This header tries to prevent people from using potentially dangerous functions +// (like the notorious non-null-terminating strncpy) and functions that will break +// VCR mode (like time, input, registry, etc). +// +// This header should be included by ALL of our source code. + +// Eventually, ALL of these should be protected, but one man can only accomplish so much in +// one day AND work on features too! +#if defined( PROTECT_STRING_FUNCTIONS ) +#if defined( strncpy ) +#undef strncpy +#endif +#define strncpy strncpy__HEY_YOU__USE_VSTDLIB + + +#if defined( _snprintf ) +#undef _snprintf +#endif +#define _snprintf snprintf__HEY_YOU__USE_VSTDLIB + + +#if defined( sprintf ) +#undef sprintf +#endif +#define sprintf sprintf__HEY_YOU__USE_VSTDLIB + + +#if defined( _vsnprintf ) +#undef _vsnprintf +#endif +#define _vsnprintf vsnprintf__HEY_YOU__USE_VSTDLIB + + +#if defined( strcat ) +#undef strcat +#endif +#define strcat strcat__HEY_YOU__USE_VSTDLIB +#endif + + +#if defined( PROTECT_FILEIO_FUNCTIONS ) +#if defined( fopen ) +#undef fopen +#endif +#define fopen fopen_USE_FILESYSTEM_INSTEAD +#endif + + +#if defined( PROTECTED_THINGS_ENABLE ) + +#if defined( GetTickCount ) +#undef GetTickCount +#endif +#define GetTickCount GetTickCount__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( timeGetTime ) +#undef timeGetTime +#endif +#define timeGetTime timeGetTime__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( clock ) +#undef clock +#endif +#define time time__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( recvfrom ) +#undef recvfrom +#endif +#define recvfrom recvfrom__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetCursorPos ) +#undef GetCursorPos +#endif +#define GetCursorPos GetCursorPos__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( ScreenToClient ) +#undef ScreenToClient +#endif +#define ScreenToClient ScreenToClient__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetCommandLine ) +#undef GetCommandLine +#endif +#define GetCommandLine GetCommandLine__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegOpenKeyEx ) +#undef RegOpenKeyEx +#endif +#define RegOpenKeyEx RegOpenKeyEx__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegOpenKey ) +#undef RegOpenKey +#endif +#define RegOpenKey RegOpenKey__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegSetValueEx ) +#undef RegSetValueEx +#endif +#define RegSetValueEx RegSetValueEx__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegSetValue ) +#undef RegSetValue +#endif +#define RegSetValue RegSetValue__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegQueryValueEx ) +#undef RegQueryValueEx +#endif +#define RegQueryValueEx RegQueryValueEx__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegQueryValue ) +#undef RegQueryValue +#endif +#define RegQueryValue RegQueryValue__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegCreateKeyEx ) +#undef RegCreateKeyEx +#endif +#define RegCreateKeyEx RegCreateKeyEx__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegCreateKey ) +#undef RegCreateKey +#endif +#define RegCreateKey RegCreateKey__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( RegCloseKey ) +#undef RegCloseKey +#endif +#define RegCloseKey RegCloseKey__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetNumberOfConsoleInputEvents ) +#undef GetNumberOfConsoleInputEvents +#endif +#define GetNumberOfConsoleInputEvents GetNumberOfConsoleInputEvents__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( ReadConsoleInput ) +#undef ReadConsoleInput +#endif +#define ReadConsoleInput ReadConsoleInput__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetAsyncKeyState ) +#undef GetAsyncKeyState +#endif +#define GetAsyncKeyState GetAsyncKeyState__HEY_YOU__USE_PLATFORM_LIB + + +#if defined( GetKeyState ) +#undef GetKeyState +#endif +#define GetKeyState GetKeyState__HEY_YOU__USE_PLATFORM_LIB + +#endif + + +#endif // PROTECTED_THINGS_H diff --git a/rehlds/public/registry.cpp b/rehlds/public/registry.cpp new file mode 100644 index 0000000..5b1f4d2 --- /dev/null +++ b/rehlds/public/registry.cpp @@ -0,0 +1,264 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "precompiled.h" + +#ifndef _WIN32 +typedef int HKEY; +#endif + +//----------------------------------------------------------------------------- +// Purpose: Exposes registry interface to rest of launcher +//----------------------------------------------------------------------------- +class CRegistry : public IRegistry +{ +public: + CRegistry(void); + virtual ~CRegistry(void); + + void Init(void); + void Shutdown(void); + + int ReadInt(const char *key, int defaultValue = 0); + void WriteInt(const char *key, int value); + + const char *ReadString(const char *key, const char *defaultValue = NULL); + void WriteString(const char *key, const char *value); + +private: + bool m_bValid; + HKEY m_hKey; +}; + +// Expose to launcher +#ifndef HOOK_ENGINE + +static CRegistry g_Registry; +IRegistry *registry = (IRegistry *)&g_Registry; + +#else + +IRegistry *registry; + +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CRegistry::CRegistry(void) +{ + // Assume failure + m_bValid = false; + m_hKey = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CRegistry::~CRegistry(void) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Read integer from registry +// Input : *key - +// defaultValue - +// Output : int +//----------------------------------------------------------------------------- +int CRegistry::ReadInt(const char *key, int defaultValue /*= 0*/) +{ +#ifdef _WIN32 + LONG lResult; // Registry function result code + DWORD dwType; // Type of key + DWORD dwSize; // Size of element data + + int value; + + if (!m_bValid) + { + return defaultValue; + } + + dwSize = sizeof(DWORD); + + lResult = RegQueryValueEx( + m_hKey, // handle to key + key, // value name + 0, // reserved + &dwType, // type buffer + (LPBYTE)&value, // data buffer + &dwSize); // size of data buffer + + if (lResult != ERROR_SUCCESS) // Failure + return defaultValue; + + if (dwType != REG_DWORD) + return defaultValue; + + return value; +#else + return defaultValue; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Save integer to registry +// Input : *key - +// value - +//----------------------------------------------------------------------------- +void CRegistry::WriteInt(const char *key, int value) +{ +#ifdef _WIN32 + // Size of element data + DWORD dwSize; + + if (!m_bValid) + { + return; + } + + dwSize = sizeof(DWORD); + + RegSetValueEx( + m_hKey, // handle to key + key, // value name + 0, // reserved + REG_DWORD, // type buffer + (LPBYTE)&value, // data buffer + dwSize); // size of data buffer +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Read string value from registry +// Input : *key - +// *defaultValue - +// Output : const char +//----------------------------------------------------------------------------- +const char *CRegistry::ReadString(const char *key, const char *defaultValue /* = NULL */) +{ +#ifdef _WIN32 + LONG lResult; + // Type of key + DWORD dwType; + // Size of element data + DWORD dwSize = 512; + + static char value[512]; + + value[0] = 0; + + if (!m_bValid) + { + return defaultValue; + } + + lResult = RegQueryValueEx( + m_hKey, // handle to key + key, // value name + 0, // reserved + &dwType, // type buffer + (unsigned char *)value, // data buffer + &dwSize); // size of data buffer + + if (lResult != ERROR_SUCCESS) + { + return defaultValue; + } + + if (dwType != REG_SZ) + { + return defaultValue; + } + + return value; +#else + return defaultValue; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Save string to registry +// Input : *key - +// *value - +//----------------------------------------------------------------------------- +void CRegistry::WriteString(const char *key, const char *value) +{ +#ifdef _WIN32 + DWORD dwSize; // Size of element data + + if (!m_bValid) + { + return; + } + + dwSize = strlen(value) + 1; + + RegSetValueEx( + m_hKey, // handle to key + key, // value name + 0, // reserved + REG_SZ, // type buffer + (LPBYTE)value, // data buffer + dwSize); // size of data buffer +#endif +} + +// FIXME: SHould be "steam" +static char *GetPlatformName(void) +{ + return "Half-Life"; +} + +//----------------------------------------------------------------------------- +// Purpose: Open default launcher key based on game directory +//----------------------------------------------------------------------------- +void CRegistry::Init(void) +{ +#ifdef _WIN32 + LONG lResult; // Registry function result code + DWORD dwDisposition; // Type of key opening event + + char szModelKey[1024]; + wsprintf(szModelKey, "Software\\Valve\\%s\\Settings\\", GetPlatformName()); + + lResult = RegCreateKeyEx( + HKEY_CURRENT_USER, // handle of open key + szModelKey, // address of name of subkey to open + 0, // DWORD ulOptions, // reserved + NULL, // Type of value + REG_OPTION_NON_VOLATILE, // Store permanently in reg. + KEY_ALL_ACCESS, // REGSAM samDesired, // security access mask + NULL, + &m_hKey, // Key we are creating + &dwDisposition); // Type of creation + + if (lResult != ERROR_SUCCESS) + { + m_bValid = false; + return; + } + + // Success + m_bValid = true; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CRegistry::Shutdown(void) +{ +#ifdef _WIN32 + if (!m_bValid) + return; + + // Make invalid + m_bValid = false; + RegCloseKey(m_hKey); +#endif +} diff --git a/rehlds/public/rehlds/FlightRecorder.h b/rehlds/public/rehlds/FlightRecorder.h new file mode 100644 index 0000000..a5852e7 --- /dev/null +++ b/rehlds/public/rehlds/FlightRecorder.h @@ -0,0 +1,61 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "osconfig.h" + +class IRehldsFlightRecorder +{ +public: + virtual ~IRehldsFlightRecorder() { } + + virtual uint16_t RegisterMessage(const char* module, const char *message, unsigned int version, bool inOut) = 0; + + virtual void StartMessage(uint16_t msg, bool entrance) = 0; + virtual void EndMessage(uint16_t msg, bool entrance) = 0; + + virtual void WriteInt8(int8_t v) = 0; + virtual void WriteUInt8(uint8_t v) = 0; + + virtual void WriteInt16(int16_t v) = 0; + virtual void WriteUInt16(uint16_t v) = 0; + + virtual void WriteInt32(int32_t v) = 0; + virtual void WriteUInt32(uint32_t v) = 0; + + virtual void WriteInt64(int64_t v) = 0; + virtual void WriteUInt64(uint64_t v) = 0; + + virtual void WriteFloat(float v) = 0; + virtual void WriteDouble(double v) = 0; + + virtual void WriteString(const char* s) = 0; + + virtual void WriteBuffer(const void* data ,unsigned int len) = 0; + +}; diff --git a/rehlds/public/rehlds/Sequence.h b/rehlds/public/rehlds/Sequence.h new file mode 100644 index 0000000..a321b84 --- /dev/null +++ b/rehlds/public/rehlds/Sequence.h @@ -0,0 +1,201 @@ +//--------------------------------------------------------------------------- +// +// S c r i p t e d S e q u e n c e s +// +//--------------------------------------------------------------------------- +#ifndef _INCLUDE_SEQUENCE_H_ +#define _INCLUDE_SEQUENCE_H_ + + +#ifndef _DEF_BYTE_ +typedef unsigned char byte; +#endif + +//--------------------------------------------------------------------------- +// client_textmessage_t +//--------------------------------------------------------------------------- +typedef struct client_textmessage_s +{ + int effect; + byte r1, g1, b1, a1; // 2 colors for effects + byte r2, g2, b2, a2; + float x; + float y; + float fadein; + float fadeout; + float holdtime; + float fxtime; + const char *pName; + const char *pMessage; +} client_textmessage_t; + + +//-------------------------------------------------------------------------- +// sequenceDefaultBits_e +// +// Enumerated list of possible modifiers for a command. This enumeration +// is used in a bitarray controlling what modifiers are specified for a command. +//--------------------------------------------------------------------------- +enum sequenceModifierBits +{ + SEQUENCE_MODIFIER_EFFECT_BIT = (1 << 1), + SEQUENCE_MODIFIER_POSITION_BIT = (1 << 2), + SEQUENCE_MODIFIER_COLOR_BIT = (1 << 3), + SEQUENCE_MODIFIER_COLOR2_BIT = (1 << 4), + SEQUENCE_MODIFIER_FADEIN_BIT = (1 << 5), + SEQUENCE_MODIFIER_FADEOUT_BIT = (1 << 6), + SEQUENCE_MODIFIER_HOLDTIME_BIT = (1 << 7), + SEQUENCE_MODIFIER_FXTIME_BIT = (1 << 8), + SEQUENCE_MODIFIER_SPEAKER_BIT = (1 << 9), + SEQUENCE_MODIFIER_LISTENER_BIT = (1 << 10), + SEQUENCE_MODIFIER_TEXTCHANNEL_BIT = (1 << 11), +}; +typedef enum sequenceModifierBits sequenceModifierBits_e ; + + +//--------------------------------------------------------------------------- +// sequenceCommandEnum_e +// +// Enumerated sequence command types. +//--------------------------------------------------------------------------- +enum sequenceCommandEnum_ +{ + SEQUENCE_COMMAND_ERROR = -1, + SEQUENCE_COMMAND_PAUSE = 0, + SEQUENCE_COMMAND_FIRETARGETS, + SEQUENCE_COMMAND_KILLTARGETS, + SEQUENCE_COMMAND_TEXT, + SEQUENCE_COMMAND_SOUND, + SEQUENCE_COMMAND_GOSUB, + SEQUENCE_COMMAND_SENTENCE, + SEQUENCE_COMMAND_REPEAT, + SEQUENCE_COMMAND_SETDEFAULTS, + SEQUENCE_COMMAND_MODIFIER, + SEQUENCE_COMMAND_POSTMODIFIER, + SEQUENCE_COMMAND_NOOP, + + SEQUENCE_MODIFIER_EFFECT, + SEQUENCE_MODIFIER_POSITION, + SEQUENCE_MODIFIER_COLOR, + SEQUENCE_MODIFIER_COLOR2, + SEQUENCE_MODIFIER_FADEIN, + SEQUENCE_MODIFIER_FADEOUT, + SEQUENCE_MODIFIER_HOLDTIME, + SEQUENCE_MODIFIER_FXTIME, + SEQUENCE_MODIFIER_SPEAKER, + SEQUENCE_MODIFIER_LISTENER, + SEQUENCE_MODIFIER_TEXTCHANNEL, +}; +typedef enum sequenceCommandEnum_ sequenceCommandEnum_e; + + +//--------------------------------------------------------------------------- +// sequenceCommandType_e +// +// Typeerated sequence command types. +//--------------------------------------------------------------------------- +enum sequenceCommandType_ +{ + SEQUENCE_TYPE_COMMAND, + SEQUENCE_TYPE_MODIFIER, +}; +typedef enum sequenceCommandType_ sequenceCommandType_e; + + +//--------------------------------------------------------------------------- +// sequenceCommandMapping_s +// +// A mapping of a command enumerated-value to its name. +//--------------------------------------------------------------------------- +typedef struct sequenceCommandMapping_ sequenceCommandMapping_s; +struct sequenceCommandMapping_ +{ + sequenceCommandEnum_e commandEnum; + const char* commandName; + sequenceCommandType_e commandType; +}; + + +//--------------------------------------------------------------------------- +// sequenceCommandLine_s +// +// Structure representing a single command (usually 1 line) from a +// .SEQ file entry. +//--------------------------------------------------------------------------- +typedef struct sequenceCommandLine_ sequenceCommandLine_s; +struct sequenceCommandLine_ +{ + int commandType; // Specifies the type of command + client_textmessage_t clientMessage; // Text HUD message struct + char* speakerName; // Targetname of speaking entity + char* listenerName; // Targetname of entity being spoken to + char* soundFileName; // Name of sound file to play + char* sentenceName; // Name of sentences.txt to play + char* fireTargetNames; // List of targetnames to fire + char* killTargetNames; // List of targetnames to remove + float delay; // Seconds 'till next command + int repeatCount; // If nonzero, reset execution pointer to top of block (N times, -1 = infinite) + int textChannel; // Display channel on which text message is sent + int modifierBitField; // Bit field to specify what clientmessage fields are valid + sequenceCommandLine_s* nextCommandLine; // Next command (linked list) +}; + + +//--------------------------------------------------------------------------- +// sequenceEntry_s +// +// Structure representing a single command (usually 1 line) from a +// .SEQ file entry. +//--------------------------------------------------------------------------- +typedef struct sequenceEntry_ sequenceEntry_s; +struct sequenceEntry_ +{ + char* fileName; // Name of sequence file without .SEQ extension + char* entryName; // Name of entry label in file + sequenceCommandLine_s* firstCommand; // Linked list of commands in entry + sequenceEntry_s* nextEntry; // Next loaded entry + qboolean isGlobal; // Is entry retained over level transitions? +}; + + + +//--------------------------------------------------------------------------- +// sentenceEntry_s +// Structure representing a single sentence of a group from a .SEQ +// file entry. Sentences are identical to entries in sentences.txt, but +// can be unique per level and are loaded/unloaded with the level. +//--------------------------------------------------------------------------- +typedef struct sentenceEntry_ sentenceEntry_s; +struct sentenceEntry_ +{ + char* data; // sentence data (ie "We have hostiles" ) + sentenceEntry_s* nextEntry; // Next loaded entry + qboolean isGlobal; // Is entry retained over level transitions? + unsigned int index; // this entry's position in the file. +}; + +//-------------------------------------------------------------------------- +// sentenceGroupEntry_s +// Structure representing a group of sentences found in a .SEQ file. +// A sentence group is defined by all sentences with the same name, ignoring +// the number at the end of the sentence name. Groups enable a sentence +// to be picked at random across a group. +//-------------------------------------------------------------------------- +typedef struct sentenceGroupEntry_ sentenceGroupEntry_s; +struct sentenceGroupEntry_ +{ + char* groupName; // name of the group (ie CT_ALERT ) + unsigned int numSentences; // number of sentences in group + sentenceEntry_s* firstSentence; // head of linked list of sentences in group + sentenceGroupEntry_s* nextEntry; // next loaded group +}; + +//--------------------------------------------------------------------------- +// Function declarations +//--------------------------------------------------------------------------- +sequenceEntry_s* SequenceGet( const char* fileName, const char* entryName ); +void Sequence_ParseFile( const char* fileName, qboolean isGlobal ); +void Sequence_OnLevelLoad( const char* mapName ); +sentenceEntry_s* SequencePickSentence( const char *groupName, int pickMethod, int *picked ); + +#endif /* _INCLUDE_SEQUENCE_H_ */ diff --git a/rehlds/public/rehlds/archtypes.h b/rehlds/public/rehlds/archtypes.h new file mode 100644 index 0000000..7e6210b --- /dev/null +++ b/rehlds/public/rehlds/archtypes.h @@ -0,0 +1,63 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/#ifndef ARCHTYPES_H +#define ARCHTYPES_H + +#ifdef __x86_64__ +#define X64BITS +#endif + +#if defined( _WIN32 ) && (! defined( __MINGW32__ )) + +typedef __int16 int16; +typedef unsigned __int16 uint16; +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; +typedef __int32 intp; // intp is an integer that can accomodate a pointer +typedef unsigned __int32 uintp; // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) + +#else /* _WIN32 */ + +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; +#ifdef X64BITS +typedef long long intp; +typedef unsigned long long uintp; +#else +typedef int intp; +typedef unsigned int uintp; +#endif + +#endif /* else _WIN32 */ + +#endif /* ARCHTYPES_H */ diff --git a/rehlds/public/rehlds/bspfile.h b/rehlds/public/rehlds/bspfile.h new file mode 100644 index 0000000..72fe722 --- /dev/null +++ b/rehlds/public/rehlds/bspfile.h @@ -0,0 +1,169 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#define BSPVERSION 30 +#define MAX_MAP_HULLS 4 + +#define CONTENTS_ORIGIN -7 // removed at csg time +#define CONTENTS_CLIP -8 // changed to contents_solid +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 + +#define CONTENTS_TRANSLUCENT -15 + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 +#define LUMP_VERTEXES 3 +#define LUMP_VISIBILITY 4 +#define LUMP_NODES 5 +#define LUMP_TEXINFO 6 +#define LUMP_FACES 7 +#define LUMP_LIGHTING 8 +#define LUMP_CLIPNODES 9 +#define LUMP_LEAFS 10 +#define LUMP_MARKSURFACES 11 +#define LUMP_EDGES 12 +#define LUMP_SURFEDGES 13 +#define LUMP_MODELS 14 + +#define HEADER_LUMPS 15 + +/* ../engine/bspfile.h:41 */ +typedef struct lump_s +{ + int fileofs; + int filelen; +} lump_t; + +/* ../engine/bspfile.h:64 */ +typedef struct dmodel_s +{ + float mins[3], maxs[3]; + float origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} dmodel_t; + +/* ../engine/bspfile.h:73 */ +typedef struct dheader_s +{ + int version; + lump_t lumps[15]; +} dheader_t; + +/* <485b2> ../engine/bspfile.h:79 */ +typedef struct dmiptexlump_s +{ + int _nummiptex; + int dataofs[4]; +} dmiptexlump_t; + +/* <1ce18> ../engine/bspfile.h:86 */ +typedef struct miptex_s +{ + char name[16]; + unsigned width; + unsigned height; + unsigned offsets[4]; +} miptex_t; + +/* <48652> ../engine/bspfile.h:94 */ +typedef struct dvertex_s +{ + float point[3]; +} dvertex_t; + +/* <48674> ../engine/bspfile.h:110 */ +typedef struct dplane_s +{ + float normal[3]; + float dist; + int type; +} dplane_t; + +/* <486b2> ../engine/bspfile.h:132 */ +typedef struct dnode_s +{ + int planenum; + short children[2]; + short mins[3]; + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; +} dnode_t; + +/* ../engine/bspfile.h:142 */ +typedef struct dclipnode_s +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + +/* <4876a> ../engine/bspfile.h:149 */ +typedef struct texinfo_s +{ + float vecs[2][4]; + int _miptex; + int flags; +} texinfo_t; + +/* <487c2> ../engine/bspfile.h:159 */ +typedef struct dedge_s +{ + unsigned short v[2]; +} dedge_t; + +/* <487f2> ../engine/bspfile.h:165 */ +typedef struct dface_s +{ + short planenum; + short side; + int firstedge; + short numedges; + short texinfo; + byte styles[4]; + int lightofs; +} dface_t; + +typedef struct dleaf_s +{ + int contents; + int visofs; + short mins[3]; + short maxs[3]; + unsigned short firstmarksurface; + unsigned short nummarksurfaces; + byte ambient_level[4]; +} dleaf_t; diff --git a/rehlds/public/rehlds/cmd_rehlds.h b/rehlds/public/rehlds/cmd_rehlds.h new file mode 100644 index 0000000..abab94a --- /dev/null +++ b/rehlds/public/rehlds/cmd_rehlds.h @@ -0,0 +1,53 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "maintypes.h" + +/* <8f1> ../engine/cmd.h:65 */ +typedef void(*xcommand_t)(void); + +/* <904> ../engine/cmd.h:71 */ +typedef struct cmd_function_s +{ + struct cmd_function_s *next; + char *name; + xcommand_t function; + int flags; +} cmd_function_t; + +/* <95a> ../engine/cmd.h:80 */ +typedef enum cmd_source_s +{ + src_client = 0, // came in over a net connection as a clc_stringcmd. host_client will be valid during this state. + src_command = 1, // from the command buffer. +} cmd_source_t; + +#define FCMD_HUD_COMMAND BIT(0) +#define FCMD_GAME_COMMAND BIT(1) +#define FCMD_WRAPPER_COMMAND BIT(2) diff --git a/rehlds/public/rehlds/common_rehlds.h b/rehlds/public/rehlds/common_rehlds.h new file mode 100644 index 0000000..52dce23 --- /dev/null +++ b/rehlds/public/rehlds/common_rehlds.h @@ -0,0 +1,76 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "maintypes.h" + +#define COM_TOKEN_LEN 1024 + +// Don't allow overflow +#define SIZEBUF_CHECK_OVERFLOW 0 +#define SIZEBUF_ALLOW_OVERFLOW BIT(0) +#define SIZEBUF_OVERFLOWED BIT(1) + +#define MAX_NUM_ARGVS 50 +#define NUM_SAFE_ARGVS 7 + +#define COM_COPY_CHUNK_SIZE 1024 +#define COM_MAX_CMD_LINE 256 + +/* <6ae> ../common/common.h:82 */ +typedef struct sizebuf_s +{ + const char *buffername; + uint16_t flags; + byte *data; + int maxsize; + int cursize; +} sizebuf_t; + +/* <270aa> ../common/common.h:297 */ +typedef struct downloadtime_s +{ + qboolean bUsed; + float fTime; + int nBytesRemaining; +} downloadtime_t; + +/* <19fa2> ../common/common.h:303 */ +typedef struct incomingtransfer_s +{ + qboolean doneregistering; + int percent; + qboolean downloadrequested; + downloadtime_t rgStats[8]; + int nCurStat; + int nTotalSize; + int nTotalToTransfer; + int nRemainingToTransfer; + float fLastStatusUpdate; + qboolean custom; +} incomingtransfer_t; diff --git a/rehlds/public/rehlds/crc32.cpp b/rehlds/public/rehlds/crc32.cpp new file mode 100644 index 0000000..d3840d3 --- /dev/null +++ b/rehlds/public/rehlds/crc32.cpp @@ -0,0 +1,132 @@ +/* The implementation here was originally done by Gary S. Brown. I have + borrowed the tables directly, and made some minor changes to the + crc32-function (including changing the interface). //ylo */ + + /* ============================================================= */ + /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ + /* code or tables extracted from it, as desired without restriction. */ + /* */ + /* First, the polynomial itself and its table of feedback terms. The */ + /* polynomial is */ + /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ + /* */ + /* Note that we take it "backwards" and put the highest-order term in */ + /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ + /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ + /* the MSB being 1. */ + /* */ + /* Note that the usual hardware shift register implementation, which */ + /* is what we're using (we're merely optimizing it by doing eight-bit */ + /* chunks at a time) shifts bits into the lowest-order term. In our */ + /* implementation, that means shifting towards the right. Why do we */ + /* do it this way? Because the calculated CRC must be transmitted in */ + /* order from highest-order term to lowest-order term. UARTs transmit */ + /* characters in order from LSB to MSB. By storing the CRC this way, */ + /* we hand it to the UART in the order low-byte to high-byte; the UART */ + /* sends each low-bit to hight-bit; and the result is transmission bit */ + /* by bit from highest- to lowest-order term without requiring any bit */ + /* shuffling on our part. Reception works similarly. */ + /* */ + /* The feedback terms table consists of 256, 32-bit entries. Notes: */ + /* */ + /* The table can be generated at runtime if desired; code to do so */ + /* is shown later. It might not be obvious, but the feedback */ + /* terms simply represent the results of eight shift/xor opera- */ + /* tions for all combinations of data and CRC register values. */ + /* */ + /* The values must be right-shifted by eight bits by the "updcrc" */ + /* logic; the shift must be unsigned (bring in zeroes). On some */ + /* hardware you could probably optimize the shift in assembler by */ + /* using byte-swap instructions. */ + /* polynomial $edb88320 */ + /* */ + /* -------------------------------------------------------------------- */ +#include "precompiled.h" + +static uint32_t crc32_tab[] = { + + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL + }; + + +uint32_t NOINLINE crc32_t_nosse(uint32_t iCRC, const uint8_t *s, unsigned int len) { + uint32_t crc32val = iCRC; + for (unsigned int i = 0; i < len; i++) { + crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8); + } + return crc32val; +} + +uint32_t crc32_t(uint32_t iCRC, const uint8_t *s, unsigned int len) { + if (!g_HasSSE42) { + return crc32_t_nosse(iCRC, s, len); + } + + uint32_t crc32val = iCRC; + unsigned int i = 0; + + for (; i < (len >> 2); i += 4) { + crc32val = _mm_crc32_u32(crc32val, *(uint32_t*)&s[i]); + } + + for (; i < len; i++) { + crc32val = _mm_crc32_u8(crc32val, s[i]); + } + + return crc32val; +} + +uint32_t crc32(const uint8_t *buf, unsigned int len) { + return crc32_t(0, buf, len); +} diff --git a/rehlds/public/rehlds/crc32.h b/rehlds/public/rehlds/crc32.h new file mode 100644 index 0000000..58abf4d --- /dev/null +++ b/rehlds/public/rehlds/crc32.h @@ -0,0 +1,21 @@ +/* + * $Id: crc32.h,v 1.1.1.1 1996/02/18 21:38:11 ylo Exp $ + * $Log: crc32.h,v $ + * Revision 1.1.1.1 1996/02/18 21:38:11 ylo + * Imported ssh-1.2.13. + * + * Revision 1.2 1995/07/13 01:21:45 ylo + * Removed "Last modified" header. + * Added cvs log. + * + * $Endlog$ + */ + +#pragma once +#include "osconfig.h" +/* This computes a 32 bit CRC of the data in the buffer, and returns the + CRC. The polynomial used is 0xedb88320. */ + +uint32_t crc32(const uint8_t *buf, unsigned int len); +uint32_t crc32_t(uint32_t iCRC, const uint8_t *s, unsigned int len); + diff --git a/rehlds/public/rehlds/custom.h b/rehlds/public/rehlds/custom.h new file mode 100644 index 0000000..4ecca95 --- /dev/null +++ b/rehlds/public/rehlds/custom.h @@ -0,0 +1,92 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Customization.h +#pragma once + +#include "const.h" + +#define MAX_QPATH 64 // Must match value in quakedefs.h + +///////////////// +// Customization +// passed to pfnPlayerCustomization +// For automatic downloading. +typedef enum +{ + t_sound = 0, + t_skin, + t_model, + t_decal, + t_generic, + t_eventscript, + t_world, // Fake type for world, is really t_model +} resourcetype_t; + + +typedef struct +{ + int size; +} _resourceinfo_t; + +typedef struct resourceinfo_s +{ + _resourceinfo_t info[ 8 ]; +} resourceinfo_t; + +#define RES_FATALIFMISSING (1<<0) // Disconnect if we can't get this file. +#define RES_WASMISSING (1<<1) // Do we have the file locally, did we get it ok? +#define RES_CUSTOM (1<<2) // Is this resource one that corresponds to another player's customization + // or is it a server startup resource. +#define RES_REQUESTED (1<<3) // Already requested a download of this one +#define RES_PRECACHED (1<<4) // Already precached +#define RES_ALWAYS (1<<5) // download always even if available on client +#define RES_UNK_6 (1<<6) // TODO: what is it? +#define RES_CHECKFILE (1<<7) // check file on client + +#include "crc.h" + +typedef struct resource_s +{ + char szFileName[MAX_QPATH]; // File name to download/precache. + resourcetype_t type; // t_sound, t_skin, t_model, t_decal. + int nIndex; // For t_decals + int nDownloadSize; // Size in Bytes if this must be downloaded. + unsigned char ucFlags; + +// For handling client to client resource propagation + unsigned char rgucMD5_hash[16]; // To determine if we already have it. + unsigned char playernum; // Which player index this resource is associated with, if it's a custom resource. + + unsigned char rguc_reserved[ 32 ]; // For future expansion + struct resource_s *pNext; // Next in chain. + struct resource_s *pPrev; +} resource_t; + +typedef struct customization_s +{ + qboolean bInUse; // Is this customization in use; + resource_t resource; // The resource_t for this customization + qboolean bTranslated; // Has the raw data been translated into a useable format? + // (e.g., raw decal .wad make into texture_t *) + int nUserData1; // Customization specific data + int nUserData2; // Customization specific data + void *pInfo; // Buffer that holds the data structure that references the data (e.g., the cachewad_t) + void *pBuffer; // Buffer that holds the data for the customization (the raw .wad data) + struct customization_s *pNext; // Next in chain +} customization_t; + +#define FCUST_FROMHPAK ( 1<<0 ) +#define FCUST_WIPEDATA ( 1<<1 ) +#define FCUST_IGNOREINIT ( 1<<2 ) diff --git a/rehlds/public/rehlds/customentity.h b/rehlds/public/rehlds/customentity.h new file mode 100644 index 0000000..2c4eb5e --- /dev/null +++ b/rehlds/public/rehlds/customentity.h @@ -0,0 +1,38 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef CUSTOMENTITY_H +#define CUSTOMENTITY_H + +// Custom Entities + +// Start/End Entity is encoded as 12 bits of entity index, and 4 bits of attachment (4:12) +#define BEAMENT_ENTITY(x) ((x)&0xFFF) +#define BEAMENT_ATTACHMENT(x) (((x)>>12)&0xF) + +// Beam types, encoded as a byte +enum +{ + BEAM_POINTS = 0, + BEAM_ENTPOINT, + BEAM_ENTS, + BEAM_HOSE, +}; + +#define BEAM_FSINE 0x10 +#define BEAM_FSOLID 0x20 +#define BEAM_FSHADEIN 0x40 +#define BEAM_FSHADEOUT 0x80 + +#endif //CUSTOMENTITY_H diff --git a/rehlds/public/rehlds/d_local.h b/rehlds/public/rehlds/d_local.h new file mode 100644 index 0000000..1313edf --- /dev/null +++ b/rehlds/public/rehlds/d_local.h @@ -0,0 +1,46 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#pragma once + + + +/* <82286> ../engine/d_local.h:20 */ +typedef struct surfcache_s +{ + struct surfcache_s *next; + struct surfcache_s **owner; + int lightadj[4]; + int dlight; + int size; + unsigned width; + unsigned height; + float mipscale; + struct texture_s *texture; + unsigned char data[4]; +} surfcache_t; diff --git a/rehlds/public/rehlds/edict.h b/rehlds/public/rehlds/edict.h new file mode 100644 index 0000000..6bb109d --- /dev/null +++ b/rehlds/public/rehlds/edict.h @@ -0,0 +1,36 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined EDICT_H +#define EDICT_H +#ifdef _WIN32 +#pragma once +#endif +#define MAX_ENT_LEAFS 48 + +#include "progdefs.h" + +struct edict_s +{ + qboolean free; + int serialnumber; + link_t area; // linked to a division node or leaf + + int headnode; // -1 to use normal leaf check + int num_leafs; + short leafnums[MAX_ENT_LEAFS]; + + float freetime; // sv.time when the object was freed + + void* pvPrivateData; // Alloced and freed by engine, used by DLLs + + entvars_t v; // C exported fields from progs + + // other fields from progs come immediately after +}; + +#endif diff --git a/rehlds/public/rehlds/eiface.h b/rehlds/public/rehlds/eiface.h new file mode 100644 index 0000000..f34cd95 --- /dev/null +++ b/rehlds/public/rehlds/eiface.h @@ -0,0 +1,536 @@ +/*** +* +* Copyright (c) 1999, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#pragma once + +#include "archtypes.h" // DAL + +#ifdef HLDEMO_BUILD +#define INTERFACE_VERSION 001 +#else // !HLDEMO_BUILD, i.e., regular version of HL +#define INTERFACE_VERSION 140 +#endif // !HLDEMO_BUILD + +#include +#include "custom.h" +#include "cvardef.h" +#include "Sequence.h" +// +// Defines entity interface between engine and DLLs. +// This header file included by engine files and DLL files. +// +// Before including this header, DLLs must: +// include progdefs.h +// This is conveniently done for them in extdll.h +// + +/* +#ifdef _WIN32 +#define DLLEXPORT __stdcall +#else +#define DLLEXPORT __attribute__ ((visibility("default"))) +#endif +*/ + +enum ALERT_TYPE +{ + at_notice, + at_console, // same as at_notice, but forces a ConPrintf, not a message box + at_aiconsole, // same as at_console, but only shown if developer level is 2! + at_warning, + at_error, + at_logged // Server print to console ( only in multiplayer games ). +}; + +// 4-22-98 JOHN: added for use in pfnClientPrintf +enum PRINT_TYPE +{ + print_console, + print_center, + print_chat, +}; + +// For integrity checking of content on clients +enum FORCE_TYPE +{ + force_exactfile, // File on client must exactly match server's file + force_model_samebounds, // For model files only, the geometry must fit in the same bbox + force_model_specifybounds, // For model files only, the geometry must fit in the specified bbox + force_model_specifybounds_if_avail, // For Steam model files only, the geometry must fit in the specified bbox (if the file is available) +}; + +// Returned by TraceLine +struct TraceResult +{ + int fAllSolid; // if true, plane is not valid + int fStartSolid; // if true, the initial point was in a solid area + int fInOpen; + int fInWater; + float flFraction; // time completed, 1.0 = didn't hit anything + vec3_t vecEndPos; // final position + float flPlaneDist; + vec3_t vecPlaneNormal; // surface normal at impact + edict_t *pHit; // entity the surface is on + int iHitgroup; // 0 == generic, non zero is specific body part +}; + +// CD audio status +typedef struct +{ + int fPlaying;// is sound playing right now? + int fWasPlaying;// if not, CD is paused if WasPlaying is true. + int fInitialized; + int fEnabled; + int fPlayLooping; + float cdvolume; + //BYTE remap[100]; + int fCDRom; + int fPlayTrack; +} CDStatus; + +#include "../common/crc.h" + + +// Engine hands this to DLLs for functionality callbacks +typedef struct enginefuncs_s +{ + int (*pfnPrecacheModel) (char* s); + int (*pfnPrecacheSound) (char* s); + void (*pfnSetModel) (edict_t *e, const char *m); + int (*pfnModelIndex) (const char *m); + int (*pfnModelFrames) (int modelIndex); + void (*pfnSetSize) (edict_t *e, const float *rgflMin, const float *rgflMax); + void (*pfnChangeLevel) (char* s1, char* s2); + void (*pfnGetSpawnParms) (edict_t *ent); + void (*pfnSaveSpawnParms) (edict_t *ent); + float (*pfnVecToYaw) (const float *rgflVector); + void (*pfnVecToAngles) (const float *rgflVectorIn, float *rgflVectorOut); + void (*pfnMoveToOrigin) (edict_t *ent, const float *pflGoal, float dist, int iMoveType); + void (*pfnChangeYaw) (edict_t* ent); + void (*pfnChangePitch) (edict_t* ent); + edict_t* (*pfnFindEntityByString) (edict_t *pEdictStartSearchAfter, const char *pszField, const char *pszValue); + int (*pfnGetEntityIllum) (edict_t* pEnt); + edict_t* (*pfnFindEntityInSphere) (edict_t *pEdictStartSearchAfter, const float *org, float rad); + edict_t* (*pfnFindClientInPVS) (edict_t *pEdict); + edict_t* (*pfnEntitiesInPVS) (edict_t *pplayer); + void (*pfnMakeVectors) (const float *rgflVector); + void (*pfnAngleVectors) (const float *rgflVector, float *forward, float *right, float *up); + edict_t* (*pfnCreateEntity) (void); + void (*pfnRemoveEntity) (edict_t* e); + edict_t* (*pfnCreateNamedEntity) (int className); + void (*pfnMakeStatic) (edict_t *ent); + int (*pfnEntIsOnFloor) (edict_t *e); + int (*pfnDropToFloor) (edict_t* e); + int (*pfnWalkMove) (edict_t *ent, float yaw, float dist, int iMode); + void (*pfnSetOrigin) (edict_t *e, const float *rgflOrigin); + void (*pfnEmitSound) (edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch); + void (*pfnEmitAmbientSound) (edict_t *entity, float *pos, const char *samp, float vol, float attenuation, int fFlags, int pitch); + void (*pfnTraceLine) (const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); + void (*pfnTraceToss) (edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr); + int (*pfnTraceMonsterHull) (edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr); + void (*pfnTraceHull) (const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr); + void (*pfnTraceModel) (const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr); + const char *(*pfnTraceTexture) (edict_t *pTextureEntity, const float *v1, const float *v2 ); + void (*pfnTraceSphere) (const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr); + void (*pfnGetAimVector) (edict_t* ent, float speed, float *rgflReturn); + void (*pfnServerCommand) (char* str); + void (*pfnServerExecute) (void); + void (*pfnClientCommand) (edict_t* pEdict, char* szFmt, ...); + void (*pfnParticleEffect) (const float *org, const float *dir, float color, float count); + void (*pfnLightStyle) (int style, char* val); + int (*pfnDecalIndex) (const char *name); + int (*pfnPointContents) (const float *rgflVector); + void (*pfnMessageBegin) (int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); + void (*pfnMessageEnd) (void); + void (*pfnWriteByte) (int iValue); + void (*pfnWriteChar) (int iValue); + void (*pfnWriteShort) (int iValue); + void (*pfnWriteLong) (int iValue); + void (*pfnWriteAngle) (float flValue); + void (*pfnWriteCoord) (float flValue); + void (*pfnWriteString) (const char *sz); + void (*pfnWriteEntity) (int iValue); + void (*pfnCVarRegister) (cvar_t *pCvar); + float (*pfnCVarGetFloat) (const char *szVarName); + const char* (*pfnCVarGetString) (const char *szVarName); + void (*pfnCVarSetFloat) (const char *szVarName, float flValue); + void (*pfnCVarSetString) (const char *szVarName, const char *szValue); + void (*pfnAlertMessage) (ALERT_TYPE atype, const char *szFmt, ...); + void (*pfnEngineFprintf) (void *pfile, const char *szFmt, ...); + void* (*pfnPvAllocEntPrivateData) (edict_t *pEdict, int32 cb); + void* (*pfnPvEntPrivateData) (edict_t *pEdict); + void (*pfnFreeEntPrivateData) (edict_t *pEdict); + const char* (*pfnSzFromIndex) (int iString); + int (*pfnAllocString) (const char *szValue); + struct entvars_s* (*pfnGetVarsOfEnt) (edict_t *pEdict); + edict_t* (*pfnPEntityOfEntOffset) (int iEntOffset); + int (*pfnEntOffsetOfPEntity) (const edict_t *pEdict); + int (*pfnIndexOfEdict) (const edict_t *pEdict); + edict_t* (*pfnPEntityOfEntIndex) (int iEntIndex); + edict_t* (*pfnFindEntityByVars) (struct entvars_s* pvars); + void* (*pfnGetModelPtr) (edict_t* pEdict); + int (*pfnRegUserMsg) (const char *pszName, int iSize); + void (*pfnAnimationAutomove) (const edict_t* pEdict, float flTime); + void (*pfnGetBonePosition) (const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); + uint32 (*pfnFunctionFromName) ( const char *pName ); + const char *(*pfnNameForFunction) ( uint32 function ); + void (*pfnClientPrintf) ( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg ); // JOHN: engine callbacks so game DLL can print messages to individual clients + void (*pfnServerPrint) ( const char *szMsg ); + const char *(*pfnCmd_Args) ( void ); // these 3 added + const char *(*pfnCmd_Argv) ( int argc ); // so game DLL can easily + int (*pfnCmd_Argc) ( void ); // access client 'cmd' strings + void (*pfnGetAttachment) (const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ); + void (*pfnCRC32_Init) (CRC32_t *pulCRC); + void (*pfnCRC32_ProcessBuffer) (CRC32_t *pulCRC, void *p, int len); + void (*pfnCRC32_ProcessByte) (CRC32_t *pulCRC, unsigned char ch); + CRC32_t (*pfnCRC32_Final) (CRC32_t pulCRC); + int32 (*pfnRandomLong) (int32 lLow, int32 lHigh); + float (*pfnRandomFloat) (float flLow, float flHigh); + void (*pfnSetView) (const edict_t *pClient, const edict_t *pViewent ); + float (*pfnTime) ( void ); + void (*pfnCrosshairAngle) (const edict_t *pClient, float pitch, float yaw); + byte * (*pfnLoadFileForMe) (char *filename, int *pLength); + void (*pfnFreeFile) (void *buffer); + void (*pfnEndSection) (const char *pszSectionName); // trigger_endsection + int (*pfnCompareFileTime) (char *filename1, char *filename2, int *iCompare); + void (*pfnGetGameDir) (char *szGetGameDir); + void (*pfnCvar_RegisterVariable) (cvar_t *variable); + void (*pfnFadeClientVolume) (const edict_t *pEdict, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds); + void (*pfnSetClientMaxspeed) (edict_t *pEdict, float fNewMaxspeed); + edict_t * (*pfnCreateFakeClient) (const char *netname); // returns NULL if fake client can't be created + void (*pfnRunPlayerMove) (edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, byte msec ); + int (*pfnNumberOfEntities) (void); + char* (*pfnGetInfoKeyBuffer) (edict_t *e); // passing in NULL gets the serverinfo + char* (*pfnInfoKeyValue) (char *infobuffer, char *key); + void (*pfnSetKeyValue) (char *infobuffer, char *key, char *value); + void (*pfnSetClientKeyValue) (int clientIndex, char *infobuffer, char *key, char *value); + int (*pfnIsMapValid) (char *filename); + void (*pfnStaticDecal) ( const float *origin, int decalIndex, int entityIndex, int modelIndex ); + int (*pfnPrecacheGeneric) (char* s); + int (*pfnGetPlayerUserId) (edict_t *e ); // returns the server assigned userid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients + void (*pfnBuildSoundMsg) (edict_t *entity, int channel, const char *sample, /*int*/float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed); + int (*pfnIsDedicatedServer) (void);// is this a dedicated server? + cvar_t *(*pfnCVarGetPointer) (const char *szVarName); + unsigned int (*pfnGetPlayerWONId) (edict_t *e); // returns the server assigned WONid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients + + // YWB 8/1/99 TFF Physics additions + void (*pfnInfo_RemoveKey) ( char *s, const char *key ); + const char *(*pfnGetPhysicsKeyValue) ( const edict_t *pClient, const char *key ); + void (*pfnSetPhysicsKeyValue) ( const edict_t *pClient, const char *key, const char *value ); + const char *(*pfnGetPhysicsInfoString) ( const edict_t *pClient ); + unsigned short (*pfnPrecacheEvent) ( int type, const char*psz ); + void (*pfnPlaybackEvent) ( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); + + unsigned char *(*pfnSetFatPVS) ( float *org ); + unsigned char *(*pfnSetFatPAS) ( float *org ); + + int (*pfnCheckVisibility ) ( edict_t *entity, unsigned char *pset ); + + void (*pfnDeltaSetField) ( struct delta_s *pFields, const char *fieldname ); + void (*pfnDeltaUnsetField) ( struct delta_s *pFields, const char *fieldname ); + void (*pfnDeltaAddEncoder) ( char *name, void (*conditionalencode)( struct delta_s *pFields, const unsigned char *from, const unsigned char *to ) ); + int (*pfnGetCurrentPlayer) ( void ); + int (*pfnCanSkipPlayer) ( const edict_t *player ); + int (*pfnDeltaFindField) ( struct delta_s *pFields, const char *fieldname ); + void (*pfnDeltaSetFieldByIndex) ( struct delta_s *pFields, int fieldNumber ); + void (*pfnDeltaUnsetFieldByIndex)( struct delta_s *pFields, int fieldNumber ); + + void (*pfnSetGroupMask) ( int mask, int op ); + + int (*pfnCreateInstancedBaseline) ( int classname, struct entity_state_s *baseline ); + void (*pfnCvar_DirectSet) ( struct cvar_s *var, char *value ); + + // Forces the client and server to be running with the same version of the specified file + // ( e.g., a player model ). + // Calling this has no effect in single player + void (*pfnForceUnmodified) ( FORCE_TYPE type, float *mins, float *maxs, const char *filename ); + + void (*pfnGetPlayerStats) ( const edict_t *pClient, int *ping, int *packet_loss ); + + void (*pfnAddServerCommand) ( char *cmd_name, void (*function) (void) ); + + // For voice communications, set which clients hear eachother. + // NOTE: these functions take player entity indices (starting at 1). + qboolean (*pfnVoice_GetClientListening)(int iReceiver, int iSender); + qboolean (*pfnVoice_SetClientListening)(int iReceiver, int iSender, qboolean bListen); + + const char *(*pfnGetPlayerAuthId) ( edict_t *e ); + + // PSV: Added for CZ training map +// const char *(*pfnKeyNameForBinding) ( const char* pBinding ); + + sequenceEntry_s* (*pfnSequenceGet) ( const char* fileName, const char* entryName ); + sentenceEntry_s* (*pfnSequencePickSentence) ( const char* groupName, int pickMethod, int *picked ); + + // LH: Give access to filesize via filesystem + int (*pfnGetFileSize) ( char *filename ); + + unsigned int (*pfnGetApproxWavePlayLen) (const char *filepath); + // MDC: Added for CZ career-mode + int (*pfnIsCareerMatch) ( void ); + + // BGC: return the number of characters of the localized string referenced by using "label" + int (*pfnGetLocalizedStringLength) (const char *label); + + // BGC: added to facilitate persistent storage of tutor message decay values for + // different career game profiles. Also needs to persist regardless of mp.dll being + // destroyed and recreated. + void (*pfnRegisterTutorMessageShown) (int mid); + int (*pfnGetTimesTutorMessageShown) (int mid); + void (*pfnProcessTutorMessageDecayBuffer) (int *buffer, int bufferLength); + void (*pfnConstructTutorMessageDecayBuffer) (int *buffer, int bufferLength); + void (*pfnResetTutorMessageDecayData) ( void ); + + // Added 2005/08/11 (no SDK update): + void(*pfnQueryClientCvarValue) (const edict_t *player, const char *cvarName); + + // Added 2005/11/21 (no SDK update): + void(*pfnQueryClientCvarValue2) (const edict_t *player, const char *cvarName, int requestID); + + // Added 2009/06/19 (no SDK update): + int(*pfnEngCheckParm) (const char *pchCmdLineToken, char **ppnext); +} enginefuncs_t; + + +// ONLY ADD NEW FUNCTIONS TO THE END OF THIS STRUCT. INTERFACE VERSION IS FROZEN AT 138 + +// Passed to pfnKeyValue +typedef struct KeyValueData_s +{ + char *szClassName; // in: entity classname + char *szKeyName; // in: name of key + char *szValue; // in: value of key + qboolean fHandled; // out: DLL sets to true if key-value pair was understood +} KeyValueData; + + +typedef struct +{ + char mapName[ 32 ]; + char landmarkName[ 32 ]; + edict_t *pentLandmark; + vec3_t vecLandmarkOrigin; +} LEVELLIST; +#define MAX_LEVEL_CONNECTIONS 16 // These are encoded in the lower 16bits of ENTITYTABLE->flags + +typedef struct +{ + int id; // Ordinal ID of this entity (used for entity <--> pointer conversions) + edict_t *pent; // Pointer to the in-game entity + + int location; // Offset from the base data of this entity + int size; // Byte size of this entity's data + int flags; // This could be a short -- bit mask of transitions that this entity is in the PVS of + string_t classname; // entity class name + +} ENTITYTABLE; + +#define FENTTABLE_PLAYER 0x80000000 +#define FENTTABLE_REMOVED 0x40000000 +#define FENTTABLE_MOVEABLE 0x20000000 +#define FENTTABLE_GLOBAL 0x10000000 + +typedef struct saverestore_s SAVERESTOREDATA; + +#ifdef _WIN32 +typedef +#endif +struct saverestore_s +{ + char *pBaseData; // Start of all entity save data + char *pCurrentData; // Current buffer pointer for sequential access + int size; // Current data size + int bufferSize; // Total space for data + int tokenSize; // Size of the linear list of tokens + int tokenCount; // Number of elements in the pTokens table + char **pTokens; // Hash table of entity strings (sparse) + int currentIndex; // Holds a global entity table ID + int tableCount; // Number of elements in the entity table + int connectionCount;// Number of elements in the levelList[] + ENTITYTABLE *pTable; // Array of ENTITYTABLE elements (1 for each entity) + LEVELLIST levelList[ MAX_LEVEL_CONNECTIONS ]; // List of connections from this level + + // smooth transition + int fUseLandmark; + char szLandmarkName[20];// landmark we'll spawn near in next level + vec3_t vecLandmarkOffset;// for landmark transitions + float time; + char szCurrentMapName[32]; // To check global entities + +} +#ifdef _WIN32 +SAVERESTOREDATA +#endif +; + +typedef enum _fieldtypes +{ + FIELD_FLOAT = 0, // Any floating point value + FIELD_STRING, // A string ID (return from ALLOC_STRING) + FIELD_ENTITY, // An entity offset (EOFFSET) + FIELD_CLASSPTR, // CBaseEntity * + FIELD_EHANDLE, // Entity handle + FIELD_EVARS, // EVARS * + FIELD_EDICT, // edict_t *, or edict_t * (same thing) + FIELD_VECTOR, // Any vector + FIELD_POSITION_VECTOR, // A world coordinate (these are fixed up across level transitions automagically) + FIELD_POINTER, // Arbitrary data pointer... to be removed, use an array of FIELD_CHARACTER + FIELD_INTEGER, // Any integer or enum + FIELD_FUNCTION, // A class function pointer (Think, Use, etc) + FIELD_BOOLEAN, // boolean, implemented as an int, I may use this as a hint for compression + FIELD_SHORT, // 2 byte integer + FIELD_CHARACTER, // a byte + FIELD_TIME, // a floating point time (these are fixed up automatically too!) + FIELD_MODELNAME, // Engine string that is a model name (needs precache) + FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache) + + FIELD_TYPECOUNT, // MUST BE LAST +} FIELDTYPE; + +#if !defined(offsetof) && !defined(GNUC) +#define offsetof(s,m) (size_t)&(((s *)0)->m) +#endif + +#define _FIELD(type,name,fieldtype,count,flags) { fieldtype, #name, offsetof(type, name), count, flags } +#define DEFINE_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, 0) +#define DEFINE_ARRAY(type,name,fieldtype,count) _FIELD(type, name, fieldtype, count, 0) +#define DEFINE_ENTITY_FIELD(name,fieldtype) _FIELD(entvars_t, name, fieldtype, 1, 0 ) +#define DEFINE_ENTITY_GLOBAL_FIELD(name,fieldtype) _FIELD(entvars_t, name, fieldtype, 1, FTYPEDESC_GLOBAL ) +#define DEFINE_GLOBAL_FIELD(type,name,fieldtype) _FIELD(type, name, fieldtype, 1, FTYPEDESC_GLOBAL ) + + +#define FTYPEDESC_GLOBAL 0x0001 // This field is masked for global entity save/restore + +typedef struct +{ + FIELDTYPE fieldType; + char *fieldName; + int fieldOffset; + short fieldSize; + short flags; +} TYPEDESCRIPTION; + +#ifndef ARRAYSIZE +#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) +#endif + +typedef struct +{ + // Initialize/shutdown the game (one-time call after loading of game .dll ) + void (*pfnGameInit) ( void ); + int (*pfnSpawn) ( edict_t *pent ); + void (*pfnThink) ( edict_t *pent ); + void (*pfnUse) ( edict_t *pentUsed, edict_t *pentOther ); + void (*pfnTouch) ( edict_t *pentTouched, edict_t *pentOther ); + void (*pfnBlocked) ( edict_t *pentBlocked, edict_t *pentOther ); + void (*pfnKeyValue) ( edict_t *pentKeyvalue, KeyValueData *pkvd ); + void (*pfnSave) ( edict_t *pent, SAVERESTOREDATA *pSaveData ); + int (*pfnRestore) ( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); + void (*pfnSetAbsBox) ( edict_t *pent ); + + void (*pfnSaveWriteFields) ( SAVERESTOREDATA *, const char *, void *, TYPEDESCRIPTION *, int ); + void (*pfnSaveReadFields) ( SAVERESTOREDATA *, const char *, void *, TYPEDESCRIPTION *, int ); + + void (*pfnSaveGlobalState) ( SAVERESTOREDATA * ); + void (*pfnRestoreGlobalState) ( SAVERESTOREDATA * ); + void (*pfnResetGlobalState) ( void ); + + qboolean (*pfnClientConnect) ( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); + + void (*pfnClientDisconnect) ( edict_t *pEntity ); + void (*pfnClientKill) ( edict_t *pEntity ); + void (*pfnClientPutInServer) ( edict_t *pEntity ); + void (*pfnClientCommand) ( edict_t *pEntity ); + void (*pfnClientUserInfoChanged)( edict_t *pEntity, char *infobuffer ); + + void (*pfnServerActivate) ( edict_t *pEdictList, int edictCount, int clientMax ); + void (*pfnServerDeactivate) ( void ); + + void (*pfnPlayerPreThink) ( edict_t *pEntity ); + void (*pfnPlayerPostThink) ( edict_t *pEntity ); + + void (*pfnStartFrame) ( void ); + void (*pfnParmsNewLevel) ( void ); + void (*pfnParmsChangeLevel) ( void ); + + // Returns string describing current .dll. E.g., TeamFotrress 2, Half-Life + const char *(*pfnGetGameDescription)( void ); + + // Notify dll about a player customization. + void (*pfnPlayerCustomization) ( edict_t *pEntity, customization_t *pCustom ); + + // Spectator funcs + void (*pfnSpectatorConnect) ( edict_t *pEntity ); + void (*pfnSpectatorDisconnect) ( edict_t *pEntity ); + void (*pfnSpectatorThink) ( edict_t *pEntity ); + + // Notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. + void (*pfnSys_Error) ( const char *error_string ); + + void (*pfnPM_Move) ( struct playermove_s *ppmove, qboolean server ); + void (*pfnPM_Init) ( struct playermove_s *ppmove ); + char (*pfnPM_FindTextureType)( char *name ); + void (*pfnSetupVisibility)( struct edict_s *pViewEntity, struct edict_s *pClient, unsigned char **pvs, unsigned char **pas ); + void (*pfnUpdateClientData) ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); + int (*pfnAddToFullPack)( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ); + void (*pfnCreateBaseline) ( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); + void (*pfnRegisterEncoders) ( void ); + int (*pfnGetWeaponData) ( struct edict_s *player, struct weapon_data_s *info ); + + void (*pfnCmdStart) ( const edict_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); + void (*pfnCmdEnd) ( const edict_t *player ); + + // Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max + // size of the response_buffer, so you must zero it out if you choose not to respond. + int (*pfnConnectionlessPacket ) ( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); + + // Enumerates player hulls. Returns 0 if the hull number doesn't exist, 1 otherwise + int (*pfnGetHullBounds) ( int hullnumber, float *mins, float *maxs ); + + // Create baselines for certain "unplaced" items. + void (*pfnCreateInstancedBaselines) ( void ); + + // One of the pfnForceUnmodified files failed the consistency check for the specified player + // Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters ) + int (*pfnInconsistentFile)( const struct edict_s *player, const char *filename, char *disconnect_message ); + + // The game .dll should return 1 if lag compensation should be allowed ( could also just set + // the sv_unlag cvar. + // Most games right now should return 0, until client-side weapon prediction code is written + // and tested for them. + int (*pfnAllowLagCompensation)( void ); +} DLL_FUNCTIONS; + +extern DLL_FUNCTIONS gEntityInterface; + +// Current version. +#define NEW_DLL_FUNCTIONS_VERSION 1 + +typedef struct +{ + // Called right before the object's memory is freed. + // Calls its destructor. + void (*pfnOnFreeEntPrivateData)(edict_t *pEnt); + void (*pfnGameShutdown)(void); + int (*pfnShouldCollide)( edict_t *pentTouched, edict_t *pentOther ); + void (*pfnCvarValue)( const edict_t *pEnt, const char *value ); + void (*pfnCvarValue2)( const edict_t *pEnt, int requestID, const char *cvarName, const char *value ); +} NEW_DLL_FUNCTIONS; +typedef int(*NEW_DLL_FUNCTIONS_FN)(NEW_DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion); + +// Pointers will be null if the game DLL doesn't support this API. +extern NEW_DLL_FUNCTIONS gNewDLLFunctions; + +typedef int(*APIFUNCTION)(DLL_FUNCTIONS *pFunctionTable, int interfaceVersion); +typedef int(*APIFUNCTION2)(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion); diff --git a/rehlds/public/rehlds/hookchains.h b/rehlds/public/rehlds/hookchains.h new file mode 100644 index 0000000..52f15c7 --- /dev/null +++ b/rehlds/public/rehlds/hookchains.h @@ -0,0 +1,67 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +template +class IHookChain { +protected: + virtual ~IHookChain() { } + +public: + virtual t_ret callNext(t_args... args) = 0; + virtual t_ret getOriginalReturnResult() = 0; + virtual bool isOriginalCalled() = 0; +}; + +// Hook chain registry(for hooks [un]registration) +template +class IHookChainRegistry { +public: + typedef t_ret(*hookfunc_t)(IHookChain*, t_args...); + + virtual void registerHook(hookfunc_t hook) = 0; +}; + + + + +template +class IVoidHookChain { +public: + virtual void callNext(t_args... args) = 0; + virtual bool isOriginalCalled() = 0; +}; + +// Hook chain registry(for hooks [un]registration) +template +class IVoidHookChainRegistry { +public: + typedef void(*hookfunc_t)(IVoidHookChain*, t_args...); + + virtual void registerHook(hookfunc_t hook) = 0; +}; diff --git a/rehlds/public/rehlds/keydefs.h b/rehlds/public/rehlds/keydefs.h new file mode 100644 index 0000000..4adeeab --- /dev/null +++ b/rehlds/public/rehlds/keydefs.h @@ -0,0 +1,131 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// keydefs.h +#ifndef KEYDEFS_H +#define KEYDEFS_H +#ifdef _WIN32 +#ifndef __MINGW32__ +#pragma once +#endif /* not __MINGW32__ */ +#endif + +// +// these are the key numbers that should be passed to Key_Event +// +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 + +// normal keys should be passed as lowercased ascii + +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 + +#define K_ALT 132 +#define K_CTRL 133 +#define K_SHIFT 134 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 + +#define K_KP_HOME 160 +#define K_KP_UPARROW 161 +#define K_KP_PGUP 162 +#define K_KP_LEFTARROW 163 +#define K_KP_5 164 +#define K_KP_RIGHTARROW 165 +#define K_KP_END 166 +#define K_KP_DOWNARROW 167 +#define K_KP_PGDN 168 +#define K_KP_ENTER 169 +#define K_KP_INS 170 +#define K_KP_DEL 171 +#define K_KP_SLASH 172 +#define K_KP_MINUS 173 +#define K_KP_PLUS 174 +#define K_CAPSLOCK 175 + + +// +// joystick buttons +// +#define K_JOY1 203 +#define K_JOY2 204 +#define K_JOY3 205 +#define K_JOY4 206 + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +#define K_AUX1 207 +#define K_AUX2 208 +#define K_AUX3 209 +#define K_AUX4 210 +#define K_AUX5 211 +#define K_AUX6 212 +#define K_AUX7 213 +#define K_AUX8 214 +#define K_AUX9 215 +#define K_AUX10 216 +#define K_AUX11 217 +#define K_AUX12 218 +#define K_AUX13 219 +#define K_AUX14 220 +#define K_AUX15 221 +#define K_AUX16 222 +#define K_AUX17 223 +#define K_AUX18 224 +#define K_AUX19 225 +#define K_AUX20 226 +#define K_AUX21 227 +#define K_AUX22 228 +#define K_AUX23 229 +#define K_AUX24 230 +#define K_AUX25 231 +#define K_AUX26 232 +#define K_AUX27 233 +#define K_AUX28 234 +#define K_AUX29 235 +#define K_AUX30 236 +#define K_AUX31 237 +#define K_AUX32 238 +#define K_MWHEELDOWN 239 +#define K_MWHEELUP 240 + +#define K_PAUSE 255 + +// +// mouse buttons generate virtual keys +// +#define K_MOUSE1 241 +#define K_MOUSE2 242 +#define K_MOUSE3 243 +#define K_MOUSE4 244 +#define K_MOUSE5 245 + +#endif // KEYDEFS_H diff --git a/rehlds/public/rehlds/maintypes.h b/rehlds/public/rehlds/maintypes.h new file mode 100644 index 0000000..6a7fa96 --- /dev/null +++ b/rehlds/public/rehlds/maintypes.h @@ -0,0 +1,58 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef MAINTYPES_H +#define MAINTYPES_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "osconfig.h" +#include "mathlib.h" + + +// Has no references on server side. +#define NOXREF +// Function body is not implemented. +#define NOBODY +// Function is not tested at all. +#define UNTESTED + +#define BIT(n) (1<<(n)) + + +typedef unsigned int string_t; // from engine's pr_comp.h; + +#ifndef __cplusplus + typedef enum { false, true } qboolean; +#else + typedef int qboolean; +#endif + +#endif // MAINTYPES_H diff --git a/rehlds/public/rehlds/model.h b/rehlds/public/rehlds/model.h new file mode 100644 index 0000000..e02ed97 --- /dev/null +++ b/rehlds/public/rehlds/model.h @@ -0,0 +1,415 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "const.h" +#include "modelgen.h" +#include "spritegn.h" +#include "bspfile.h" +#include "crc.h" +#include "com_model.h" + +#define SURF_PLANEBACK 2 +#define SURF_DRAWSKY 4 +#define SURF_DRAWSPRITE 8 +#define SURF_DRAWTURB 0x10 +#define SURF_DRAWTILED 0x20 +#define SURF_DRAWBACKGROUND 0x40 +#define ALIAS_MODEL_VERSION 0x006 + +#define MAX_MODEL_NAME 64 +#define MIPLEVELS 4 +#define NUM_AMBIENTS 4 // automatic ambient sounds +#define MAXLIGHTMAPS 4 +#define MAX_KNOWN_MODELS 1024 + +/* <6816> ../engine/model.h:27 */ +typedef struct mvertex_s +{ + vec3_t position; +} mvertex_t; + +/* <6838> ../engine/model.h:39 */ +typedef struct mplane_s +{ + vec3_t normal; // surface normal + float dist; // closest appoach to origin + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_t; + +/* <68a6> ../engine/model.h:48 */ +typedef struct texture_s +{ + char name[16]; + unsigned width, height; + int anim_total; // total tenths in sequence ( 0 = no) + int anim_min, anim_max; // time for this frame min <=time< max + struct texture_s *anim_next; // in the animation sequence + struct texture_s *alternate_anims; // bmodels in frame 1 use these + unsigned offsets[MIPLEVELS]; // four mip maps stored + unsigned paloffset; +} texture_t; + +/* <6950> ../engine/model.h:71 */ +typedef struct medge_s +{ + unsigned short v[2]; + unsigned int cachededgeoffset; +} medge_t; + +/* <697e> ../engine/model.h:78 */ +typedef struct mtexinfo_s +{ + float vecs[2][4]; // [s/t] unit vectors in world space. + // [i][3] is the s/t offset relative to the origin. + // s or t = dot(3Dpoint,vecs[i])+vecs[i][3] + float mipadjust; // ?? mipmap limits for very small surfaces + texture_t *texture; + int flags; // sky or slime, no lightmap or 256 subdivision +} mtexinfo_t; +#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision + +/* <69d0> ../engine/model.h:91 */ +typedef struct msurface_s msurface_t; +/* <1db66> ../engine/model.h:92 */ +typedef struct decal_s decal_t; + +// JAY: Compress this as much as possible +/* <1db71> ../engine/model.h:96 */ +struct decal_s +{ + decal_t *pnext; // linked list for each surface + msurface_t *psurface; // Surface id for persistence / unlinking + short dx; // Offsets into surface texture (in texture coordinates, so we don't need floats) + short dy; + short texture; // Decal texture + byte scale; // Pixel scale + byte flags; // Decal flags + + short entityIndex; // Entity this is attached to +}; + +/* <69db> ../engine/model.h:118 */ +struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + int dlightframe; // last frame the surface was checked by an animated light + int dlightbits; // dynamically generated. Indicates if the surface illumination + // is modified by an animated light. + + mplane_t *plane; // pointer to shared plane + int flags; // see SURF_ #defines + + int firstedge; // look up in model->surfedges[], negative numbers + int numedges; // are backwards edges + + // surface generation data + struct surfcache_s *cachespots[MIPLEVELS]; + + short texturemins[2]; // smallest s/t position on the surface. + short extents[2]; // ?? s/t texture size, 1..256 for all non-sky surfaces + + mtexinfo_t *texinfo; + + // lighting info + byte styles[MAXLIGHTMAPS]; // index into d_lightstylevalue[] for animated lights + // no one surface can be effected by more than 4 + // animated lights. + color24 *samples; + + decal_t *pdecals; +}; + +/* <6b6c> ../engine/model.h:149 */ +typedef struct mnode_s +{ + // common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + + // node specific + mplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; + +/* <1dcd4> ../engine/model.h:169 */ +typedef struct mleaf_s +{ + // common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + + // leaf specific + byte *compressed_vis; + struct efrag_s *efrags; + + msurface_t **firstmarksurface; + int nummarksurfaces; + int key; // BSP sequence number for leaf's contents + byte ambient_sound_level[NUM_AMBIENTS]; +} mleaf_t; + +/* <1ddbe> ../engine/model.h:190 */ +typedef struct hull_s +{ + dclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins, clip_maxs; +} hull_t; + +/* <4b3fe> ../engine/model.h:210 */ +typedef struct mspriteframe_t +{ + int width; + int height; + void *pcachespot; + float up, down, left, right; + byte pixels[4]; +} mspriteframe_s; + +/* <4b485> ../engine/model.h:219 */ +typedef struct mspritegroup_s +{ + int numframes; + float *intervals; + mspriteframe_t *frames[1]; +} mspritegroup_t; + +/* <4b4df> ../engine/model.h:226 */ +typedef struct mspriteframedesc_s +{ + spriteframetype_t type; + mspriteframe_t *frameptr; +} mspriteframedesc_t; + +/* <4b50f> ../engine/model.h:232 */ +typedef struct msprite_s +{ + short int type; + short int texFormat; + int maxwidth, maxheight; + int numframes; + int paloffset; + float beamlength; + void *cachespot; + mspriteframedesc_t frames[1]; +} msprite_t; + +/* <4b5b5> ../engine/model.h:255 */ +typedef struct maliasframedesc_s +{ + aliasframetype_t type; + trivertx_t bboxmin, bboxmax; + int frame; + char name[16]; +} maliasframedesc_t; + +/* <4b615> ../engine/model.h:264 */ +typedef struct maliasskindesc_s +{ + aliasskintype_t type; + void *pcachespot; + int skin; +} maliasskindesc_t; + +/* <4b658> ../engine/model.h:271 */ +typedef struct maliasgroupframedesc_s +{ + trivertx_t bboxmin, bboxmax; + int frame; +} maliasgroupframedesc_t; + +/* <4b69b> ../engine/model.h:278 */ +typedef struct maliasgroup_s +{ + int numframes; + int intervals; + maliasgroupframedesc_t frames[1]; +} maliasgroup_t; + +/* <4b6ee> ../engine/model.h:285 */ +typedef struct maliasskingroup_s +{ + int numskins; + int intervals; + maliasskindesc_t skindescs[1]; +} maliasskingroup_t; + +/* <4b741> ../engine/model.h:293 */ +typedef struct mtriangle_s +{ + int facesfront; + int vertindex[3]; +} mtriangle_t; + +/* <4b779> ../engine/model.h:298 */ +typedef struct aliashdr_s +{ + int model; + int stverts; + int skindesc; + int triangles; + int palette; + maliasframedesc_t frames[1]; +} aliashdr_t; + +/* <1de30> ../engine/model.h:315 */ +typedef enum modtype_e +{ + mod_brush, + mod_sprite, + mod_alias, + mod_studio, +} modtype_t; + +/* <1de5e> ../engine/model.h:331 */ +typedef struct model_s +{ + char name[MAX_MODEL_NAME]; + + //TODO: qboolean? seriously? + int needload; // bmodels and sprites don't cache normally + + modtype_t type; + int numframes; + synctype_t synctype; + + int flags; + + // + // volume occupied by the model + // + vec3_t mins, maxs; + float radius; + + // + // brush model + // + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + struct mleaf_s *leafs; + + int numvertexes; + mvertex_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + dclipnode_t *clipnodes; + + int nummarksurfaces; + msurface_t **marksurfaces; + + hull_t hulls[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + + byte *visdata; + + color24 *lightdata; + + char *entities; + + // + // additional model data + // + cache_user_t cache; // only access through Mod_Extradata +} model_t; + +typedef struct cachepic_s +{ + char name[64]; + cache_user_t cache; +} cachepic_t; + +typedef struct cachewad_s cachewad_t; + +typedef void(*PFNCACHE)(cachewad_t *, unsigned char *); + +typedef struct cachewad_s +{ + char *name; + cachepic_t *cache; + int cacheCount; + int cacheMax; + struct lumpinfo_s *lumps; + int lumpCount; + int cacheExtra; + PFNCACHE pfnCacheBuild; + int numpaths; + char **basedirs; + int *lumppathindices; +#ifndef SWDS + int tempWad; +#endif // SWDS +} cachewad_t; + +typedef struct mod_known_info_s +{ + qboolean shouldCRC; + qboolean firstCRCDone; + CRC32_t initialCRC; +} mod_known_info_t; + diff --git a/rehlds/public/rehlds/modelgen.h b/rehlds/public/rehlds/modelgen.h new file mode 100644 index 0000000..c33a202 --- /dev/null +++ b/rehlds/public/rehlds/modelgen.h @@ -0,0 +1,144 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef MODELGEN_H +#define MODELGEN_H +#ifdef _WIN32 +#pragma once +#endif + + +/* <67f6> ../engine/modelgen.h:37 */ +typedef enum synctype_e +{ + ST_SYNC = 0, + ST_RAND = 1, +} synctype_t; + +/* <4abae> ../engine/modelgen.h:40 */ +typedef enum aliasframetype_s +{ + ALIAS_SINGLE = 0, + ALIAS_GROUP = 1, +} aliasframetype_t; + +/* 203 */ +/* <4abce> ../engine/modelgen.h:42 */ +typedef enum aliasskintype_s +{ + ALIAS_SKIN_SINGLE = 0, + ALIAS_SKIN_GROUP = 1, +} aliasskintype_t; + +/* <4abee> ../engine/modelgen.h:44 */ +typedef struct mdl_s +{ + int ident; + int version; + vec3_t scale; + vec3_t scale_origin; + float boundingradius; + vec3_t eyeposition; + int numskins; + int skinwidth; + int skinheight; + int numverts; + int numtris; + int numframes; + synctype_t synctype; + int flags; + float size; +} mdl_t; + +/* <4acd4> ../engine/modelgen.h:64 */ +typedef struct stvert_s +{ + int onseam; + int s; + int t; +} stvert_t; + +/* <4ad0e> ../engine/modelgen.h:70 */ +typedef struct dtriangle_s +{ + int facesfront; + int vertindex[3]; +} dtriangle_t; + +/* <4ad42> ../engine/modelgen.h:80 */ +typedef struct trivertx_s +{ + byte v[3]; + byte lightnormalindex; +} trivertx_t; + +/* <4ad80> ../engine/modelgen.h:85 */ +typedef struct daliasframe_s +{ + trivertx_t bboxmin, bboxmax; + char name[16]; +} daliasframe_t; + +/* <4adbe> ../engine/modelgen.h:91 */ +typedef struct daliasgroup_s +{ + int numframes; + trivertx_t bboxmin, bboxmax; +} daliasgroup_t; + +/* <4adfc> ../engine/modelgen.h:97 */ +typedef struct daliasskingroup_s +{ + int numskins; +} daliasskingroup_t; + +/* <4ae1e> ../engine/modelgen.h:101 */ +typedef struct daliasinterval_s +{ + float interval; +} daliasinterval_t; + +/* <4ae40> ../engine/modelgen.h:105 */ +typedef struct daliasskininterval_s +{ + float interval; +} daliasskininterval_t; + +/* <4ae62> ../engine/modelgen.h:109 */ +typedef struct daliasframetype_s +{ + aliasframetype_t type; +} daliasframetype_t; + +/* <4ae84> ../engine/modelgen.h:113 */ +typedef struct daliasskintype_s +{ + aliasskintype_t type; +} daliasskintype_t; + +#endif // MODELGEN_H diff --git a/rehlds/public/rehlds/osconfig.h b/rehlds/public/rehlds/osconfig.h new file mode 100644 index 0000000..91c69e2 --- /dev/null +++ b/rehlds/public/rehlds/osconfig.h @@ -0,0 +1,199 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef _OSCONFIG_H +#define _OSCONFIG_H + +#ifdef _WIN32 // WINDOWS + #pragma warning(disable : 4005) +#endif // _WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 // WINDOWS + #include + #include + #include // for support IPX + #include + #include + #include + #include + #include + #include +#else // _WIN32 + #include + #include + //#include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + // Deail with stupid macro in kernel.h + #undef __FUNCTION__ +#endif // _WIN32 + +#include +#include +#include +#include + +#ifdef _WIN32 // WINDOWS +#ifndef _STDINT + typedef unsigned __int64 uint64_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int8 uint8_t; + + typedef __int64 int64_t; + typedef __int32 int32_t; + typedef __int16 int16_t; + typedef __int8 int8_t; +#endif +#else // _WIN32 + typedef unsigned long long uint64_t; + typedef unsigned int uint32_t; + typedef unsigned short uint16_t; + typedef unsigned char uint8_t; + + #ifndef __int8_t_defined + typedef long long int64_t; + typedef int int32_t; + typedef short int16_t; + typedef char int8_t; + #endif + + typedef unsigned char byte; +#endif // _WIN32 + +#ifdef _WIN32 // WINDOWS + #define _CRT_SECURE_NO_WARNINGS + #define WIN32_LEAN_AND_MEAN + + #ifndef CDECL + #define CDECL __cdecl + #endif + #define STDCALL __stdcall + #define HIDDEN + #define NOINLINE __declspec(noinline) + + //inline bool SOCKET_FIONBIO(SOCKET s, int m) { return (ioctlsocket(s, FIONBIO, (u_long*)&m) == 0); } + //inline int SOCKET_MSGLEN(SOCKET s, u_long& r) { return ioctlsocket(s, FIONREAD, (u_long*)&r); } + typedef int socklen_t; + #define SOCKET_FIONBIO(s, m) ioctlsocket(s, FIONBIO, (u_long*)&m) + #define SOCKET_MSGLEN(s, r) ioctlsocket(s, FIONREAD, (u_long*)&r) + #define SIN_GET_ADDR(saddr, r) r = (saddr)->S_un.S_addr + #define SIN_SET_ADDR(saddr, r) (saddr)->S_un.S_addr = (r) + #define SOCKET_CLOSE(s) closesocket(s) + #define SOCKET_AGAIN() (WSAGetLastError() == WSAEWOULDBLOCK) + + inline void* sys_allocmem(unsigned int size) { + return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); + } +#else // _WIN32 + #ifndef PAGESIZE + #define PAGESIZE 4096 + #endif + #define ALIGN(addr) (size_t)((size_t)addr & ~(PAGESIZE-1)) + #define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + + #define _MAX_FNAME NAME_MAX + #define MAX_PATH 260 + + typedef void *HWND; + + typedef unsigned long DWORD; + typedef unsigned short WORD; + typedef unsigned int UNINT32; + + #define CDECL __attribute__ ((cdecl)) + #define STDCALL __attribute__ ((stdcall)) + #define HIDDEN __attribute__((visibility("hidden"))) + #define NOINLINE __attribute__((noinline)) + + //inline bool SOCKET_FIONBIO(SOCKET s, int m) { return (ioctl(s, FIONBIO, (int*)&m) == 0); } + //inline int SOCKET_MSGLEN(SOCKET s, u_long& r) { return ioctl(s, FIONREAD, (int*)&r); } + typedef int SOCKET; + #define INVALID_SOCKET (SOCKET)(~0) + #define SOCKET_FIONBIO(s, m) ioctl(s, FIONBIO, (char*)&m) + #define SOCKET_MSGLEN(s, r) ioctl(s, FIONREAD, (char*)&r) + #define SIN_GET_ADDR(saddr, r) r = (saddr)->s_addr + #define SIN_SET_ADDR(saddr, r) (saddr)->s_addr = (r) + #define SOCKET_CLOSE(s) close(s) + #define SOCKET_AGAIN() (errno == EAGAIN) + #define SOCKET_ERROR -1 + + inline void* sys_allocmem(unsigned int size) { + return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + + #define WSAENOPROTOOPT ENOPROTOOPT + + inline unsigned long _byteswap_ulong(unsigned long val) { return _bswap(val); } + + #ifndef FALSE + #define FALSE 0 + #endif + #ifndef TRUE + #define TRUE 1 + #endif +#endif // _WIN32 + +#ifdef _WIN32 + static const bool __isWindows = true; + static const bool __isLinux = false; +#else + static const bool __isWindows = false; + static const bool __isLinux = true; +#endif + +extern void rehlds_syserror(const char* fmt, ...); + +#endif // _OSCONFIG_H diff --git a/rehlds/public/rehlds/progdefs.h b/rehlds/public/rehlds/progdefs.h new file mode 100644 index 0000000..d35382a --- /dev/null +++ b/rehlds/public/rehlds/progdefs.h @@ -0,0 +1,224 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PROGDEFS_H +#define PROGDEFS_H +#ifdef _WIN32 +#pragma once +#endif + +typedef struct globalvars_s +{ + float time; + float frametime; + float force_retouch; + string_t mapname; + string_t startspot; + float deathmatch_; + float coop_; + float teamplay; + float serverflags; + float found_secrets; + vec3_t v_forward; + vec3_t v_up; + vec3_t v_right; + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vec3_t trace_endpos; + vec3_t trace_plane_normal; + float trace_plane_dist; + edict_t *trace_ent; + float trace_inopen; + float trace_inwater; + int trace_hitgroup; + int trace_flags; + int msg_entity; + int cdAudioTrack; + int maxClients; + int maxEntities; + const char *pStringBase; + + void *pSaveData; + vec3_t vecLandmarkOffset; +} globalvars_t; + + +typedef struct entvars_s +{ + string_t classname; + string_t globalname; + + vec3_t origin; + vec3_t oldorigin; + vec3_t velocity; + vec3_t basevelocity; + vec3_t clbasevelocity; // Base velocity that was passed in to server physics so + // client can predict conveyors correctly. Server zeroes it, so we need to store here, too. + vec3_t movedir; + + vec3_t angles; // Model angles + vec3_t avelocity; // angle velocity (degrees per second) + vec3_t punchangle; // auto-decaying view angle adjustment + vec3_t v_angle; // Viewing angle (player only) + + // For parametric entities + vec3_t endpos; + vec3_t startpos; + float impacttime; + float starttime; + + int fixangle; // 0:nothing, 1:force view angles, 2:add avelocity + float idealpitch; + float pitch_speed; + float ideal_yaw; + float yaw_speed; + + int modelindex; + string_t model; + + int viewmodel; // player's viewmodel + int weaponmodel; // what other players see + + vec3_t absmin; // BB max translated to world coord + vec3_t absmax; // BB max translated to world coord + vec3_t mins; // local BB min + vec3_t maxs; // local BB max + vec3_t size; // maxs - mins + + float ltime; + float nextthink; + + int movetype; + int solid; + + int skin; + int body; // sub-model selection for studiomodels + int effects; + + float gravity; // % of "normal" gravity + float friction; // inverse elasticity of MOVETYPE_BOUNCE + + int light_level; + + int sequence; // animation sequence + int gaitsequence; // movement animation sequence for player (0 for none) + float frame; // % playback position in animation sequences (0..255) + float animtime; // world time when frame was set + float framerate; // animation playback rate (-8x to 8x) + byte controller[4]; // bone controller setting (0..255) + byte blending[2]; // blending amount between sub-sequences (0..255) + + float scale; // sprite rendering scale (0..255) + + int rendermode; + float renderamt; + vec3_t rendercolor; + int renderfx; + + float health; + float frags; + int weapons; // bit mask for available weapons + float takedamage; + + int deadflag; + vec3_t view_ofs; // eye position + + int button; + int impulse; + + edict_t *chain; // Entity pointer when linked into a linked list + edict_t *dmg_inflictor; + edict_t *enemy; + edict_t *aiment; // entity pointer when MOVETYPE_FOLLOW + edict_t *owner; + edict_t *groundentity; + + int spawnflags; + int flags; + + int colormap; // lowbyte topcolor, highbyte bottomcolor + int team; + + float max_health; + float teleport_time; + float armortype; + float armorvalue; + int waterlevel; + int watertype; + + string_t target; + string_t targetname; + string_t netname; + string_t message; + + float dmg_take; + float dmg_save; + float dmg; + float dmgtime; + + string_t noise; + string_t noise1; + string_t noise2; + string_t noise3; + + float speed; + float air_finished; + float pain_finished; + float radsuit_finished; + + edict_t *pContainingEntity; + + int playerclass; + float maxspeed; + + float fov; + int weaponanim; + + int pushmsec; + + int bInDuck; + int flTimeStepSound; + int flSwimTime; + int flDuckTime; + int iStepLeft; + float flFallVelocity; + + int gamestate; + + int oldbuttons; + + int groupinfo; + + // For mods + int iuser1; + int iuser2; + int iuser3; + int iuser4; + float fuser1; + float fuser2; + float fuser3; + float fuser4; + vec3_t vuser1; + vec3_t vuser2; + vec3_t vuser3; + vec3_t vuser4; + edict_t *euser1; + edict_t *euser2; + edict_t *euser3; + edict_t *euser4; +} entvars_t; + + +#endif // PROGDEFS_H diff --git a/rehlds/public/rehlds/progs.h b/rehlds/public/rehlds/progs.h new file mode 100644 index 0000000..1d1f885 --- /dev/null +++ b/rehlds/public/rehlds/progs.h @@ -0,0 +1,82 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef PROGS_H +#define PROGS_H + +#include "progdefs.h" + +// 16 simultaneous events, max +#define MAX_EVENT_QUEUE 64 + +#define DEFAULT_EVENT_RESENDS 1 + +#include "event_flags.h" + +typedef struct event_info_s event_info_t; + +#include "event_args.h" + +struct event_info_s +{ + unsigned short index; // 0 implies not in use + + short packet_index; // Use data from state info for entity in delta_packet . -1 implies separate info based on event + // parameter signature + short entity_index; // The edict this event is associated with + + float fire_time; // if non-zero, the time when the event should be fired ( fixed up on the client ) + + event_args_t args; + +// CLIENT ONLY + int flags; // Reliable or not, etc. + +}; + +typedef struct event_state_s event_state_t; + +struct event_state_s +{ + struct event_info_s ei[ MAX_EVENT_QUEUE ]; +}; + +#if !defined( ENTITY_STATEH ) +#include "entity_state.h" +#endif + +#if !defined( EDICT_H ) +#include "edict.h" +#endif + +#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m))) +#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area) + +//============================================================================ + +extern char *pr_strings; +extern globalvars_t gGlobalVariables; + +//============================================================================ + +edict_t *ED_Alloc (void); +void ED_Free (edict_t *ed); +void ED_LoadFromFile (char *data); + +edict_t *EDICT_NUM(int n); +int NUM_FOR_EDICT(const edict_t *e); + +#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e)) + +#endif // PROGS_H diff --git a/rehlds/public/rehlds/rehlds_api.h b/rehlds/public/rehlds/rehlds_api.h new file mode 100644 index 0000000..729e772 --- /dev/null +++ b/rehlds/public/rehlds/rehlds_api.h @@ -0,0 +1,177 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once +#include "maintypes.h" +#include "cmd_rehlds.h" +#include "rehlds_interfaces.h" +#include "hookchains.h" +#include "FlightRecorder.h" +#include "interface.h" +#include "model.h" + +#define REHLDS_API_VERSION_MAJOR 1 +#define REHLDS_API_VERSION_MINOR 0 + +//Steam_NotifyClientConnect hook +typedef IHookChain IRehldsHook_Steam_NotifyClientConnect; +typedef IHookChainRegistry IRehldsHookRegistry_Steam_NotifyClientConnect; + +//SV_ConnectClient hook +typedef IVoidHookChain<> IRehldsHook_SV_ConnectClient; +typedef IVoidHookChainRegistry<> IRehldsHookRegistry_SV_ConnectClient; + +//SV_GetIDString hook +typedef IHookChain IRehldsHook_SV_GetIDString; +typedef IHookChainRegistry IRehldsHookRegistry_SV_GetIDString; + +//SV_SendServerinfo hook +typedef IVoidHookChain IRehldsHook_SV_SendServerinfo; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SV_SendServerinfo; + +//SV_CheckProtocol hook +typedef IHookChain IRehldsHook_SV_CheckProtocol; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckProtocol; + +//SVC_GetChallenge_mod hook +typedef IVoidHookChain IRehldsHook_SVC_GetChallenge_mod; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SVC_GetChallenge_mod; + +//SV_CheckKeyInfo hook +typedef IHookChain IRehldsHook_SV_CheckKeyInfo; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckKeyInfo; + +//SV_CheckIPRestrictions hook +typedef IHookChain IRehldsHook_SV_CheckIPRestrictions; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CheckIPRestrictions; + +//SV_FinishCertificateCheck hook +typedef IHookChain IRehldsHook_SV_FinishCertificateCheck; +typedef IHookChainRegistry IRehldsHookRegistry_SV_FinishCertificateCheck; + +//Steam_NotifyBotConnect hook +typedef IHookChain IRehldsHook_Steam_NotifyBotConnect; +typedef IHookChainRegistry IRehldsHookRegistry_Steam_NotifyBotConnect; + +//SerializeSteamId +typedef IVoidHookChain IRehldsHook_SerializeSteamId; +typedef IVoidHookChainRegistry IRehldsHookRegistry_SerializeSteamId; + +//SV_CompareUserID hook +typedef IHookChain IRehldsHook_SV_CompareUserID; +typedef IHookChainRegistry IRehldsHookRegistry_SV_CompareUserID; + +//Steam_NotifyClientDisconnect +typedef IVoidHookChain IRehldsHook_Steam_NotifyClientDisconnect; +typedef IVoidHookChainRegistry IRehldsHookRegistry_Steam_NotifyClientDisconnect; + +//PreProcessPacket +typedef IHookChain IRehldsHook_PreprocessPacket; +typedef IHookChainRegistry IRehldsHookRegistry_PreprocessPacket; + +//ValidateCommand +typedef IHookChain IRehldsHook_ValidateCommand; +typedef IHookChainRegistry IRehldsHookRegistry_ValidateCommand; + +//ClientConnected +typedef IVoidHookChain IRehldsHook_ClientConnected; +typedef IVoidHookChainRegistry IRehldsHookRegistry_ClientConnected; + +//HandleNetCommand +typedef IVoidHookChain IRehldsHook_HandleNetCommand; +typedef IVoidHookChainRegistry IRehldsHookRegistry_HandleNetCommand; + +//Mod_LoadBrushModel +typedef IVoidHookChain IRehldsHook_Mod_LoadBrushModel; +typedef IVoidHookChainRegistry IRehldsHookRegistry_Mod_LoadBrushModel; + +//Mod_LoadStudioModel +typedef IVoidHookChain IRehldsHook_Mod_LoadStudioModel; +typedef IVoidHookChainRegistry IRehldsHookRegistry_Mod_LoadStudioModel; + +class IRehldsHookchains { +public: + virtual ~IRehldsHookchains() { } + + virtual IRehldsHookRegistry_Steam_NotifyClientConnect* Steam_NotifyClientConnect() = 0; + virtual IRehldsHookRegistry_SV_ConnectClient* SV_ConnectClient() = 0; + virtual IRehldsHookRegistry_SV_GetIDString* SV_GetIDString() = 0; + virtual IRehldsHookRegistry_SV_SendServerinfo* SV_SendServerinfo() = 0; + virtual IRehldsHookRegistry_SV_CheckProtocol* SV_CheckProtocol() = 0; + virtual IRehldsHookRegistry_SVC_GetChallenge_mod* SVC_GetChallenge_mod() = 0; + virtual IRehldsHookRegistry_SV_CheckKeyInfo* SV_CheckKeyInfo() = 0; + virtual IRehldsHookRegistry_SV_CheckIPRestrictions* SV_CheckIPRestrictions() = 0; + virtual IRehldsHookRegistry_SV_FinishCertificateCheck* SV_FinishCertificateCheck() = 0; + virtual IRehldsHookRegistry_Steam_NotifyBotConnect* Steam_NotifyBotConnect() = 0; + virtual IRehldsHookRegistry_SerializeSteamId* SerializeSteamId() = 0; + virtual IRehldsHookRegistry_SV_CompareUserID* SV_CompareUserID() = 0; + virtual IRehldsHookRegistry_Steam_NotifyClientDisconnect* Steam_NotifyClientDisconnect() = 0; + virtual IRehldsHookRegistry_PreprocessPacket* PreprocessPacket() = 0; + virtual IRehldsHookRegistry_ValidateCommand* ValidateCommand() = 0; + virtual IRehldsHookRegistry_ClientConnected* ClientConnected() = 0; + virtual IRehldsHookRegistry_HandleNetCommand* HandleNetCommand() = 0; + virtual IRehldsHookRegistry_Mod_LoadBrushModel* Mod_LoadBrushModel() = 0; + virtual IRehldsHookRegistry_Mod_LoadStudioModel* Mod_LoadStudioModel() = 0; +}; + +struct RehldsFuncs_t { + void(*DropClient)(IGameClient* cl, bool crash, const char* fmt, ...); + void(*RejectConnection)(netadr_t *adr, char *fmt, ...); + qboolean(*SteamNotifyBotConnect)(IGameClient* cl); + sizebuf_t*(*GetNetMessage)(); + IGameClient*(*GetHostClient)(); + int*(*GetMsgReadCount)(); + qboolean(*FilterUser)(USERID_t*); + void(*NET_SendPacket)(unsigned int length, void *data, const netadr_t &to); + void(*TokenizeString)(char* s); + bool(*CheckChallenge)(const netadr_t& adr, int challenge); + void(*SendUserReg)(sizebuf_t* msg); + void(*WriteDeltaDescriptionsToClient)(sizebuf_t* msg); + void(*SetMoveVars)(); + void(*WriteMovevarsToClient)(sizebuf_t* msg); + char*(*GetClientFallback)(); + int*(*GetAllowCheats)(); + bool(*GSBSecure)(); + int(*GetBuildNumber)(); + double(*GetRealTime)(); + int*(*GetMsgBadRead)(); +}; + +class IRehldsApi { +public: + virtual ~IRehldsApi() { } + + virtual int GetMajorVersion() = 0; + virtual int GetMinorVersion() = 0; + virtual const RehldsFuncs_t* GetFuncs() = 0; + virtual IRehldsHookchains* GetHookchains() = 0; + virtual IRehldsServerStatic* GetServerStatic() = 0; + virtual IRehldsServerData* GetServerData() = 0; + virtual IRehldsFlightRecorder* GetFlightRecorder() = 0; +}; + +#define VREHLDS_HLDS_API_VERSION "VREHLDS_HLDS_API_VERSION001" diff --git a/rehlds/public/rehlds/rehlds_interfaces.h b/rehlds/public/rehlds/rehlds_interfaces.h new file mode 100644 index 0000000..063e8c2 --- /dev/null +++ b/rehlds/public/rehlds/rehlds_interfaces.h @@ -0,0 +1,105 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +class INetChan; +class IGameClient; + +#include "maintypes.h" +#include "const.h" +#include "netadr.h" + +#include "common_rehlds.h" +#include "userid_rehlds.h" + +#ifdef REHLDS_SELF +#include "server.h" +#endif + +class INetChan; +class IGameClient; + +class IGameClient { +public: + virtual int GetId() = 0; + + virtual bool IsActive() = 0; + virtual void SetActive(bool active) = 0; + + virtual bool IsSpawned() = 0; + virtual void SetSpawned(bool spawned) = 0; + + virtual INetChan* GetNetChan() = 0; + + virtual sizebuf_t* GetDatagram() = 0; + + virtual edict_t* GetEdict() = 0; + + virtual USERID_t* GetNetworkUserID() = 0; + + virtual const char* GetName() = 0; + + virtual bool IsConnected() = 0; + virtual void SetConnected(bool connected) = 0; + + + // this must be the last virtual function in class +#ifdef REHLDS_SELF + virtual client_t* GetClient() = 0; +#endif +}; + +class INetChan { +public: + virtual const netadr_t* GetRemoteAdr() = 0; + + + // this must be the last virtual function in class +#ifdef REHLDS_SELF + virtual netchan_t* GetChan() = 0; +#endif +}; + +class IRehldsServerStatic { +public: + virtual ~IRehldsServerStatic() { } + + virtual int GetMaxClients() = 0; + virtual bool IsLogActive() = 0; + virtual IGameClient* GetClient(int id) = 0; +}; + +class IRehldsServerData { +public: + virtual ~IRehldsServerData() { } + + virtual const char* GetModelName() = 0; + virtual const char* GetName() = 0; + virtual uint32_t GetWorldmapCrc() = 0; + virtual uint8_t* GetClientDllMd5() = 0; +}; diff --git a/rehlds/public/rehlds/shake.h b/rehlds/public/rehlds/shake.h new file mode 100644 index 0000000..b31f478 --- /dev/null +++ b/rehlds/public/rehlds/shake.h @@ -0,0 +1,57 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#ifndef SHAKE_H +#define SHAKE_H + +// Screen / View effects + +// screen shake +extern int gmsgShake; + +// This structure is sent over the net to describe a screen shake event +typedef struct +{ + unsigned short amplitude; // FIXED 4.12 amount of shake + unsigned short duration; // FIXED 4.12 seconds duration + unsigned short frequency; // FIXED 8.8 noise frequency (low frequency is a jerk,high frequency is a rumble) +} ScreenShake; + +extern void V_ApplyShake( float *origin, float *angles, float factor ); +extern void V_CalcShake( void ); +extern int V_ScreenShake( const char *pszName, int iSize, void *pbuf ); +extern int V_ScreenFade( const char *pszName, int iSize, void *pbuf ); + + +// Fade in/out +extern int gmsgFade; + +#define FFADE_IN 0x0000 // Just here so we don't pass 0 into the function +#define FFADE_OUT 0x0001 // Fade out (not in) +#define FFADE_MODULATE 0x0002 // Modulate (don't blend) +#define FFADE_STAYOUT 0x0004 // ignores the duration, stays faded out until new ScreenFade message received +#define FFADE_LONGFADE 0x0008 // used to indicate the fade can be longer than 16 seconds (added for czero) + + +// This structure is sent over the net to describe a screen fade event +typedef struct +{ + unsigned short duration; // FIXED 4.12 seconds duration + unsigned short holdTime; // FIXED 4.12 seconds duration until reset (fade & hold) + short fadeFlags; // flags + byte r, g, b, a; // fade to color ( max alpha ) +} ScreenFade; + +#endif // SHAKE_H + diff --git a/rehlds/public/rehlds/spritegn.h b/rehlds/public/rehlds/spritegn.h new file mode 100644 index 0000000..59f4f50 --- /dev/null +++ b/rehlds/public/rehlds/spritegn.h @@ -0,0 +1,90 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#ifndef SPRITEGN_H +#define SPRITEGN_H +#ifdef _WIN32 +#pragma once +#endif + +#include "modelgen.h" + + +#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') +#define SPRITE_VERSION 2 + + +typedef enum spriteframetype_e +{ + SPR_SINGLE = 0, + SPR_GROUP, + SPR_ANGLED +} spriteframetype_t; + +/* <4aea6> ../engine/spritegn.h:50 */ +typedef struct dsprite_s +{ + int ident; + int version; + int type; + int texFormat; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dsprite_t; + +/* <4af46> ../engine/spritegn.h:74 */ +typedef struct dspriteframe_s +{ + int origin[2]; + int width; + int height; +} dspriteframe_t; + +/* <4af84> ../engine/spritegn.h:80 */ +typedef struct dspritegroup_s +{ + int numframes; +} dspritegroup_t; + +/* <4afa6> ../engine/spritegn.h:84 */ +typedef struct dspriteinterval_s +{ + float interval; +} dspriteinterval_t; + +/* <4afe8> ../engine/spritegn.h:90 */ +typedef struct dspriteframetype_s +{ + spriteframetype_t type; +} dspriteframetype_t; + +#endif // SPRITEGN_H diff --git a/rehlds/public/rehlds/static_map.h b/rehlds/public/rehlds/static_map.h new file mode 100644 index 0000000..9d57196 --- /dev/null +++ b/rehlds/public/rehlds/static_map.h @@ -0,0 +1,204 @@ +#pragma once + +#include "osconfig.h" +#include "crc32.h" + +template +class CStaticMap { +protected: + virtual uint32_t hash(const T_KEY& val) { + return crc32((const unsigned char*)&val, sizeof(T_KEY)); + } + + virtual bool equals(const T_KEY& val1, const T_KEY& val2) { + return 0 == memcmp(&val1, &val2, sizeof(T_KEY)); + } + + struct map_node_t { + map_node_t* prev; + map_node_t* next; + T_KEY key; + T_VAL val; + }; + +private: + map_node_t* m_RootNodes[1 << ASSOC_2N]; + map_node_t m_AllNodes[MAX_VALS]; + map_node_t* m_FreeRoot; + + unsigned int GetRoodNodeId(const T_KEY& val) { return hash(val) & (0xFFFFFFFF >> (32 - ASSOC_2N)); } + + void unlink(map_node_t* node) { + map_node_t* prev = node->prev; + map_node_t* next = node->next; + + if (prev) { + prev->next = next; + } + + if (next) { + next->prev = prev; + } + + if (!prev) { + // this was a root node + unsigned int rootId = GetRoodNodeId(node->key); + if (m_RootNodes[rootId] != node) { + util_syserror("%s: invlid root node", __FUNCTION__); + return; + } + + m_RootNodes[rootId] = next; + } + } + + void link(map_node_t* node) { + unsigned int rootId = GetRoodNodeId(node->key); + map_node_t* root = m_RootNodes[rootId]; + node->prev = NULL; + node->next = root; + + if (root) { + root->prev = node; + } + + m_RootNodes[rootId] = node; + } + + void linkToFreeStack(map_node_t* node) { + node->next = m_FreeRoot; + if (m_FreeRoot) { + m_FreeRoot->prev = node; + } + m_FreeRoot = node; + } + +public: + CStaticMap() { + clear(); + } + + void clear() { + memset(m_RootNodes, 0, sizeof(m_RootNodes)); + memset(m_AllNodes, 0, sizeof(m_AllNodes)); + m_FreeRoot = NULL; + + for (int i = 0; i < MAX_VALS; i++) { + linkToFreeStack(&m_AllNodes[i]); + } + } + + map_node_t* get(const T_KEY& key) { + unsigned int rootId = GetRoodNodeId(key); + map_node_t* n = m_RootNodes[rootId]; + while (n) { + if (equals(n->key, key)) { + return n; + } + n = n->next; + } + return NULL; + } + + bool put(const T_KEY& key, T_VAL& val) { + map_node_t* n = get(key); + if (n) { + n->val = val; + return true; + } + + if (!m_FreeRoot) { + return false; + } + + n = m_FreeRoot; + m_FreeRoot = m_FreeRoot->next; + + n->key = key; + n->val = val; + + unsigned int rootId = GetRoodNodeId(key); + map_node_t* root = m_RootNodes[rootId]; + + if (root) { + root->prev = n; + } + + n->prev = NULL; + n->next = root; + m_RootNodes[rootId] = n; + + return true; + } + + void remove(map_node_t* node) { + unlink(node); + linkToFreeStack(node); + } + + bool remove(const T_KEY& key) { + map_node_t* n = get(key); + if (!n) { + return false; + } + + remove(n); + return true; + } + + class Iterator { + friend class CStaticMap; + protected: + CStaticMap* m_Map; + map_node_t** m_RootNodes; + unsigned int m_NextRootNode; + map_node_t* m_CurNode; + + void searchForNextNode() { + if (m_CurNode && m_CurNode->next) { + m_CurNode = m_CurNode->next; + return; + } + + m_CurNode = NULL; + while (!m_CurNode) { + if (m_NextRootNode >= (1 << ASSOC_2N)) { + return; + } + m_CurNode = m_RootNodes[m_NextRootNode++]; + } + } + + + Iterator(CStaticMap* m) { + m_Map = m; + m_RootNodes = m_Map->m_RootNodes; + m_NextRootNode = 0; + m_CurNode = NULL; + searchForNextNode(); + } + + public: + map_node_t* next() { + searchForNextNode(); + return m_CurNode; + } + + map_node_t* current() { + return m_CurNode; + } + + void remove() { + m_Map->remove(m_CurNode); + m_CurNode = NULL; + } + + bool hasElement() { + return m_CurNode != NULL; + } + }; + + Iterator iterator() { + return Iterator(this); + } +}; diff --git a/rehlds/public/rehlds/studio.h b/rehlds/public/rehlds/studio.h new file mode 100644 index 0000000..efecde2 --- /dev/null +++ b/rehlds/public/rehlds/studio.h @@ -0,0 +1,358 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#pragma once + +/* +============================================================================== + +STUDIO MODELS + +Studio models are position independent, so the cache manager can move them. +============================================================================== +*/ + + +#define MAXSTUDIOTRIANGLES 20000 // TODO: tune this +#define MAXSTUDIOVERTS 2048 // TODO: tune this +#define MAXSTUDIOSEQUENCES 2048 // total animation sequences +#define MAXSTUDIOSKINS 100 // total textures +#define MAXSTUDIOSRCBONES 512 // bones allowed at source movement +#define MAXSTUDIOBONES 128 // total bones actually used +#define MAXSTUDIOMODELS 32 // sub-models per model +#define MAXSTUDIOBODYPARTS 32 +#define MAXSTUDIOGROUPS 16 +#define MAXSTUDIOANIMATIONS 2048 // per sequence +#define MAXSTUDIOMESHES 256 +#define MAXSTUDIOEVENTS 1024 +#define MAXSTUDIOPIVOTS 256 +#define MAXSTUDIOCONTROLLERS 8 + +typedef struct +{ + int id; + int version; + + char name[64]; + int length; + + vec3_t eyeposition; // ideal eye position + vec3_t min; // ideal movement hull size + vec3_t max; + + vec3_t bbmin; // clipping bounding box + vec3_t bbmax; + + int flags; + + int numbones; // bones + int boneindex; + + int numbonecontrollers; // bone controllers + int bonecontrollerindex; + + int numhitboxes; // complex bounding boxes + int hitboxindex; + + int numseq; // animation sequences + int seqindex; + + int numseqgroups; // demand loaded sequences + int seqgroupindex; + + int numtextures; // raw textures + int textureindex; + int texturedataindex; + + int numskinref; // replaceable textures + int numskinfamilies; + int skinindex; + + int numbodyparts; + int bodypartindex; + + int numattachments; // queryable attachable points + int attachmentindex; + + int soundtable; + int soundindex; + int soundgroups; + int soundgroupindex; + + int numtransitions; // animation node to animation node transition graph + int transitionindex; +} studiohdr_t; + +// header for demand loaded sequence group data +typedef struct +{ + int id; + int version; + + char name[64]; + int length; +} studioseqhdr_t; + +// bones +typedef struct +{ + char name[32]; // bone name for symbolic links + int parent; // parent bone + int flags; // ?? + int bonecontroller[6]; // bone controller index, -1 == none + float value[6]; // default DoF values + float scale[6]; // scale for delta DoF values +} mstudiobone_t; + + +// bone controllers +typedef struct +{ + int bone; // -1 == 0 + int type; // X, Y, Z, XR, YR, ZR, M + float start; + float end; + int rest; // byte index value at rest + int index; // 0-3 user set controller, 4 mouth +} mstudiobonecontroller_t; + +// intersection boxes +typedef struct +{ + int bone; + int group; // intersection group + vec3_t bbmin; // bounding box + vec3_t bbmax; +} mstudiobbox_t; + +// demand loaded sequence groups +typedef struct +{ + char label[32]; // textual name + char name[64]; // file name + int32_t unused1; // was "cache" - index pointer + int unused2; // was "data" - hack for group 0 +} mstudioseqgroup_t; + +// sequence descriptions +typedef struct +{ + char label[32]; // sequence label + + float fps; // frames per second + int flags; // looping/non-looping flags + + int activity; + int actweight; + + int numevents; + int eventindex; + + int numframes; // number of frames per sequence + + int numpivots; // number of foot pivots + int pivotindex; + + int motiontype; + int motionbone; + vec3_t linearmovement; + int automoveposindex; + int automoveangleindex; + + vec3_t bbmin; // per sequence bounding box + vec3_t bbmax; + + int numblends; + int animindex; // mstudioanim_t pointer relative to start of sequence group data + // [blend][bone][X, Y, Z, XR, YR, ZR] + + int blendtype[2]; // X, Y, Z, XR, YR, ZR + float blendstart[2]; // starting value + float blendend[2]; // ending value + int blendparent; + + int seqgroup; // sequence group for demand loading + + int entrynode; // transition node at entry + int exitnode; // transition node at exit + int nodeflags; // transition rules + + int nextseq; // auto advancing sequences +} mstudioseqdesc_t; + +// events +#include "studio_event.h" +/* +typedef struct +{ + int frame; + int event; + int type; + char options[64]; +} mstudioevent_t; +*/ + +// pivots +typedef struct +{ + vec3_t org; // pivot point + int start; + int end; +} mstudiopivot_t; + +// attachment +typedef struct +{ + char name[32]; + int type; + int bone; + vec3_t org; // attachment point + vec3_t vectors[3]; +} mstudioattachment_t; + +typedef struct +{ + unsigned short offset[6]; +} mstudioanim_t; + +// animation frames +typedef union +{ + struct { + byte valid; + byte total; + } num; + short value; +} mstudioanimvalue_t; + + + +// body part index +typedef struct +{ + char name[64]; + int nummodels; + int base; + int modelindex; // index into models array +} mstudiobodyparts_t; + + + +// skin info +typedef struct +{ + char name[64]; + int flags; + int width; + int height; + int index; +} mstudiotexture_t; + + +// skin families +// short index[skinfamilies][skinref] + +// studio models +typedef struct +{ + char name[64]; + + int type; + + float boundingradius; + + int nummesh; + int meshindex; + + int numverts; // number of unique vertices + int vertinfoindex; // vertex bone info + int vertindex; // vertex vec3_t + int numnorms; // number of unique surface normals + int norminfoindex; // normal bone info + int normindex; // normal vec3_t + + int numgroups; // deformation groups + int groupindex; +} mstudiomodel_t; + + +// vec3_t boundingbox[model][bone][2]; // complex intersection info + + +// meshes +typedef struct +{ + int numtris; + int triindex; + int skinref; + int numnorms; // per mesh normals + int normindex; // normal vec3_t +} mstudiomesh_t; + +// triangles +#if 0 +typedef struct +{ + short vertindex; // index into vertex array + short normindex; // index into normal array + short s,t; // s,t position on skin +} mstudiotrivert_t; +#endif + +// lighting options +#define STUDIO_NF_FLATSHADE 0x0001 +#define STUDIO_NF_CHROME 0x0002 +#define STUDIO_NF_FULLBRIGHT 0x0004 +#define STUDIO_NF_NOMIPS 0x0008 +#define STUDIO_NF_ALPHA 0x0010 +#define STUDIO_NF_ADDITIVE 0x0020 +#define STUDIO_NF_MASKED 0x0040 + +// motion flags +#define STUDIO_X 0x0001 +#define STUDIO_Y 0x0002 +#define STUDIO_Z 0x0004 +#define STUDIO_XR 0x0008 +#define STUDIO_YR 0x0010 +#define STUDIO_ZR 0x0020 +#define STUDIO_LX 0x0040 +#define STUDIO_LY 0x0080 +#define STUDIO_LZ 0x0100 +#define STUDIO_AX 0x0200 +#define STUDIO_AY 0x0400 +#define STUDIO_AZ 0x0800 +#define STUDIO_AXR 0x1000 +#define STUDIO_AYR 0x2000 +#define STUDIO_AZR 0x4000 +#define STUDIO_TYPES 0x7FFF +#define STUDIO_RLOOP 0x8000 // controller that wraps shortest distance + +// sequence flags +#define STUDIO_LOOPING 0x0001 + +// bone flags +#define STUDIO_HAS_NORMALS 0x0001 +#define STUDIO_HAS_VERTICES 0x0002 +#define STUDIO_HAS_BBOX 0x0004 +#define STUDIO_HAS_CHROME 0x0008 // if any of the textures have chrome on them + +#define RAD_TO_STUDIO (32768.0/M_PI) +#define STUDIO_TO_RAD (M_PI/32768.0) + + +#define STUDIO_NUM_HULLS 128 +#define STUDIO_NUM_PLANES (STUDIO_NUM_HULLS * 6) +#define STUDIO_CACHE_SIZE 16 + + diff --git a/rehlds/public/rehlds/sys_shared.cpp b/rehlds/public/rehlds/sys_shared.cpp new file mode 100644 index 0000000..95d80d6 --- /dev/null +++ b/rehlds/public/rehlds/sys_shared.cpp @@ -0,0 +1,45 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#include "precompiled.h" + +bool Sys_ChechSSE42Support(); + +bool g_HasSSE42 = Sys_ChechSSE42Support(); + + +bool Sys_ChechSSE42Support() { + unsigned int cpuid_data[4]; + +#if defined(__GNUC__) + __get_cpuid(0x1, &cpuid_data[0], &cpuid_data[1], &cpuid_data[2], &cpuid_data[3]); +#else //__GNUC__ + __cpuidex((int*)cpuid_data, 1, 0); +#endif //__GNUC__ + + return (0 != (cpuid_data[2] & (1 << 20))); +} diff --git a/rehlds/public/rehlds/sys_shared.h b/rehlds/public/rehlds/sys_shared.h new file mode 100644 index 0000000..a5574d4 --- /dev/null +++ b/rehlds/public/rehlds/sys_shared.h @@ -0,0 +1,31 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once +#include "maintypes.h" + +extern bool g_HasSSE42; diff --git a/rehlds/public/rehlds/userid_rehlds.h b/rehlds/public/rehlds/userid_rehlds.h new file mode 100644 index 0000000..63161b9 --- /dev/null +++ b/rehlds/public/rehlds/userid_rehlds.h @@ -0,0 +1,39 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "maintypes.h" + + +/* <2e915> ../engine/userid.h:22 */ +typedef struct USERID_s +{ + int idtype; + uint64_t m_SteamID; + unsigned int clientip; +} USERID_t; diff --git a/rehlds/public/savegame_version.h b/rehlds/public/savegame_version.h new file mode 100644 index 0000000..8cf2be5 --- /dev/null +++ b/rehlds/public/savegame_version.h @@ -0,0 +1,17 @@ +//========= Copyright 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( SAVEGAME_VERSION_H ) +#define SAVEGAME_VERSION_H +#ifdef _WIN32 +#pragma once +#endif + +#define SAVEFILE_HEADER MAKEID('V','A','L','V') // little-endian "VALV" +#define SAVEGAME_VERSION 0x0071 // Version 0.71 + +#endif // SAVEGAME_VERSION_H diff --git a/rehlds/public/steam/isteamapps.h b/rehlds/public/steam/isteamapps.h new file mode 100644 index 0000000..4b98519 --- /dev/null +++ b/rehlds/public/steam/isteamapps.h @@ -0,0 +1,127 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to app data in Steam +// +//============================================================================= + +#ifndef ISTEAMAPPS_H +#define ISTEAMAPPS_H +#ifdef _WIN32 +#pragma once +#endif + +const int k_cubAppProofOfPurchaseKeyMax = 64; // max bytes of a legacy cd key we support + + +//----------------------------------------------------------------------------- +// Purpose: interface to app data +//----------------------------------------------------------------------------- +class ISteamApps +{ +public: + virtual bool BIsSubscribed() = 0; + virtual bool BIsLowViolence() = 0; + virtual bool BIsCybercafe() = 0; + virtual bool BIsVACBanned() = 0; + virtual const char *GetCurrentGameLanguage() = 0; + virtual const char *GetAvailableGameLanguages() = 0; + + // only use this member if you need to check ownership of another game related to yours, a demo for example + virtual bool BIsSubscribedApp( AppId_t appID ) = 0; + + // Takes AppID of DLC and checks if the user owns the DLC & if the DLC is installed + virtual bool BIsDlcInstalled( AppId_t appID ) = 0; + + // returns the Unix time of the purchase of the app + virtual uint32 GetEarliestPurchaseUnixTime( AppId_t nAppID ) = 0; + + // Checks if the user is subscribed to the current app through a free weekend + // This function will return false for users who have a retail or other type of license + // Before using, please ask your Valve technical contact how to package and secure your free weekened + virtual bool BIsSubscribedFromFreeWeekend() = 0; + + // Returns the number of DLC pieces for the running app + virtual int GetDLCCount() = 0; + + // Returns metadata for DLC by index, of range [0, GetDLCCount()] + virtual bool BGetDLCDataByIndex( int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize ) = 0; + + // Install/Uninstall control for optional DLC + virtual void InstallDLC( AppId_t nAppID ) = 0; + virtual void UninstallDLC( AppId_t nAppID ) = 0; + + // Request cd-key for yourself or owned DLC. If you are interested in this + // data then make sure you provide us with a list of valid keys to be distributed + // to users when they purchase the game, before the game ships. + // You'll receive an AppProofOfPurchaseKeyResponse_t callback when + // the key is available (which may be immediately). + virtual void RequestAppProofOfPurchaseKey( AppId_t nAppID ) = 0; + + virtual bool GetCurrentBetaName( char *pchName, int cchNameBufferSize ) = 0; // returns current beta branch name, 'public' is the default branch + virtual bool MarkContentCorrupt( bool bMissingFilesOnly ) = 0; // signal Steam that game files seems corrupt or missing + virtual uint32 GetInstalledDepots( DepotId_t *pvecDepots, uint32 cMaxDepots ) = 0; // return installed depots in mount order + + // returns current app install folder for AppID, returns folder name length + virtual uint32 GetAppInstallDir( AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize ) = 0; + +#ifdef _PS3 + // Result returned in a RegisterActivationCodeResponse_t callresult + virtual SteamAPICall_t RegisterActivationCode( const char *pchActivationCode ) = 0; +#endif +}; + +#define STEAMAPPS_INTERFACE_VERSION "STEAMAPPS_INTERFACE_VERSION005" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +//----------------------------------------------------------------------------- +// Purpose: posted after the user gains ownership of DLC & that DLC is installed +//----------------------------------------------------------------------------- +struct DlcInstalled_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 5 }; + AppId_t m_nAppID; // AppID of the DLC +}; + + +//----------------------------------------------------------------------------- +// Purpose: possible results when registering an activation code +//----------------------------------------------------------------------------- +enum ERegisterActivationCodeResult +{ + k_ERegisterActivationCodeResultOK = 0, + k_ERegisterActivationCodeResultFail = 1, + k_ERegisterActivationCodeResultAlreadyRegistered = 2, + k_ERegisterActivationCodeResultTimeout = 3, + k_ERegisterActivationCodeAlreadyOwned = 4, +}; + + +//----------------------------------------------------------------------------- +// Purpose: response to RegisterActivationCode() +//----------------------------------------------------------------------------- +struct RegisterActivationCodeResponse_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 8 }; + ERegisterActivationCodeResult m_eResult; + uint32 m_unPackageRegistered; // package that was registered. Only set on success +}; + +//----------------------------------------------------------------------------- +// Purpose: response to RegisterActivationCode() +//----------------------------------------------------------------------------- +struct AppProofOfPurchaseKeyResponse_t +{ + enum { k_iCallback = k_iSteamAppsCallbacks + 13 }; + EResult m_eResult; + uint32 m_nAppID; + char m_rgchKey[ k_cubAppProofOfPurchaseKeyMax ]; +}; +#pragma pack( pop ) +#endif // ISTEAMAPPS_H diff --git a/rehlds/public/steam/isteambilling.h b/rehlds/public/steam/isteambilling.h new file mode 100644 index 0000000..503846c --- /dev/null +++ b/rehlds/public/steam/isteambilling.h @@ -0,0 +1,108 @@ +//====== Copyright © 1996-2004, Valve Corporation, All rights reserved. ======= +// +// Purpose: interface to Billings data in Steam +// +//============================================================================= + +#ifndef ISTEAMBILLING_H +#define ISTEAMBILLING_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: interface to billing +//----------------------------------------------------------------------------- +class ISteamBilling +{ +public: + // Sets the billing address in the ISteamBilling object for use by other ISteamBilling functions (not stored on server) + virtual bool SetBillingAddress( const char *pchName, + const char *pchAddress1, + const char *pchAddress2, + const char *pchCity, + const char *pchPostcode, + const char *pchState, + const char *pchCountry, + const char *pchPhone ) = 0; + // Gets any previous set billing address in the ISteamBilling object (not stored on server) + virtual bool GetBillingAddress( char *pchName, + char *pchAddress1, + char *pchAddress2, + char *pchCity, + char *pchPostcode, + char *pchState, + char *pchCountry, + char *pchPhone ) = 0; + // Sets the billing address in the ISteamBilling object for use by other ISteamBilling functions (not stored on server) + virtual bool SetShippingAddress( const char *pchName, + const char *pchAddress1, + const char *pchAddress2, + const char *pchCity, + const char *pchPostcode, + const char *pchState, + const char *pchCountry, + const char *pchPhone ) = 0; + // Gets any previous set billing address in the ISteamBilling object (not stored on server) + virtual bool GetShippingAddress( char *pchName, + char *pchAddress1, + char *pchAddress2, + char *pchCity, + char *pchPostcode, + char *pchState, + char *pchCountry, + char *pchPhone ) = 0; + // Ask the server for the final price of package: requires that ISteamBilling billing & shipping address are set (can be same) + virtual bool GetFinalPrice( int32 nPackageID ) = 0; + + // Sets the credit card info in the ISteamBilling object for use by other ISteamBilling functions (may eventually also be stored on server) + virtual bool SetCardInfo( int32 eCreditCardType, + const char *pchCardNumber, + const char *pchCardHolderName, + const char *pchCardExpYear, + const char *pchCardExpMonth, + const char *pchCardCVV2 ) = 0; + // Gets any credit card info in the ISteamBilling object (not stored on server) + virtual bool GetCardInfo( int32 *eCreditCardType, + char *pchCardNumber, + char *pchCardHolderName, + char *pchCardExpYear, + char *pchCardExpMonth, + char *pchCardCVV2 ) = 0; + + // Ask the server to purchase a package: requires that ISteamBilling cardinfo, billing & shipping address are set + virtual bool Purchase( int32 nPackageID, + int32 nExpectedCostCents, + uint64 gidCardID, // if non-NIL, use a server stored card + bool bStoreCardInfo ) = 0; // Should this cardinfo also be stored on the server +}; + + +#define STEAMBILLING_INTERFACE_VERSION "SteamBilling001" + + +enum { k_iSteamBillingCallbacks = 400 }; + +//----------------------------------------------------------------------------- +// Purpose: called when this client has received a finalprice message from a Billing +//----------------------------------------------------------------------------- +struct FinalPriceMsg_t +{ + enum { k_iCallback = k_iSteamBillingCallbacks + 1 }; + + uint32 m_bSuccess; + uint32 m_nBaseCost; + uint32 m_nTotalDiscount; + uint32 m_nTax; + uint32 m_nShippingCost; +}; + +struct PurchaseMsg_t +{ + enum { k_iCallback = k_iSteamBillingCallbacks + 2 }; + + uint32 m_bSuccess; + int32 m_EPurchaseResultDetail; // Detailed result information +}; + +#endif // ISTEAMBILLING_H diff --git a/rehlds/public/steam/isteamclient.h b/rehlds/public/steam/isteamclient.h new file mode 100644 index 0000000..952b1eb --- /dev/null +++ b/rehlds/public/steam/isteamclient.h @@ -0,0 +1,349 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Main interface for loading and accessing Steamworks API's from the +// Steam client. +// For most uses, this code is wrapped inside of SteamAPI_Init() +//============================================================================= + +#ifndef ISTEAMCLIENT_H +#define ISTEAMCLIENT_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steamtypes.h" +#include "steamclientpublic.h" + +// Define compile time assert macros to let us validate the structure sizes. +#define VALVE_COMPILE_TIME_ASSERT( pred ) typedef char compile_time_assert_type[(pred) ? 1 : -1]; + +#if defined(__linux__) || defined(__APPLE__) +// The 32-bit version of gcc has the alignment requirement for uint64 and double set to +// 4 meaning that even with #pragma pack(8) these types will only be four-byte aligned. +// The 64-bit version of gcc has the alignment requirement for these types set to +// 8 meaning that unless we use #pragma pack(4) our structures will get bigger. +// The 64-bit structure packing has to match the 32-bit structure packing for each platform. +#define VALVE_CALLBACK_PACK_SMALL +#else +#define VALVE_CALLBACK_PACK_LARGE +#endif + +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error ??? +#endif + +typedef struct +{ + uint32 m_u32; + uint64 m_u64; + uint16 m_u16; + double m_d; +} ValvePackingSentinel_t; + +#pragma pack( pop ) + + +#if defined(VALVE_CALLBACK_PACK_SMALL) +VALVE_COMPILE_TIME_ASSERT( sizeof(ValvePackingSentinel_t) == 24 ) +#elif defined(VALVE_CALLBACK_PACK_LARGE) +VALVE_COMPILE_TIME_ASSERT( sizeof(ValvePackingSentinel_t) == 32 ) +#else +#error ??? +#endif + + +// handle to a communication pipe to the Steam client +typedef int32 HSteamPipe; +// handle to single instance of a steam user +typedef int32 HSteamUser; +// function prototype +#if defined( POSIX ) +#define __cdecl +#endif +extern "C" typedef void (__cdecl *SteamAPIWarningMessageHook_t)(int, const char *); + +#if defined( __SNC__ ) + #pragma diag_suppress=1700 // warning 1700: class "%s" has virtual functions but non-virtual destructor +#endif + +// interface predec +class ISteamUser; +class ISteamGameServer; +class ISteamFriends; +class ISteamUtils; +class ISteamMatchmaking; +class ISteamContentServer; +class ISteamMatchmakingServers; +class ISteamUserStats; +class ISteamApps; +class ISteamNetworking; +class ISteamRemoteStorage; +class ISteamScreenshots; +class ISteamGameServerStats; +class ISteamPS3OverlayRender; +class ISteamHTTP; +class ISteamUnifiedMessages; + +//----------------------------------------------------------------------------- +// Purpose: Interface to creating a new steam instance, or to +// connect to an existing steam instance, whether it's in a +// different process or is local. +// +// For most scenarios this is all handled automatically via SteamAPI_Init(). +// You'll only need to use these interfaces if you have a more complex versioning scheme, +// where you want to get different versions of the same interface in different dll's in your project. +//----------------------------------------------------------------------------- +class ISteamClient +{ +public: + // Creates a communication pipe to the Steam client + virtual HSteamPipe CreateSteamPipe() = 0; + + // Releases a previously created communications pipe + virtual bool BReleaseSteamPipe( HSteamPipe hSteamPipe ) = 0; + + // connects to an existing global user, failing if none exists + // used by the game to coordinate with the steamUI + virtual HSteamUser ConnectToGlobalUser( HSteamPipe hSteamPipe ) = 0; + + // used by game servers, create a steam user that won't be shared with anyone else + virtual HSteamUser CreateLocalUser( HSteamPipe *phSteamPipe, EAccountType eAccountType ) = 0; + + // removes an allocated user + virtual void ReleaseUser( HSteamPipe hSteamPipe, HSteamUser hUser ) = 0; + + // retrieves the ISteamUser interface associated with the handle + virtual ISteamUser *GetISteamUser( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // retrieves the ISteamGameServer interface associated with the handle + virtual ISteamGameServer *GetISteamGameServer( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // set the local IP and Port to bind to + // this must be set before CreateLocalUser() + virtual void SetLocalIPBinding( uint32 unIP, uint16 usPort ) = 0; + + // returns the ISteamFriends interface + virtual ISteamFriends *GetISteamFriends( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamUtils interface + virtual ISteamUtils *GetISteamUtils( HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamMatchmaking interface + virtual ISteamMatchmaking *GetISteamMatchmaking( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamMatchmakingServers interface + virtual ISteamMatchmakingServers *GetISteamMatchmakingServers( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the a generic interface + virtual void *GetISteamGenericInterface( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamUserStats interface + virtual ISteamUserStats *GetISteamUserStats( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns the ISteamGameServerStats interface + virtual ISteamGameServerStats *GetISteamGameServerStats( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // returns apps interface + virtual ISteamApps *GetISteamApps( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // networking + virtual ISteamNetworking *GetISteamNetworking( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // remote storage + virtual ISteamRemoteStorage *GetISteamRemoteStorage( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // user screenshots + virtual ISteamScreenshots *GetISteamScreenshots( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + + // this needs to be called every frame to process matchmaking results + // redundant if you're already calling SteamAPI_RunCallbacks() + virtual void RunFrame() = 0; + + // returns the number of IPC calls made since the last time this function was called + // Used for perf debugging so you can understand how many IPC calls your game makes per frame + // Every IPC call is at minimum a thread context switch if not a process one so you want to rate + // control how often you do them. + virtual uint32 GetIPCCallCount() = 0; + + // API warning handling + // 'int' is the severity; 0 for msg, 1 for warning + // 'const char *' is the text of the message + // callbacks will occur directly after the API function is called that generated the warning or message + virtual void SetWarningMessageHook( SteamAPIWarningMessageHook_t pFunction ) = 0; + + // Trigger global shutdown for the DLL + virtual bool BShutdownIfAllPipesClosed() = 0; + +#ifdef _PS3 + virtual ISteamPS3OverlayRender *GetISteamPS3OverlayRender() = 0; +#endif + + // Expose HTTP interface + virtual ISteamHTTP *GetISteamHTTP( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + + // Exposes the ISteamUnifiedMessages interface + virtual ISteamUnifiedMessages *GetISteamUnifiedMessages( HSteamUser hSteamuser, HSteamPipe hSteamPipe, const char *pchVersion ) = 0; + +}; + +#define STEAMCLIENT_INTERFACE_VERSION "SteamClient012" + +//----------------------------------------------------------------------------- +// Purpose: Base values for callback identifiers, each callback must +// have a unique ID. +//----------------------------------------------------------------------------- +enum { k_iSteamUserCallbacks = 100 }; +enum { k_iSteamGameServerCallbacks = 200 }; +enum { k_iSteamFriendsCallbacks = 300 }; +enum { k_iSteamBillingCallbacks = 400 }; +enum { k_iSteamMatchmakingCallbacks = 500 }; +enum { k_iSteamContentServerCallbacks = 600 }; +enum { k_iSteamUtilsCallbacks = 700 }; +enum { k_iClientFriendsCallbacks = 800 }; +enum { k_iClientUserCallbacks = 900 }; +enum { k_iSteamAppsCallbacks = 1000 }; +enum { k_iSteamUserStatsCallbacks = 1100 }; +enum { k_iSteamNetworkingCallbacks = 1200 }; +enum { k_iClientRemoteStorageCallbacks = 1300 }; +enum { k_iSteamUserItemsCallbacks = 1400 }; +enum { k_iSteamGameServerItemsCallbacks = 1500 }; +enum { k_iClientUtilsCallbacks = 1600 }; +enum { k_iSteamGameCoordinatorCallbacks = 1700 }; +enum { k_iSteamGameServerStatsCallbacks = 1800 }; +enum { k_iSteam2AsyncCallbacks = 1900 }; +enum { k_iSteamGameStatsCallbacks = 2000 }; +enum { k_iClientHTTPCallbacks = 2100 }; +enum { k_iClientScreenshotsCallbacks = 2200 }; +enum { k_iSteamScreenshotsCallbacks = 2300 }; +enum { k_iClientAudioCallbacks = 2400 }; +enum { k_iClientUnifiedMessagesCallbacks = 2500 }; +enum { k_iSteamStreamLauncherCallbacks = 2600 }; +enum { k_iClientControllerCallbacks = 2700 }; +enum { k_iSteamControllerCallbacks = 2800 }; +enum { k_iClientParentalSettingsCallbacks = 2900 }; +enum { k_iClientDeviceAuthCallbacks = 3000 }; +enum { k_iClientNetworkDeviceManagerCallbacks = 3100 }; + + +//----------------------------------------------------------------------------- +// The CALLBACK macros are for client side callback logging enabled with +// log_callback +// Do not change any of these. +//----------------------------------------------------------------------------- + +class CSteamCallback +{ +public: + virtual const char *GetCallbackName() const = 0; + virtual uint32 GetCallbackID() const = 0; + virtual uint8 *GetFixedData() const = 0; + virtual uint32 GetFixedSize() const = 0; + virtual uint32 GetNumMemberVariables() const = 0; + virtual bool GetMemberVariable( uint32 index, uint32 &varOffset, uint32 &varSize, uint32 &varCount, const char **pszName, const char **pszType ) const = 0; +}; + +#define DEFINE_CALLBACK( callbackname, callbackid ) \ +struct callbackname##_t { \ + enum { k_iCallback = callbackid }; \ + static callbackname##_t *GetNullPointer() { return 0; } + +#define CALLBACK_MEMBER( varidx, vartype, varname ) \ + public: vartype varname ; \ + static void GetMemberVar_##varidx( unsigned int &varOffset, unsigned int &varSize, uint32 &varCount, const char **pszName, const char **pszType ) { \ + varOffset = (unsigned int)(size_t)&GetNullPointer()->varname; \ + varSize = sizeof( vartype ); \ + varCount = 1; \ + *pszName = #varname; *pszType = #vartype; } + +#define CALLBACK_ARRAY( varidx, vartype, varname, varcount ) \ + public: vartype varname [ varcount ]; \ + static void GetMemberVar_##varidx( unsigned int &varOffset, unsigned int &varSize, uint32 &varCount, const char **pszName, const char **pszType ) { \ + varOffset = (unsigned int)(size_t)&GetNullPointer()->varname[0]; \ + varSize = sizeof( vartype ); \ + varCount = varcount; \ + *pszName = #varname; *pszType = #vartype; } + + +#define END_CALLBACK_INTERNAL_BEGIN( callbackname, numvars ) }; \ +class C##callbackname : public CSteamCallback { \ +public: callbackname##_t m_Data; \ + C##callbackname () { memset( &m_Data, 0, sizeof(m_Data) ); } \ + virtual const char *GetCallbackName() const { return #callbackname; } \ + virtual uint32 GetCallbackID() const { return callbackname##_t::k_iCallback; } \ + virtual uint32 GetFixedSize() const { return sizeof( m_Data ); } \ + virtual uint8 *GetFixedData() const { return (uint8*)&m_Data; } \ + virtual uint32 GetNumMemberVariables() const { return numvars; } \ + virtual bool GetMemberVariable( uint32 index, uint32 &varOffset, uint32 &varSize, uint32 &varCount, const char **pszName, const char **pszType ) const { \ + switch ( index ) { default : return false; + + +#define END_CALLBACK_INTERNAL_SWITCH( varidx ) case varidx : m_Data.GetMemberVar_##varidx( varOffset, varSize, varCount, pszName, pszType ); return true; + +#define END_CALLBACK_INTERNAL_END() }; }; }; + +#define END_DEFINE_CALLBACK_0( callbackname ) }; \ +class C##callbackname : public CSteamCallback { \ +public: callbackname##_t m_Data; \ + virtual const char *GetCallbackName() const { return #callbackname; } \ + virtual uint32 GetCallbackID() const { return callbackname##_t::k_iCallback; } \ + virtual uint32 GetFixedSize() const { return sizeof( m_Data ); } \ + virtual uint8 *GetFixedData() const { return (uint8*)&m_Data; } \ + virtual uint32 GetNumMemberVariables() const { return 0; } \ + virtual bool GetMemberVariable( uint32 index, uint32 &varOffset, uint32 &varSize, uint32 &varCount, const char **pszName, const char **pszType ) const { return false; } \ + }; \ + + +#define END_DEFINE_CALLBACK_1( callbackname ) \ + END_CALLBACK_INTERNAL_BEGIN( callbackname, 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_2( callbackname ) \ + END_CALLBACK_INTERNAL_BEGIN( callbackname, 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_3( callbackname ) \ + END_CALLBACK_INTERNAL_BEGIN( callbackname, 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_4( callbackname ) \ + END_CALLBACK_INTERNAL_BEGIN( callbackname, 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_END() + + +#define END_DEFINE_CALLBACK_6( callbackname ) \ + END_CALLBACK_INTERNAL_BEGIN( callbackname, 6 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_END() + +#define END_DEFINE_CALLBACK_7( callbackname ) \ + END_CALLBACK_INTERNAL_BEGIN( callbackname, 7 ) \ + END_CALLBACK_INTERNAL_SWITCH( 0 ) \ + END_CALLBACK_INTERNAL_SWITCH( 1 ) \ + END_CALLBACK_INTERNAL_SWITCH( 2 ) \ + END_CALLBACK_INTERNAL_SWITCH( 3 ) \ + END_CALLBACK_INTERNAL_SWITCH( 4 ) \ + END_CALLBACK_INTERNAL_SWITCH( 5 ) \ + END_CALLBACK_INTERNAL_SWITCH( 6 ) \ + END_CALLBACK_INTERNAL_END() + +#endif // ISTEAMCLIENT_H diff --git a/rehlds/public/steam/isteamcontroller.h b/rehlds/public/steam/isteamcontroller.h new file mode 100644 index 0000000..6c2e117 --- /dev/null +++ b/rehlds/public/steam/isteamcontroller.h @@ -0,0 +1,62 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to valve controller +// +//============================================================================= + +#ifndef ISTEAMCONTROLLER_H +#define ISTEAMCONTROLLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +#pragma pack( pop ) + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing stats, achievements, and leaderboard information +//----------------------------------------------------------------------------- +class ISteamController +{ +public: + +}; + +#define STEAMCONTROLLER_INTERFACE_VERSION "STEAMCONTROLLER_INTERFACE_VERSION" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +/* +struct ControllerCallback_t +{ + enum { k_iCallback = k_iSteamControllerCallbacks + 1 }; + +}; +*/ + + +#pragma pack( pop ) + + +#endif // ISTEAMCONTROLLER_H diff --git a/rehlds/public/steam/isteamfriends.h b/rehlds/public/steam/isteamfriends.h new file mode 100644 index 0000000..6e8ad0c --- /dev/null +++ b/rehlds/public/steam/isteamfriends.h @@ -0,0 +1,606 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to both friends list data and general information about users +// +//============================================================================= + +#ifndef ISTEAMFRIENDS_H +#define ISTEAMFRIENDS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "steamclientpublic.h" + + +//----------------------------------------------------------------------------- +// Purpose: set of relationships to other users +//----------------------------------------------------------------------------- +enum EFriendRelationship +{ + k_EFriendRelationshipNone = 0, + k_EFriendRelationshipBlocked = 1, + k_EFriendRelationshipRequestRecipient = 2, + k_EFriendRelationshipFriend = 3, + k_EFriendRelationshipRequestInitiator = 4, + k_EFriendRelationshipIgnored = 5, + k_EFriendRelationshipIgnoredFriend = 6, + k_EFriendRelationshipSuggested = 7, + + // keep this updated + k_EFriendRelationshipMax = 8, +}; + +// maximum length of friend group name (not including terminating nul!) +const int k_cchMaxFriendsGroupName = 64; + +// maximum number of groups a single user is allowed +const int k_cFriendsGroupLimit = 100; + +const int k_cEnumerateFollowersMax = 50; + + +//----------------------------------------------------------------------------- +// Purpose: list of states a friend can be in +//----------------------------------------------------------------------------- +enum EPersonaState +{ + k_EPersonaStateOffline = 0, // friend is not currently logged on + k_EPersonaStateOnline = 1, // friend is logged on + k_EPersonaStateBusy = 2, // user is on, but busy + k_EPersonaStateAway = 3, // auto-away feature + k_EPersonaStateSnooze = 4, // auto-away for a long time + k_EPersonaStateLookingToTrade = 5, // Online, trading + k_EPersonaStateLookingToPlay = 6, // Online, wanting to play + k_EPersonaStateMax, +}; + + +//----------------------------------------------------------------------------- +// Purpose: flags for enumerating friends list, or quickly checking a the relationship between users +//----------------------------------------------------------------------------- +enum EFriendFlags +{ + k_EFriendFlagNone = 0x00, + k_EFriendFlagBlocked = 0x01, + k_EFriendFlagFriendshipRequested = 0x02, + k_EFriendFlagImmediate = 0x04, // "regular" friend + k_EFriendFlagClanMember = 0x08, + k_EFriendFlagOnGameServer = 0x10, + // k_EFriendFlagHasPlayedWith = 0x20, // not currently used + // k_EFriendFlagFriendOfFriend = 0x40, // not currently used + k_EFriendFlagRequestingFriendship = 0x80, + k_EFriendFlagRequestingInfo = 0x100, + k_EFriendFlagIgnored = 0x200, + k_EFriendFlagIgnoredFriend = 0x400, + k_EFriendFlagSuggested = 0x800, + k_EFriendFlagAll = 0xFFFF, +}; + + +// friend game played information +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct FriendGameInfo_t +{ + CGameID m_gameID; + uint32 m_unGameIP; + uint16 m_usGamePort; + uint16 m_usQueryPort; + CSteamID m_steamIDLobby; +}; +#pragma pack( pop ) + +// maximum number of characters in a user's name. Two flavors; one for UTF-8 and one for UTF-16. +// The UTF-8 version has to be very generous to accomodate characters that get large when encoded +// in UTF-8. +enum +{ + k_cchPersonaNameMax = 128, + k_cwchPersonaNameMax = 32, +}; + +//----------------------------------------------------------------------------- +// Purpose: user restriction flags +//----------------------------------------------------------------------------- +enum EUserRestriction +{ + k_nUserRestrictionNone = 0, // no known chat/content restriction + k_nUserRestrictionUnknown = 1, // we don't know yet (user offline) + k_nUserRestrictionAnyChat = 2, // user is not allowed to (or can't) send/recv any chat + k_nUserRestrictionVoiceChat = 4, // user is not allowed to (or can't) send/recv voice chat + k_nUserRestrictionGroupChat = 8, // user is not allowed to (or can't) send/recv group chat + k_nUserRestrictionRating = 16, // user is too young according to rating in current region + k_nUserRestrictionGameInvites = 32, // user cannot send or recv game invites (e.g. mobile) + k_nUserRestrictionTrading = 64, // user cannot participate in trading (console, mobile) +}; + +//----------------------------------------------------------------------------- +// Purpose: information about user sessions +//----------------------------------------------------------------------------- +struct FriendSessionStateInfo_t +{ + uint32 m_uiOnlineSessionInstances; + uint8 m_uiPublishedToFriendsSessionInstance; +}; + + + +// size limit on chat room or member metadata +const uint32 k_cubChatMetadataMax = 8192; + +// size limits on Rich Presence data +enum { k_cchMaxRichPresenceKeys = 20 }; +enum { k_cchMaxRichPresenceKeyLength = 64 }; +enum { k_cchMaxRichPresenceValueLength = 256 }; + +// These values are passed as parameters to the store +enum EOverlayToStoreFlag +{ + k_EOverlayToStoreFlag_None = 0, + k_EOverlayToStoreFlag_AddToCart = 1, + k_EOverlayToStoreFlag_AddToCartAndShow = 2, +}; + +//----------------------------------------------------------------------------- +// Purpose: interface to accessing information about individual users, +// that can be a friend, in a group, on a game server or in a lobby with the local user +//----------------------------------------------------------------------------- +class ISteamFriends +{ +public: + // returns the local players name - guaranteed to not be NULL. + // this is the same name as on the users community profile page + // this is stored in UTF-8 format + // like all the other interface functions that return a char *, it's important that this pointer is not saved + // off; it will eventually be free'd or re-allocated + virtual const char *GetPersonaName() = 0; + + // Sets the player name, stores it on the server and publishes the changes to all friends who are online. + // Changes take place locally immediately, and a PersonaStateChange_t is posted, presuming success. + // + // The final results are available through the return value SteamAPICall_t, using SetPersonaNameResponse_t. + // + // If the name change fails to happen on the server, then an additional global PersonaStateChange_t will be posted + // to change the name back, in addition to the SetPersonaNameResponse_t callback. + virtual SteamAPICall_t SetPersonaName( const char *pchPersonaName ) = 0; + + // gets the status of the current user + virtual EPersonaState GetPersonaState() = 0; + + // friend iteration + // takes a set of k_EFriendFlags, and returns the number of users the client knows about who meet that criteria + // then GetFriendByIndex() can then be used to return the id's of each of those users + virtual int GetFriendCount( int iFriendFlags ) = 0; + + // returns the steamID of a user + // iFriend is a index of range [0, GetFriendCount()) + // iFriendsFlags must be the same value as used in GetFriendCount() + // the returned CSteamID can then be used by all the functions below to access details about the user + virtual CSteamID GetFriendByIndex( int iFriend, int iFriendFlags ) = 0; + + // returns a relationship to a user + virtual EFriendRelationship GetFriendRelationship( CSteamID steamIDFriend ) = 0; + + // returns the current status of the specified user + // this will only be known by the local user if steamIDFriend is in their friends list; on the same game server; in a chat room or lobby; or in a small group with the local user + virtual EPersonaState GetFriendPersonaState( CSteamID steamIDFriend ) = 0; + + // returns the name another user - guaranteed to not be NULL. + // same rules as GetFriendPersonaState() apply as to whether or not the user knowns the name of the other user + // note that on first joining a lobby, chat room or game server the local user will not known the name of the other users automatically; that information will arrive asyncronously + // + virtual const char *GetFriendPersonaName( CSteamID steamIDFriend ) = 0; + + // returns true if the friend is actually in a game, and fills in pFriendGameInfo with an extra details + virtual bool GetFriendGamePlayed( CSteamID steamIDFriend, FriendGameInfo_t *pFriendGameInfo ) = 0; + // accesses old friends names - returns an empty string when their are no more items in the history + virtual const char *GetFriendPersonaNameHistory( CSteamID steamIDFriend, int iPersonaName ) = 0; + + // returns true if the specified user meets any of the criteria specified in iFriendFlags + // iFriendFlags can be the union (binary or, |) of one or more k_EFriendFlags values + virtual bool HasFriend( CSteamID steamIDFriend, int iFriendFlags ) = 0; + + // clan (group) iteration and access functions + virtual int GetClanCount() = 0; + virtual CSteamID GetClanByIndex( int iClan ) = 0; + virtual const char *GetClanName( CSteamID steamIDClan ) = 0; + virtual const char *GetClanTag( CSteamID steamIDClan ) = 0; + // returns the most recent information we have about what's happening in a clan + virtual bool GetClanActivityCounts( CSteamID steamIDClan, int *pnOnline, int *pnInGame, int *pnChatting ) = 0; + // for clans a user is a member of, they will have reasonably up-to-date information, but for others you'll have to download the info to have the latest + virtual SteamAPICall_t DownloadClanActivityCounts( CSteamID *psteamIDClans, int cClansToRequest ) = 0; + + // iterators for getting users in a chat room, lobby, game server or clan + // note that large clans that cannot be iterated by the local user + // note that the current user must be in a lobby to retrieve CSteamIDs of other users in that lobby + // steamIDSource can be the steamID of a group, game server, lobby or chat room + virtual int GetFriendCountFromSource( CSteamID steamIDSource ) = 0; + virtual CSteamID GetFriendFromSourceByIndex( CSteamID steamIDSource, int iFriend ) = 0; + + // returns true if the local user can see that steamIDUser is a member or in steamIDSource + virtual bool IsUserInSource( CSteamID steamIDUser, CSteamID steamIDSource ) = 0; + + // User is in a game pressing the talk button (will suppress the microphone for all voice comms from the Steam friends UI) + virtual void SetInGameVoiceSpeaking( CSteamID steamIDUser, bool bSpeaking ) = 0; + + // activates the game overlay, with an optional dialog to open + // valid options are "Friends", "Community", "Players", "Settings", "OfficialGameGroup", "Stats", "Achievements" + virtual void ActivateGameOverlay( const char *pchDialog ) = 0; + + // activates game overlay to a specific place + // valid options are + // "steamid" - opens the overlay web browser to the specified user or groups profile + // "chat" - opens a chat window to the specified user, or joins the group chat + // "jointrade" - opens a window to a Steam Trading session that was started with the ISteamEconomy/StartTrade Web API + // "stats" - opens the overlay web browser to the specified user's stats + // "achievements" - opens the overlay web browser to the specified user's achievements + // "friendadd" - opens the overlay in minimal mode prompting the user to add the target user as a friend + // "friendremove" - opens the overlay in minimal mode prompting the user to remove the target friend + // "friendrequestaccept" - opens the overlay in minimal mode prompting the user to accept an incoming friend invite + // "friendrequestignore" - opens the overlay in minimal mode prompting the user to ignore an incoming friend invite + virtual void ActivateGameOverlayToUser( const char *pchDialog, CSteamID steamID ) = 0; + + // activates game overlay web browser directly to the specified URL + // full address with protocol type is required, e.g. http://www.steamgames.com/ + virtual void ActivateGameOverlayToWebPage( const char *pchURL ) = 0; + + // activates game overlay to store page for app + virtual void ActivateGameOverlayToStore( AppId_t nAppID, EOverlayToStoreFlag eFlag ) = 0; + + // Mark a target user as 'played with'. This is a client-side only feature that requires that the calling user is + // in game + virtual void SetPlayedWith( CSteamID steamIDUserPlayedWith ) = 0; + + // activates game overlay to open the invite dialog. Invitations will be sent for the provided lobby. + virtual void ActivateGameOverlayInviteDialog( CSteamID steamIDLobby ) = 0; + + // gets the small (32x32) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + virtual int GetSmallFriendAvatar( CSteamID steamIDFriend ) = 0; + + // gets the medium (64x64) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + virtual int GetMediumFriendAvatar( CSteamID steamIDFriend ) = 0; + + // gets the large (184x184) avatar of the current user, which is a handle to be used in IClientUtils::GetImageRGBA(), or 0 if none set + // returns -1 if this image has yet to be loaded, in this case wait for a AvatarImageLoaded_t callback and then call this again + virtual int GetLargeFriendAvatar( CSteamID steamIDFriend ) = 0; + + // requests information about a user - persona name & avatar + // if bRequireNameOnly is set, then the avatar of a user isn't downloaded + // - it's a lot slower to download avatars and churns the local cache, so if you don't need avatars, don't request them + // if returns true, it means that data is being requested, and a PersonaStateChanged_t callback will be posted when it's retrieved + // if returns false, it means that we already have all the details about that user, and functions can be called immediately + virtual bool RequestUserInformation( CSteamID steamIDUser, bool bRequireNameOnly ) = 0; + + // requests information about a clan officer list + // when complete, data is returned in ClanOfficerListResponse_t call result + // this makes available the calls below + // you can only ask about clans that a user is a member of + // note that this won't download avatars automatically; if you get an officer, + // and no avatar image is available, call RequestUserInformation( steamID, false ) to download the avatar + virtual SteamAPICall_t RequestClanOfficerList( CSteamID steamIDClan ) = 0; + + // iteration of clan officers - can only be done when a RequestClanOfficerList() call has completed + + // returns the steamID of the clan owner + virtual CSteamID GetClanOwner( CSteamID steamIDClan ) = 0; + // returns the number of officers in a clan (including the owner) + virtual int GetClanOfficerCount( CSteamID steamIDClan ) = 0; + // returns the steamID of a clan officer, by index, of range [0,GetClanOfficerCount) + virtual CSteamID GetClanOfficerByIndex( CSteamID steamIDClan, int iOfficer ) = 0; + // if current user is chat restricted, he can't send or receive any text/voice chat messages. + // the user can't see custom avatars. But the user can be online and send/recv game invites. + // a chat restricted user can't add friends or join any groups. + virtual uint32 GetUserRestrictions() = 0; + + // Rich Presence data is automatically shared between friends who are in the same game + // Each user has a set of Key/Value pairs + // Up to 20 different keys can be set + // There are two magic keys: + // "status" - a UTF-8 string that will show up in the 'view game info' dialog in the Steam friends list + // "connect" - a UTF-8 string that contains the command-line for how a friend can connect to a game + // GetFriendRichPresence() returns an empty string "" if no value is set + // SetRichPresence() to a NULL or an empty string deletes the key + // You can iterate the current set of keys for a friend with GetFriendRichPresenceKeyCount() + // and GetFriendRichPresenceKeyByIndex() (typically only used for debugging) + virtual bool SetRichPresence( const char *pchKey, const char *pchValue ) = 0; + virtual void ClearRichPresence() = 0; + virtual const char *GetFriendRichPresence( CSteamID steamIDFriend, const char *pchKey ) = 0; + virtual int GetFriendRichPresenceKeyCount( CSteamID steamIDFriend ) = 0; + virtual const char *GetFriendRichPresenceKeyByIndex( CSteamID steamIDFriend, int iKey ) = 0; + // Requests rich presence for a specific user. + virtual void RequestFriendRichPresence( CSteamID steamIDFriend ) = 0; + + // rich invite support + // if the target accepts the invite, the pchConnectString gets added to the command-line for launching the game + // if the game is already running, a GameRichPresenceJoinRequested_t callback is posted containing the connect string + // invites can only be sent to friends + virtual bool InviteUserToGame( CSteamID steamIDFriend, const char *pchConnectString ) = 0; + + // recently-played-with friends iteration + // this iterates the entire list of users recently played with, across games + // GetFriendCoplayTime() returns as a unix time + virtual int GetCoplayFriendCount() = 0; + virtual CSteamID GetCoplayFriend( int iCoplayFriend ) = 0; + virtual int GetFriendCoplayTime( CSteamID steamIDFriend ) = 0; + virtual AppId_t GetFriendCoplayGame( CSteamID steamIDFriend ) = 0; + + // chat interface for games + // this allows in-game access to group (clan) chats from in the game + // the behavior is somewhat sophisticated, because the user may or may not be already in the group chat from outside the game or in the overlay + // use ActivateGameOverlayToUser( "chat", steamIDClan ) to open the in-game overlay version of the chat + virtual SteamAPICall_t JoinClanChatRoom( CSteamID steamIDClan ) = 0; + virtual bool LeaveClanChatRoom( CSteamID steamIDClan ) = 0; + virtual int GetClanChatMemberCount( CSteamID steamIDClan ) = 0; + virtual CSteamID GetChatMemberByIndex( CSteamID steamIDClan, int iUser ) = 0; + virtual bool SendClanChatMessage( CSteamID steamIDClanChat, const char *pchText ) = 0; + virtual int GetClanChatMessage( CSteamID steamIDClanChat, int iMessage, void *prgchText, int cchTextMax, EChatEntryType *, CSteamID * ) = 0; + virtual bool IsClanChatAdmin( CSteamID steamIDClanChat, CSteamID steamIDUser ) = 0; + + // interact with the Steam (game overlay / desktop) + virtual bool IsClanChatWindowOpenInSteam( CSteamID steamIDClanChat ) = 0; + virtual bool OpenClanChatWindowInSteam( CSteamID steamIDClanChat ) = 0; + virtual bool CloseClanChatWindowInSteam( CSteamID steamIDClanChat ) = 0; + + // peer-to-peer chat interception + // this is so you can show P2P chats inline in the game + virtual bool SetListenForFriendsMessages( bool bInterceptEnabled ) = 0; + virtual bool ReplyToFriendMessage( CSteamID steamIDFriend, const char *pchMsgToSend ) = 0; + virtual int GetFriendMessage( CSteamID steamIDFriend, int iMessageID, void *pvData, int cubData, EChatEntryType *peChatEntryType ) = 0; + + // following apis + virtual SteamAPICall_t GetFollowerCount( CSteamID steamID ) = 0; + virtual SteamAPICall_t IsFollowing( CSteamID steamID ) = 0; + virtual SteamAPICall_t EnumerateFollowingList( uint32 unStartIndex ) = 0; +}; + +#define STEAMFRIENDS_INTERFACE_VERSION "SteamFriends013" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when a friends' status changes +//----------------------------------------------------------------------------- +struct PersonaStateChange_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 4 }; + + uint64 m_ulSteamID; // steamID of the friend who changed + int m_nChangeFlags; // what's changed +}; + + +// used in PersonaStateChange_t::m_nChangeFlags to describe what's changed about a user +// these flags describe what the client has learned has changed recently, so on startup you'll see a name, avatar & relationship change for every friend +enum EPersonaChange +{ + k_EPersonaChangeName = 0x0001, + k_EPersonaChangeStatus = 0x0002, + k_EPersonaChangeComeOnline = 0x0004, + k_EPersonaChangeGoneOffline = 0x0008, + k_EPersonaChangeGamePlayed = 0x0010, + k_EPersonaChangeGameServer = 0x0020, + k_EPersonaChangeAvatar = 0x0040, + k_EPersonaChangeJoinedSource= 0x0080, + k_EPersonaChangeLeftSource = 0x0100, + k_EPersonaChangeRelationshipChanged = 0x0200, + k_EPersonaChangeNameFirstSet = 0x0400, + k_EPersonaChangeFacebookInfo = 0x0800, + k_EPersonaChangeNickname = 0x1000, + k_EPersonaChangeSteamLevel = 0x2000, +}; + + +//----------------------------------------------------------------------------- +// Purpose: posted when game overlay activates or deactivates +// the game can use this to be pause or resume single player games +//----------------------------------------------------------------------------- +struct GameOverlayActivated_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 31 }; + uint8 m_bActive; // true if it's just been activated, false otherwise +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a different game server from their friends list +// game client should attempt to connect to specified server when this is received +//----------------------------------------------------------------------------- +struct GameServerChangeRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 32 }; + char m_rgchServer[64]; // server address ("127.0.0.1:27015", "tf2.valvesoftware.com") + char m_rgchPassword[64]; // server password, if any +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a lobby from their friends list +// game client should attempt to connect to specified lobby when this is received +//----------------------------------------------------------------------------- +struct GameLobbyJoinRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 33 }; + CSteamID m_steamIDLobby; + + // The friend they did the join via (will be invalid if not directly via a friend) + // + // On PS3, the friend will be invalid if this was triggered by a PSN invite via the XMB, but + // the account type will be console user so you can tell at least that this was from a PSN friend + // rather than a Steam friend. + CSteamID m_steamIDFriend; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when an avatar is loaded in from a previous GetLargeFriendAvatar() call +// if the image wasn't already available +//----------------------------------------------------------------------------- +struct AvatarImageLoaded_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 34 }; + CSteamID m_steamID; // steamid the avatar has been loaded for + int m_iImage; // the image index of the now loaded image + int m_iWide; // width of the loaded image + int m_iTall; // height of the loaded image +}; + + +//----------------------------------------------------------------------------- +// Purpose: marks the return of a request officer list call +//----------------------------------------------------------------------------- +struct ClanOfficerListResponse_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 35 }; + CSteamID m_steamIDClan; + int m_cOfficers; + uint8 m_bSuccess; +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating updated data about friends rich presence information +//----------------------------------------------------------------------------- +struct FriendRichPresenceUpdate_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 36 }; + CSteamID m_steamIDFriend; // friend who's rich presence has changed + AppId_t m_nAppID; // the appID of the game (should always be the current game) +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the user tries to join a game from their friends list +// rich presence will have been set with the "connect" key which is set here +//----------------------------------------------------------------------------- +struct GameRichPresenceJoinRequested_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 37 }; + CSteamID m_steamIDFriend; // the friend they did the join via (will be invalid if not directly via a friend) + char m_rgchConnect[k_cchMaxRichPresenceValueLength]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a chat message has been received for a clan chat the game has joined +//----------------------------------------------------------------------------- +struct GameConnectedClanChatMsg_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 38 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; + int m_iMessageID; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a user has joined a clan chat +//----------------------------------------------------------------------------- +struct GameConnectedChatJoin_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 39 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a user has left the chat we're in +//----------------------------------------------------------------------------- +struct GameConnectedChatLeave_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 40 }; + CSteamID m_steamIDClanChat; + CSteamID m_steamIDUser; + bool m_bKicked; // true if admin kicked + bool m_bDropped; // true if Steam connection dropped +}; + + +//----------------------------------------------------------------------------- +// Purpose: a DownloadClanActivityCounts() call has finished +//----------------------------------------------------------------------------- +struct DownloadClanActivityCountsResult_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 41 }; + bool m_bSuccess; +}; + + +//----------------------------------------------------------------------------- +// Purpose: a JoinClanChatRoom() call has finished +//----------------------------------------------------------------------------- +struct JoinClanChatRoomCompletionResult_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 42 }; + CSteamID m_steamIDClanChat; + EChatRoomEnterResponse m_eChatRoomEnterResponse; +}; + +//----------------------------------------------------------------------------- +// Purpose: a chat message has been received from a user +//----------------------------------------------------------------------------- +struct GameConnectedFriendChatMsg_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 43 }; + CSteamID m_steamIDUser; + int m_iMessageID; +}; + + +struct FriendsGetFollowerCount_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 44 }; + EResult m_eResult; + CSteamID m_steamID; + int m_nCount; +}; + + +struct FriendsIsFollowing_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 45 }; + EResult m_eResult; + CSteamID m_steamID; + bool m_bIsFollowing; +}; + + +struct FriendsEnumerateFollowingList_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 46 }; + EResult m_eResult; + CSteamID m_rgSteamID[ k_cEnumerateFollowersMax ]; + int32 m_nResultsReturned; + int32 m_nTotalResultCount; +}; + +//----------------------------------------------------------------------------- +// Purpose: reports the result of an attempt to change the user's persona name +//----------------------------------------------------------------------------- +struct SetPersonaNameResponse_t +{ + enum { k_iCallback = k_iSteamFriendsCallbacks + 47 }; + + bool m_bSuccess; // true if name change succeeded completely. + bool m_bLocalSuccess; // true if name change was retained locally. (We might not have been able to communicate with Steam) + EResult m_result; // detailed result code +}; + + +#pragma pack( pop ) + +#endif // ISTEAMFRIENDS_H diff --git a/rehlds/public/steam/isteamgameserver.h b/rehlds/public/steam/isteamgameserver.h new file mode 100644 index 0000000..6ae3cd6 --- /dev/null +++ b/rehlds/public/steam/isteamgameserver.h @@ -0,0 +1,391 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to steam for game servers +// +//============================================================================= + +#ifndef ISTEAMGAMESERVER_H +#define ISTEAMGAMESERVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +#define MASTERSERVERUPDATERPORT_USEGAMESOCKETSHARE ((uint16)-1) + +//----------------------------------------------------------------------------- +// Purpose: Functions for authenticating users via Steam to play on a game server +//----------------------------------------------------------------------------- +class ISteamGameServer +{ +public: + +// +// Basic server data. These properties, if set, must be set before before calling LogOn. They +// may not be changed after logged in. +// + + /// This is called by SteamGameServer_Init, and you will usually not need to call it directly + virtual bool InitGameServer( uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString ) = 0; + + /// Game product identifier. This is currently used by the master server for version checking purposes. + /// It's a required field, but will eventually will go away, and the AppID will be used for this purpose. + virtual void SetProduct( const char *pszProduct ) = 0; + + /// Description of the game. This is a required field and is displayed in the steam server browser....for now. + /// This is a required field, but it will go away eventually, as the data should be determined from the AppID. + virtual void SetGameDescription( const char *pszGameDescription ) = 0; + + /// If your game is a "mod," pass the string that identifies it. The default is an empty string, meaning + /// this application is the original game, not a mod. + /// + /// @see k_cbMaxGameServerGameDir + virtual void SetModDir( const char *pszModDir ) = 0; + + /// Is this is a dedicated server? The default value is false. + virtual void SetDedicatedServer( bool bDedicated ) = 0; + +// +// Login +// + + /// Begin process to login to a persistent game server account + /// + /// You need to register for callbacks to determine the result of this operation. + /// @see SteamServersConnected_t + /// @see SteamServerConnectFailure_t + /// @see SteamServersDisconnected_t + virtual void LogOn( + const char *pszAccountName, + const char *pszPassword + ) = 0; + + /// Login to a generic, anonymous account. + /// + /// Note: in previous versions of the SDK, this was automatically called within SteamGameServer_Init, + /// but this is no longer the case. + virtual void LogOnAnonymous() = 0; + + /// Begin process of logging game server out of steam + virtual void LogOff() = 0; + + // status functions + virtual bool BLoggedOn() = 0; + virtual bool BSecure() = 0; + virtual CSteamID GetSteamID() = 0; + + /// Returns true if the master server has requested a restart. + /// Only returns true once per request. + virtual bool WasRestartRequested() = 0; + +// +// Server state. These properties may be changed at any time. +// + + /// Max player count that will be reported to server browser and client queries + virtual void SetMaxPlayerCount( int cPlayersMax ) = 0; + + /// Number of bots. Default value is zero + virtual void SetBotPlayerCount( int cBotplayers ) = 0; + + /// Set the name of server as it will appear in the server browser + /// + /// @see k_cbMaxGameServerName + virtual void SetServerName( const char *pszServerName ) = 0; + + /// Set name of map to report in the server browser + /// + /// @see k_cbMaxGameServerName + virtual void SetMapName( const char *pszMapName ) = 0; + + /// Let people know if your server will require a password + virtual void SetPasswordProtected( bool bPasswordProtected ) = 0; + + /// Spectator server. The default value is zero, meaning the service + /// is not used. + virtual void SetSpectatorPort( uint16 unSpectatorPort ) = 0; + + /// Name of the spectator server. (Only used if spectator port is nonzero.) + /// + /// @see k_cbMaxGameServerMapName + virtual void SetSpectatorServerName( const char *pszSpectatorServerName ) = 0; + + /// Call this to clear the whole list of key/values that are sent in rules queries. + virtual void ClearAllKeyValues() = 0; + + /// Call this to add/update a key/value pair. + virtual void SetKeyValue( const char *pKey, const char *pValue ) = 0; + + /// Sets a string defining the "gametags" for this server, this is optional, but if it is set + /// it allows users to filter in the matchmaking/server-browser interfaces based on the value + /// + /// @see k_cbMaxGameServerTags + virtual void SetGameTags( const char *pchGameTags ) = 0; + + /// Sets a string defining the "gamedata" for this server, this is optional, but if it is set + /// it allows users to filter in the matchmaking/server-browser interfaces based on the value + /// don't set this unless it actually changes, its only uploaded to the master once (when + /// acknowledged) + /// + /// @see k_cbMaxGameServerGameData + virtual void SetGameData( const char *pchGameData) = 0; + + /// Region identifier. This is an optional field, the default value is empty, meaning the "world" region + virtual void SetRegion( const char *pszRegion ) = 0; + +// +// Player list management / authentication +// + + // Handles receiving a new connection from a Steam user. This call will ask the Steam + // servers to validate the users identity, app ownership, and VAC status. If the Steam servers + // are off-line, then it will validate the cached ticket itself which will validate app ownership + // and identity. The AuthBlob here should be acquired on the game client using SteamUser()->InitiateGameConnection() + // and must then be sent up to the game server for authentication. + // + // Return Value: returns true if the users ticket passes basic checks. pSteamIDUser will contain the Steam ID of this user. pSteamIDUser must NOT be NULL + // If the call succeeds then you should expect a GSClientApprove_t or GSClientDeny_t callback which will tell you whether authentication + // for the user has succeeded or failed (the steamid in the callback will match the one returned by this call) + virtual bool SendUserConnectAndAuthenticate( uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser ) = 0; + + // Creates a fake user (ie, a bot) which will be listed as playing on the server, but skips validation. + // + // Return Value: Returns a SteamID for the user to be tracked with, you should call HandleUserDisconnect() + // when this user leaves the server just like you would for a real user. + virtual CSteamID CreateUnauthenticatedUserConnection() = 0; + + // Should be called whenever a user leaves our game server, this lets Steam internally + // track which users are currently on which servers for the purposes of preventing a single + // account being logged into multiple servers, showing who is currently on a server, etc. + virtual void SendUserDisconnect( CSteamID steamIDUser ) = 0; + + // Update the data to be displayed in the server browser and matchmaking interfaces for a user + // currently connected to the server. For regular users you must call this after you receive a + // GSUserValidationSuccess callback. + // + // Return Value: true if successful, false if failure (ie, steamIDUser wasn't for an active player) + virtual bool BUpdateUserData( CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore ) = 0; + + // New auth system APIs - do not mix with the old auth system APIs. + // ---------------------------------------------------------------- + + // Retrieve ticket to be sent to the entity who wishes to authenticate you ( using BeginAuthSession API ). + // pcbTicket retrieves the length of the actual ticket. + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // Authenticate ticket ( from GetAuthSessionTicket ) from entity steamID to be sure it is valid and isnt reused + // Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse ) + virtual EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID ) = 0; + + // Stop tracking started by BeginAuthSession - called when no longer playing game with this entity + virtual void EndAuthSession( CSteamID steamID ) = 0; + + // Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to + virtual void CancelAuthTicket( HAuthTicket hAuthTicket ) = 0; + + // After receiving a user's authentication data, and passing it to SendUserConnectAndAuthenticate, use this function + // to determine if the user owns downloadable content specified by the provided AppID. + virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0; + + // Ask if a user in in the specified group, results returns async by GSUserGroupStatus_t + // returns false if we're not connected to the steam servers and thus cannot ask + virtual bool RequestUserGroupStatus( CSteamID steamIDUser, CSteamID steamIDGroup ) = 0; + +// +// Query steam for server data +// + + // Ask for the gameplay stats for the server. Results returned in a callback + virtual void GetGameplayStats( ) = 0; + + // Gets the reputation score for the game server. This API also checks if the server or some + // other server on the same IP is banned from the Steam master servers. + virtual SteamAPICall_t GetServerReputation( ) = 0; + + // Returns the public IP of the server according to Steam, useful when the server is + // behind NAT and you want to advertise its IP in a lobby for other clients to directly + // connect to + virtual uint32 GetPublicIP() = 0; + +// These are in GameSocketShare mode, where instead of ISteamGameServer creating its own +// socket to talk to the master server on, it lets the game use its socket to forward messages +// back and forth. This prevents us from requiring server ops to open up yet another port +// in their firewalls. +// +// the IP address and port should be in host order, i.e 127.0.0.1 == 0x7f000001 + + // These are used when you've elected to multiplex the game server's UDP socket + // rather than having the master server updater use its own sockets. + // + // Source games use this to simplify the job of the server admins, so they + // don't have to open up more ports on their firewalls. + + // Call this when a packet that starts with 0xFFFFFFFF comes in. That means + // it's for us. + virtual bool HandleIncomingPacket( const void *pData, int cbData, uint32 srcIP, uint16 srcPort ) = 0; + + // AFTER calling HandleIncomingPacket for any packets that came in that frame, call this. + // This gets a packet that the master server updater needs to send out on UDP. + // It returns the length of the packet it wants to send, or 0 if there are no more packets to send. + // Call this each frame until it returns 0. + virtual int GetNextOutgoingPacket( void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort ) = 0; + +// +// Control heartbeats / advertisement with master server +// + + // Call this as often as you like to tell the master server updater whether or not + // you want it to be active (default: off). + virtual void EnableHeartbeats( bool bActive ) = 0; + + // You usually don't need to modify this. + // Pass -1 to use the default value for iHeartbeatInterval. + // Some mods change this. + virtual void SetHeartbeatInterval( int iHeartbeatInterval ) = 0; + + // Force a heartbeat to steam at the next opportunity + virtual void ForceHeartbeat() = 0; + + // associate this game server with this clan for the purposes of computing player compat + virtual SteamAPICall_t AssociateWithClan( CSteamID steamIDClan ) = 0; + + // ask if any of the current players dont want to play with this new player - or vice versa + virtual SteamAPICall_t ComputeNewPlayerCompatibility( CSteamID steamIDNewPlayer ) = 0; + +}; + +#define STEAMGAMESERVER_INTERFACE_VERSION "SteamGameServer011" + +// game server flags +const uint32 k_unServerFlagNone = 0x00; +const uint32 k_unServerFlagActive = 0x01; // server has users playing +const uint32 k_unServerFlagSecure = 0x02; // server wants to be secure +const uint32 k_unServerFlagDedicated = 0x04; // server is dedicated +const uint32 k_unServerFlagLinux = 0x08; // linux build +const uint32 k_unServerFlagPassworded = 0x10; // password protected +const uint32 k_unServerFlagPrivate = 0x20; // server shouldn't list on master server and + // won't enforce authentication of users that connect to the server. + // Useful when you run a server where the clients may not + // be connected to the internet but you want them to play (i.e LANs) + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + + +// client has been approved to connect to this game server +struct GSClientApprove_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 1 }; + CSteamID m_SteamID; +}; + + +// client has been denied to connection to this game server +struct GSClientDeny_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 2 }; + CSteamID m_SteamID; + EDenyReason m_eDenyReason; + char m_rgchOptionalText[128]; +}; + + +// request the game server should kick the user +struct GSClientKick_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 3 }; + CSteamID m_SteamID; + EDenyReason m_eDenyReason; +}; + +// NOTE: callback values 4 and 5 are skipped because they are used for old deprecated callbacks, +// do not reuse them here. + + +// client achievement info +struct GSClientAchievementStatus_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 6 }; + uint64 m_SteamID; + char m_pchAchievement[128]; + bool m_bUnlocked; +}; + +// received when the game server requests to be displayed as secure (VAC protected) +// m_bSecure is true if the game server should display itself as secure to users, false otherwise +struct GSPolicyResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 15 }; + uint8 m_bSecure; +}; + +// GS gameplay stats info +struct GSGameplayStats_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 7 }; + EResult m_eResult; // Result of the call + int32 m_nRank; // Overall rank of the server (0-based) + uint32 m_unTotalConnects; // Total number of clients who have ever connected to the server + uint32 m_unTotalMinutesPlayed; // Total number of minutes ever played on the server +}; + +// send as a reply to RequestUserGroupStatus() +struct GSClientGroupStatus_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 8 }; + CSteamID m_SteamIDUser; + CSteamID m_SteamIDGroup; + bool m_bMember; + bool m_bOfficer; +}; + +// Sent as a reply to GetServerReputation() +struct GSReputation_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 9 }; + EResult m_eResult; // Result of the call; + uint32 m_unReputationScore; // The reputation score for the game server + bool m_bBanned; // True if the server is banned from the Steam + // master servers + + // The following members are only filled out if m_bBanned is true. They will all + // be set to zero otherwise. Master server bans are by IP so it is possible to be + // banned even when the score is good high if there is a bad server on another port. + // This information can be used to determine which server is bad. + + uint32 m_unBannedIP; // The IP of the banned server + uint16 m_usBannedPort; // The port of the banned server + uint64 m_ulBannedGameID; // The game ID the banned server is serving + uint32 m_unBanExpires; // Time the ban expires, expressed in the Unix epoch (seconds since 1/1/1970) +}; + +// Sent as a reply to AssociateWithClan() +struct AssociateWithClanResult_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 10 }; + EResult m_eResult; // Result of the call; +}; + +// Sent as a reply to ComputeNewPlayerCompatibility() +struct ComputeNewPlayerCompatibilityResult_t +{ + enum { k_iCallback = k_iSteamGameServerCallbacks + 11 }; + EResult m_eResult; // Result of the call; + int m_cPlayersThatDontLikeCandidate; + int m_cPlayersThatCandidateDoesntLike; + int m_cClanPlayersThatDontLikeCandidate; + CSteamID m_SteamIDCandidate; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMGAMESERVER_H diff --git a/rehlds/public/steam/isteamgameserverstats.h b/rehlds/public/steam/isteamgameserverstats.h new file mode 100644 index 0000000..78c299a --- /dev/null +++ b/rehlds/public/steam/isteamgameserverstats.h @@ -0,0 +1,99 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface for game servers to steam stats and achievements +// +//============================================================================= + +#ifndef ISTEAMGAMESERVERSTATS_H +#define ISTEAMGAMESERVERSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +//----------------------------------------------------------------------------- +// Purpose: Functions for authenticating users via Steam to play on a game server +//----------------------------------------------------------------------------- +class ISteamGameServerStats +{ +public: + // downloads stats for the user + // returns a GSStatsReceived_t callback when completed + // if the user has no stats, GSStatsReceived_t.m_eResult will be set to k_EResultFail + // these stats will only be auto-updated for clients playing on the server. For other + // users you'll need to call RequestUserStats() again to refresh any data + virtual SteamAPICall_t RequestUserStats( CSteamID steamIDUser ) = 0; + + // requests stat information for a user, usable after a successful call to RequestUserStats() + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData ) = 0; + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, float *pData ) = 0; + virtual bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchieved ) = 0; + + // Set / update stats and achievements. + // Note: These updates will work only on stats game servers are allowed to edit and only for + // game servers that have been declared as officially controlled by the game creators. + // Set the IP range of your official servers on the Steamworks page + virtual bool SetUserStat( CSteamID steamIDUser, const char *pchName, int32 nData ) = 0; + virtual bool SetUserStat( CSteamID steamIDUser, const char *pchName, float fData ) = 0; + virtual bool UpdateUserAvgRateStat( CSteamID steamIDUser, const char *pchName, float flCountThisSession, double dSessionLength ) = 0; + + virtual bool SetUserAchievement( CSteamID steamIDUser, const char *pchName ) = 0; + virtual bool ClearUserAchievement( CSteamID steamIDUser, const char *pchName ) = 0; + + // Store the current data on the server, will get a GSStatsStored_t callback when set. + // + // If the callback has a result of k_EResultInvalidParam, one or more stats + // uploaded has been rejected, either because they broke constraints + // or were out of date. In this case the server sends back updated values. + // The stats should be re-iterated to keep in sync. + virtual SteamAPICall_t StoreUserStats( CSteamID steamIDUser ) = 0; +}; + +#define STEAMGAMESERVERSTATS_INTERFACE_VERSION "SteamGameServerStats001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when the latests stats and achievements have been received +// from the server +//----------------------------------------------------------------------------- +struct GSStatsReceived_t +{ + enum { k_iCallback = k_iSteamGameServerStatsCallbacks }; + EResult m_eResult; // Success / error fetching the stats + CSteamID m_steamIDUser; // The user for whom the stats are retrieved for +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the user stats for a game +//----------------------------------------------------------------------------- +struct GSStatsStored_t +{ + enum { k_iCallback = k_iSteamGameServerStatsCallbacks + 1 }; + EResult m_eResult; // success / error + CSteamID m_steamIDUser; // The user for whom the stats were stored +}; + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that a user's stats have been unloaded. +// Call RequestUserStats again to access stats for this user +//----------------------------------------------------------------------------- +struct GSStatsUnloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 8 }; + CSteamID m_steamIDUser; // User whose stats have been unloaded +}; + +#pragma pack( pop ) + + +#endif // ISTEAMGAMESERVERSTATS_H diff --git a/rehlds/public/steam/isteamhttp.h b/rehlds/public/steam/isteamhttp.h new file mode 100644 index 0000000..f81475e --- /dev/null +++ b/rehlds/public/steam/isteamhttp.h @@ -0,0 +1,176 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to http client +// +//============================================================================= + +#ifndef ISTEAMHTTP_H +#define ISTEAMHTTP_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "steamhttpenums.h" + +// Handle to a HTTP Request handle +typedef uint32 HTTPRequestHandle; +#define INVALID_HTTPREQUEST_HANDLE 0 + +//----------------------------------------------------------------------------- +// Purpose: interface to http client +//----------------------------------------------------------------------------- +class ISteamHTTP +{ +public: + + // Initializes a new HTTP request, returning a handle to use in further operations on it. Requires + // the method (GET or POST) and the absolute URL for the request. Only http requests (ie, not https) are + // currently supported, so this string must start with http:// or https:// and should look like http://store.steampowered.com/app/250/ + // or such. + virtual HTTPRequestHandle CreateHTTPRequest( EHTTPMethod eHTTPRequestMethod, const char *pchAbsoluteURL ) = 0; + + // Set a context value for the request, which will be returned in the HTTPRequestCompleted_t callback after + // sending the request. This is just so the caller can easily keep track of which callbacks go with which request data. + virtual bool SetHTTPRequestContextValue( HTTPRequestHandle hRequest, uint64 ulContextValue ) = 0; + + // Set a timeout in seconds for the HTTP request, must be called prior to sending the request. Default + // timeout is 60 seconds if you don't call this. Returns false if the handle is invalid, or the request + // has already been sent. + virtual bool SetHTTPRequestNetworkActivityTimeout( HTTPRequestHandle hRequest, uint32 unTimeoutSeconds ) = 0; + + // Set a request header value for the request, must be called prior to sending the request. Will + // return false if the handle is invalid or the request is already sent. + virtual bool SetHTTPRequestHeaderValue( HTTPRequestHandle hRequest, const char *pchHeaderName, const char *pchHeaderValue ) = 0; + + // Set a GET or POST parameter value on the request, which is set will depend on the EHTTPMethod specified + // when creating the request. Must be called prior to sending the request. Will return false if the + // handle is invalid or the request is already sent. + virtual bool SetHTTPRequestGetOrPostParameter( HTTPRequestHandle hRequest, const char *pchParamName, const char *pchParamValue ) = 0; + + // Sends the HTTP request, will return false on a bad handle, otherwise use SteamCallHandle to wait on + // asynchronous response via callback. + // + // Note: If the user is in offline mode in Steam, then this will add a only-if-cached cache-control + // header and only do a local cache lookup rather than sending any actual remote request. + virtual bool SendHTTPRequest( HTTPRequestHandle hRequest, SteamAPICall_t *pCallHandle ) = 0; + + // Sends the HTTP request, will return false on a bad handle, otherwise use SteamCallHandle to wait on + // asynchronous response via callback for completion, and listen for HTTPRequestHeadersReceived_t and + // HTTPRequestDataReceived_t callbacks while streaming. + virtual bool SendHTTPRequestAndStreamResponse( HTTPRequestHandle hRequest, SteamAPICall_t *pCallHandle ) = 0; + + // Defers a request you have sent, the actual HTTP client code may have many requests queued, and this will move + // the specified request to the tail of the queue. Returns false on invalid handle, or if the request is not yet sent. + virtual bool DeferHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Prioritizes a request you have sent, the actual HTTP client code may have many requests queued, and this will move + // the specified request to the head of the queue. Returns false on invalid handle, or if the request is not yet sent. + virtual bool PrioritizeHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Checks if a response header is present in a HTTP response given a handle from HTTPRequestCompleted_t, also + // returns the size of the header value if present so the caller and allocate a correctly sized buffer for + // GetHTTPResponseHeaderValue. + virtual bool GetHTTPResponseHeaderSize( HTTPRequestHandle hRequest, const char *pchHeaderName, uint32 *unResponseHeaderSize ) = 0; + + // Gets header values from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // header is not present or if your buffer is too small to contain it's value. You should first call + // BGetHTTPResponseHeaderSize to check for the presence of the header and to find out the size buffer needed. + virtual bool GetHTTPResponseHeaderValue( HTTPRequestHandle hRequest, const char *pchHeaderName, uint8 *pHeaderValueBuffer, uint32 unBufferSize ) = 0; + + // Gets the size of the body data from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // handle is invalid. + virtual bool GetHTTPResponseBodySize( HTTPRequestHandle hRequest, uint32 *unBodySize ) = 0; + + // Gets the body data from a HTTP response given a handle from HTTPRequestCompleted_t, will return false if the + // handle is invalid or is to a streaming response, or if the provided buffer is not the correct size. Use BGetHTTPResponseBodySize first to find out + // the correct buffer size to use. + virtual bool GetHTTPResponseBodyData( HTTPRequestHandle hRequest, uint8 *pBodyDataBuffer, uint32 unBufferSize ) = 0; + + // Gets the body data from a streaming HTTP response given a handle from HTTPRequestDataReceived_t. Will return false if the + // handle is invalid or is to a non-streaming response (meaning it wasn't sent with SendHTTPRequestAndStreamResponse), or if the buffer size and offset + // do not match the size and offset sent in HTTPRequestDataReceived_t. + virtual bool GetHTTPStreamingResponseBodyData( HTTPRequestHandle hRequest, uint32 cOffset, uint8 *pBodyDataBuffer, uint32 unBufferSize ) = 0; + + // Releases an HTTP response handle, should always be called to free resources after receiving a HTTPRequestCompleted_t + // callback and finishing using the response. + virtual bool ReleaseHTTPRequest( HTTPRequestHandle hRequest ) = 0; + + // Gets progress on downloading the body for the request. This will be zero unless a response header has already been + // received which included a content-length field. For responses that contain no content-length it will report + // zero for the duration of the request as the size is unknown until the connection closes. + virtual bool GetHTTPDownloadProgressPct( HTTPRequestHandle hRequest, float *pflPercentOut ) = 0; + + // Sets the body for an HTTP Post request. Will fail and return false on a GET request, and will fail if POST params + // have already been set for the request. Setting this raw body makes it the only contents for the post, the pchContentType + // parameter will set the content-type header for the request so the server may know how to interpret the body. + virtual bool SetHTTPRequestRawPostBody( HTTPRequestHandle hRequest, const char *pchContentType, uint8 *pubBody, uint32 unBodyLen ) = 0; +}; + +#define STEAMHTTP_INTERFACE_VERSION "STEAMHTTP_INTERFACE_VERSION002" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +struct HTTPRequestCompleted_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 1 }; + + // Handle value for the request that has completed. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; + + // This will be true if we actually got any sort of response from the server (even an error). + // It will be false if we failed due to an internal error or client side network failure. + bool m_bRequestSuccessful; + + // Will be the HTTP status code value returned by the server, k_EHTTPStatusCode200OK is the normal + // OK response, if you get something else you probably need to treat it as a failure. + EHTTPStatusCode m_eStatusCode; +}; + + +struct HTTPRequestHeadersReceived_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 2 }; + + // Handle value for the request that has received headers. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; +}; + +struct HTTPRequestDataReceived_t +{ + enum { k_iCallback = k_iClientHTTPCallbacks + 3 }; + + // Handle value for the request that has received data. + HTTPRequestHandle m_hRequest; + + // Context value that the user defined on the request that this callback is associated with, 0 if + // no context value was set. + uint64 m_ulContextValue; + + + // Offset to provide to GetHTTPStreamingResponseBodyData to get this chunk of data + uint32 m_cOffset; + + // Size to provide to GetHTTPStreamingResponseBodyData to get this chunk of data + uint32 m_cBytesReceived; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMHTTP_H \ No newline at end of file diff --git a/rehlds/public/steam/isteammatchmaking.h b/rehlds/public/steam/isteammatchmaking.h new file mode 100644 index 0000000..829c509 --- /dev/null +++ b/rehlds/public/steam/isteammatchmaking.h @@ -0,0 +1,731 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to steam managing game server/client match making +// +//============================================================================= + +#ifndef ISTEAMMATCHMAKING +#define ISTEAMMATCHMAKING +#ifdef _WIN32 +#pragma once +#endif + +#include "steamtypes.h" +#include "steamclientpublic.h" +#include "matchmakingtypes.h" +#include "isteamclient.h" +#include "isteamfriends.h" + +// lobby type description +enum ELobbyType +{ + k_ELobbyTypePrivate = 0, // only way to join the lobby is to invite to someone else + k_ELobbyTypeFriendsOnly = 1, // shows for friends or invitees, but not in lobby list + k_ELobbyTypePublic = 2, // visible for friends and in lobby list + k_ELobbyTypeInvisible = 3, // returned by search, but not visible to other friends + // useful if you want a user in two lobbies, for example matching groups together + // a user can be in only one regular lobby, and up to two invisible lobbies +}; + +// lobby search filter tools +enum ELobbyComparison +{ + k_ELobbyComparisonEqualToOrLessThan = -2, + k_ELobbyComparisonLessThan = -1, + k_ELobbyComparisonEqual = 0, + k_ELobbyComparisonGreaterThan = 1, + k_ELobbyComparisonEqualToOrGreaterThan = 2, + k_ELobbyComparisonNotEqual = 3, +}; + +// lobby search distance. Lobby results are sorted from closest to farthest. +enum ELobbyDistanceFilter +{ + k_ELobbyDistanceFilterClose, // only lobbies in the same immediate region will be returned + k_ELobbyDistanceFilterDefault, // only lobbies in the same region or near by regions + k_ELobbyDistanceFilterFar, // for games that don't have many latency requirements, will return lobbies about half-way around the globe + k_ELobbyDistanceFilterWorldwide, // no filtering, will match lobbies as far as India to NY (not recommended, expect multiple seconds of latency between the clients) +}; + +// maximum number of characters a lobby metadata key can be +#define k_nMaxLobbyKeyLength 255 + +//----------------------------------------------------------------------------- +// Purpose: Functions for match making services for clients to get to favorites +// and to operate on game lobbies. +//----------------------------------------------------------------------------- +class ISteamMatchmaking +{ +public: + // game server favorites storage + // saves basic details about a multiplayer game server locally + + // returns the number of favorites servers the user has stored + virtual int GetFavoriteGameCount() = 0; + + // returns the details of the game server + // iGame is of range [0,GetFavoriteGameCount()) + // *pnIP, *pnConnPort are filled in the with IP:port of the game server + // *punFlags specify whether the game server was stored as an explicit favorite or in the history of connections + // *pRTime32LastPlayedOnServer is filled in the with the Unix time the favorite was added + virtual bool GetFavoriteGame( int iGame, AppId_t *pnAppID, uint32 *pnIP, uint16 *pnConnPort, uint16 *pnQueryPort, uint32 *punFlags, uint32 *pRTime32LastPlayedOnServer ) = 0; + + // adds the game server to the local list; updates the time played of the server if it already exists in the list + virtual int AddFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags, uint32 rTime32LastPlayedOnServer ) =0; + + // removes the game server from the local storage; returns true if one was removed + virtual bool RemoveFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags ) = 0; + + /////// + // Game lobby functions + + // Get a list of relevant lobbies + // this is an asynchronous request + // results will be returned by LobbyMatchList_t callback & call result, with the number of lobbies found + // this will never return lobbies that are full + // to add more filter, the filter calls below need to be call before each and every RequestLobbyList() call + // use the CCallResult<> object in steam_api.h to match the SteamAPICall_t call result to a function in an object, e.g. + /* + class CMyLobbyListManager + { + CCallResult m_CallResultLobbyMatchList; + void FindLobbies() + { + // SteamMatchmaking()->AddRequestLobbyListFilter*() functions would be called here, before RequestLobbyList() + SteamAPICall_t hSteamAPICall = SteamMatchmaking()->RequestLobbyList(); + m_CallResultLobbyMatchList.Set( hSteamAPICall, this, &CMyLobbyListManager::OnLobbyMatchList ); + } + + void OnLobbyMatchList( LobbyMatchList_t *pLobbyMatchList, bool bIOFailure ) + { + // lobby list has be retrieved from Steam back-end, use results + } + } + */ + // + virtual SteamAPICall_t RequestLobbyList() = 0; + // filters for lobbies + // this needs to be called before RequestLobbyList() to take effect + // these are cleared on each call to RequestLobbyList() + virtual void AddRequestLobbyListStringFilter( const char *pchKeyToMatch, const char *pchValueToMatch, ELobbyComparison eComparisonType ) = 0; + // numerical comparison + virtual void AddRequestLobbyListNumericalFilter( const char *pchKeyToMatch, int nValueToMatch, ELobbyComparison eComparisonType ) = 0; + // returns results closest to the specified value. Multiple near filters can be added, with early filters taking precedence + virtual void AddRequestLobbyListNearValueFilter( const char *pchKeyToMatch, int nValueToBeCloseTo ) = 0; + // returns only lobbies with the specified number of slots available + virtual void AddRequestLobbyListFilterSlotsAvailable( int nSlotsAvailable ) = 0; + // sets the distance for which we should search for lobbies (based on users IP address to location map on the Steam backed) + virtual void AddRequestLobbyListDistanceFilter( ELobbyDistanceFilter eLobbyDistanceFilter ) = 0; + // sets how many results to return, the lower the count the faster it is to download the lobby results & details to the client + virtual void AddRequestLobbyListResultCountFilter( int cMaxResults ) = 0; + + virtual void AddRequestLobbyListCompatibleMembersFilter( CSteamID steamIDLobby ) = 0; + + // returns the CSteamID of a lobby, as retrieved by a RequestLobbyList call + // should only be called after a LobbyMatchList_t callback is received + // iLobby is of the range [0, LobbyMatchList_t::m_nLobbiesMatching) + // the returned CSteamID::IsValid() will be false if iLobby is out of range + virtual CSteamID GetLobbyByIndex( int iLobby ) = 0; + + // Create a lobby on the Steam servers. + // If private, then the lobby will not be returned by any RequestLobbyList() call; the CSteamID + // of the lobby will need to be communicated via game channels or via InviteUserToLobby() + // this is an asynchronous request + // results will be returned by LobbyCreated_t callback and call result; lobby is joined & ready to use at this point + // a LobbyEnter_t callback will also be received (since the local user is joining their own lobby) + virtual SteamAPICall_t CreateLobby( ELobbyType eLobbyType, int cMaxMembers ) = 0; + + // Joins an existing lobby + // this is an asynchronous request + // results will be returned by LobbyEnter_t callback & call result, check m_EChatRoomEnterResponse to see if was successful + // lobby metadata is available to use immediately on this call completing + virtual SteamAPICall_t JoinLobby( CSteamID steamIDLobby ) = 0; + + // Leave a lobby; this will take effect immediately on the client side + // other users in the lobby will be notified by a LobbyChatUpdate_t callback + virtual void LeaveLobby( CSteamID steamIDLobby ) = 0; + + // Invite another user to the lobby + // the target user will receive a LobbyInvite_t callback + // will return true if the invite is successfully sent, whether or not the target responds + // returns false if the local user is not connected to the Steam servers + // if the other user clicks the join link, a GameLobbyJoinRequested_t will be posted if the user is in-game, + // or if the game isn't running yet the game will be launched with the parameter +connect_lobby <64-bit lobby id> + virtual bool InviteUserToLobby( CSteamID steamIDLobby, CSteamID steamIDInvitee ) = 0; + + // Lobby iteration, for viewing details of users in a lobby + // only accessible if the lobby user is a member of the specified lobby + // persona information for other lobby members (name, avatar, etc.) will be asynchronously received + // and accessible via ISteamFriends interface + + // returns the number of users in the specified lobby + virtual int GetNumLobbyMembers( CSteamID steamIDLobby ) = 0; + // returns the CSteamID of a user in the lobby + // iMember is of range [0,GetNumLobbyMembers()) + // note that the current user must be in a lobby to retrieve CSteamIDs of other users in that lobby + virtual CSteamID GetLobbyMemberByIndex( CSteamID steamIDLobby, int iMember ) = 0; + + // Get data associated with this lobby + // takes a simple key, and returns the string associated with it + // "" will be returned if no value is set, or if steamIDLobby is invalid + virtual const char *GetLobbyData( CSteamID steamIDLobby, const char *pchKey ) = 0; + // Sets a key/value pair in the lobby metadata + // each user in the lobby will be broadcast this new value, and any new users joining will receive any existing data + // this can be used to set lobby names, map, etc. + // to reset a key, just set it to "" + // other users in the lobby will receive notification of the lobby data change via a LobbyDataUpdate_t callback + virtual bool SetLobbyData( CSteamID steamIDLobby, const char *pchKey, const char *pchValue ) = 0; + + // returns the number of metadata keys set on the specified lobby + virtual int GetLobbyDataCount( CSteamID steamIDLobby ) = 0; + + // returns a lobby metadata key/values pair by index, of range [0, GetLobbyDataCount()) + virtual bool GetLobbyDataByIndex( CSteamID steamIDLobby, int iLobbyData, char *pchKey, int cchKeyBufferSize, char *pchValue, int cchValueBufferSize ) = 0; + + // removes a metadata key from the lobby + virtual bool DeleteLobbyData( CSteamID steamIDLobby, const char *pchKey ) = 0; + + // Gets per-user metadata for someone in this lobby + virtual const char *GetLobbyMemberData( CSteamID steamIDLobby, CSteamID steamIDUser, const char *pchKey ) = 0; + // Sets per-user metadata (for the local user implicitly) + virtual void SetLobbyMemberData( CSteamID steamIDLobby, const char *pchKey, const char *pchValue ) = 0; + + // Broadcasts a chat message to the all the users in the lobby + // users in the lobby (including the local user) will receive a LobbyChatMsg_t callback + // returns true if the message is successfully sent + // pvMsgBody can be binary or text data, up to 4k + // if pvMsgBody is text, cubMsgBody should be strlen( text ) + 1, to include the null terminator + virtual bool SendLobbyChatMsg( CSteamID steamIDLobby, const void *pvMsgBody, int cubMsgBody ) = 0; + // Get a chat message as specified in a LobbyChatMsg_t callback + // iChatID is the LobbyChatMsg_t::m_iChatID value in the callback + // *pSteamIDUser is filled in with the CSteamID of the member + // *pvData is filled in with the message itself + // return value is the number of bytes written into the buffer + virtual int GetLobbyChatEntry( CSteamID steamIDLobby, int iChatID, CSteamID *pSteamIDUser, void *pvData, int cubData, EChatEntryType *peChatEntryType ) = 0; + + // Refreshes metadata for a lobby you're not necessarily in right now + // you never do this for lobbies you're a member of, only if your + // this will send down all the metadata associated with a lobby + // this is an asynchronous call + // returns false if the local user is not connected to the Steam servers + // results will be returned by a LobbyDataUpdate_t callback + // if the specified lobby doesn't exist, LobbyDataUpdate_t::m_bSuccess will be set to false + virtual bool RequestLobbyData( CSteamID steamIDLobby ) = 0; + + // sets the game server associated with the lobby + // usually at this point, the users will join the specified game server + // either the IP/Port or the steamID of the game server has to be valid, depending on how you want the clients to be able to connect + virtual void SetLobbyGameServer( CSteamID steamIDLobby, uint32 unGameServerIP, uint16 unGameServerPort, CSteamID steamIDGameServer ) = 0; + // returns the details of a game server set in a lobby - returns false if there is no game server set, or that lobby doesn't exist + virtual bool GetLobbyGameServer( CSteamID steamIDLobby, uint32 *punGameServerIP, uint16 *punGameServerPort, CSteamID *psteamIDGameServer ) = 0; + + // set the limit on the # of users who can join the lobby + virtual bool SetLobbyMemberLimit( CSteamID steamIDLobby, int cMaxMembers ) = 0; + // returns the current limit on the # of users who can join the lobby; returns 0 if no limit is defined + virtual int GetLobbyMemberLimit( CSteamID steamIDLobby ) = 0; + + // updates which type of lobby it is + // only lobbies that are k_ELobbyTypePublic or k_ELobbyTypeInvisible, and are set to joinable, will be returned by RequestLobbyList() calls + virtual bool SetLobbyType( CSteamID steamIDLobby, ELobbyType eLobbyType ) = 0; + + // sets whether or not a lobby is joinable - defaults to true for a new lobby + // if set to false, no user can join, even if they are a friend or have been invited + virtual bool SetLobbyJoinable( CSteamID steamIDLobby, bool bLobbyJoinable ) = 0; + + // returns the current lobby owner + // you must be a member of the lobby to access this + // there always one lobby owner - if the current owner leaves, another user will become the owner + // it is possible (bur rare) to join a lobby just as the owner is leaving, thus entering a lobby with self as the owner + virtual CSteamID GetLobbyOwner( CSteamID steamIDLobby ) = 0; + + // changes who the lobby owner is + // you must be the lobby owner for this to succeed, and steamIDNewOwner must be in the lobby + // after completion, the local user will no longer be the owner + virtual bool SetLobbyOwner( CSteamID steamIDLobby, CSteamID steamIDNewOwner ) = 0; + + // link two lobbies for the purposes of checking player compatibility + // you must be the lobby owner of both lobbies + virtual bool SetLinkedLobby( CSteamID steamIDLobby, CSteamID steamIDLobbyDependent ) = 0; + +#ifdef _PS3 + // changes who the lobby owner is + // you must be the lobby owner for this to succeed, and steamIDNewOwner must be in the lobby + // after completion, the local user will no longer be the owner + virtual void CheckForPSNGameBootInvite( unsigned int iGameBootAttributes ) = 0; +#endif +}; +#define STEAMMATCHMAKING_INTERFACE_VERSION "SteamMatchMaking009" + + +//----------------------------------------------------------------------------- +// Callback interfaces for server list functions (see ISteamMatchmakingServers below) +// +// The idea here is that your game code implements objects that implement these +// interfaces to receive callback notifications after calling asynchronous functions +// inside the ISteamMatchmakingServers() interface below. +// +// This is different than normal Steam callback handling due to the potentially +// large size of server lists. +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Typedef for handle type you will receive when requesting server list. +//----------------------------------------------------------------------------- +typedef void* HServerListRequest; + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after a server list refresh +// or an individual server update. +// +// Since you get these callbacks after requesting full list refreshes you will +// usually implement this interface inside an object like CServerBrowser. If that +// object is getting destructed you should use ISteamMatchMakingServers()->CancelQuery() +// to cancel any in-progress queries so you don't get a callback into the destructed +// object and crash. +//----------------------------------------------------------------------------- +class ISteamMatchmakingServerListResponse +{ +public: + // Server has responded ok with updated data + virtual void ServerResponded( HServerListRequest hRequest, int iServer ) = 0; + + // Server has failed to respond + virtual void ServerFailedToRespond( HServerListRequest hRequest, int iServer ) = 0; + + // A list refresh you had initiated is now 100% completed + virtual void RefreshComplete( HServerListRequest hRequest, EMatchMakingServerResponse response ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after pinging an individual server +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->PingServer() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingPingResponse +{ +public: + // Server has responded successfully and has updated data + virtual void ServerResponded( gameserveritem_t &server ) = 0; + + // Server failed to respond to the ping request + virtual void ServerFailedToRespond() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after requesting details on +// who is playing on a particular server. +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->PlayerDetails() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingPlayersResponse +{ +public: + // Got data on a new player on the server -- you'll get this callback once per player + // on the server which you have requested player data on. + virtual void AddPlayerToList( const char *pchName, int nScore, float flTimePlayed ) = 0; + + // The server failed to respond to the request for player details + virtual void PlayersFailedToRespond() = 0; + + // The server has finished responding to the player details request + // (ie, you won't get anymore AddPlayerToList callbacks) + virtual void PlayersRefreshComplete() = 0; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for receiving responses after requesting rules +// details on a particular server. +// +// These callbacks all occur in response to querying an individual server +// via the ISteamMatchmakingServers()->ServerRules() call below. If you are +// destructing an object that implements this interface then you should call +// ISteamMatchmakingServers()->CancelServerQuery() passing in the handle to the query +// which is in progress. Failure to cancel in progress queries when destructing +// a callback handler may result in a crash when a callback later occurs. +//----------------------------------------------------------------------------- +class ISteamMatchmakingRulesResponse +{ +public: + // Got data on a rule on the server -- you'll get one of these per rule defined on + // the server you are querying + virtual void RulesResponded( const char *pchRule, const char *pchValue ) = 0; + + // The server failed to respond to the request for rule details + virtual void RulesFailedToRespond() = 0; + + // The server has finished responding to the rule details request + // (ie, you won't get anymore RulesResponded callbacks) + virtual void RulesRefreshComplete() = 0; +}; + + +//----------------------------------------------------------------------------- +// Typedef for handle type you will receive when querying details on an individual server. +//----------------------------------------------------------------------------- +typedef int HServerQuery; +const int HSERVERQUERY_INVALID = 0xffffffff; + +//----------------------------------------------------------------------------- +// Purpose: Functions for match making services for clients to get to game lists and details +//----------------------------------------------------------------------------- +class ISteamMatchmakingServers +{ +public: + // Request a new list of servers of a particular type. These calls each correspond to one of the EMatchMakingType values. + // Each call allocates a new asynchronous request object. + // Request object must be released by calling ReleaseRequest( hServerListRequest ) + virtual HServerListRequest RequestInternetServerList( AppId_t iApp, MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestLANServerList( AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestFriendsServerList( AppId_t iApp, MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestFavoritesServerList( AppId_t iApp, MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestHistoryServerList( AppId_t iApp, MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + virtual HServerListRequest RequestSpectatorServerList( AppId_t iApp, MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse ) = 0; + + // Releases the asynchronous request object and cancels any pending query on it if there's a pending query in progress. + // RefreshComplete callback is not posted when request is released. + virtual void ReleaseRequest( HServerListRequest hServerListRequest ) = 0; + + /* the filter operation codes that go in the key part of MatchMakingKeyValuePair_t should be one of these: + + "map" + - Server passes the filter if the server is playing the specified map. + "gamedataand" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) contains all of the + specified strings. The value field is a comma-delimited list of strings to match. + "gamedataor" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) contains at least one of the + specified strings. The value field is a comma-delimited list of strings to match. + "gamedatanor" + - Server passes the filter if the server's game data (ISteamGameServer::SetGameData) does not contain any + of the specified strings. The value field is a comma-delimited list of strings to check. + "gametagsand" + - Server passes the filter if the server's game tags (ISteamGameServer::SetGameTags) contains all + of the specified strings. The value field is a comma-delimited list of strings to check. + "gametagsnor" + - Server passes the filter if the server's game tags (ISteamGameServer::SetGameTags) does not contain any + of the specified strings. The value field is a comma-delimited list of strings to check. + "and" (x1 && x2 && ... && xn) + "or" (x1 || x2 || ... || xn) + "nand" !(x1 && x2 && ... && xn) + "nor" !(x1 || x2 || ... || xn) + - Performs Boolean operation on the following filters. The operand to this filter specifies + the "size" of the Boolean inputs to the operation, in Key/value pairs. (The keyvalue + pairs must immediately follow, i.e. this is a prefix logical operator notation.) + In the simplest case where Boolean expressions are not nested, this is simply + the number of operands. + + For example, to match servers on a particular map or with a particular tag, would would + use these filters. + + ( server.map == "cp_dustbowl" || server.gametags.contains("payload") ) + "or", "2" + "map", "cp_dustbowl" + "gametagsand", "payload" + + If logical inputs are nested, then the operand specifies the size of the entire + "length" of its operands, not the number of immediate children. + + ( server.map == "cp_dustbowl" || ( server.gametags.contains("payload") && !server.gametags.contains("payloadrace") ) ) + "or", "4" + "map", "cp_dustbowl" + "and", "2" + "gametagsand", "payload" + "gametagsnor", "payloadrace" + + Unary NOT can be achieved using either "nand" or "nor" with a single operand. + + "addr" + - Server passes the filter if the server's query address matches the specified IP or IP:port. + "gameaddr" + - Server passes the filter if the server's game address matches the specified IP or IP:port. + + The following filter operations ignore the "value" part of MatchMakingKeyValuePair_t + + "dedicated" + - Server passes the filter if it passed true to SetDedicatedServer. + "secure" + - Server passes the filter if the server is VAC-enabled. + "notfull" + - Server passes the filter if the player count is less than the reported max player count. + "hasplayers" + - Server passes the filter if the player count is greater than zero. + "noplayers" + - Server passes the filter if it doesn't have any players. + "linux" + - Server passes the filter if it's a linux server + */ + + // Get details on a given server in the list, you can get the valid range of index + // values by calling GetServerCount(). You will also receive index values in + // ISteamMatchmakingServerListResponse::ServerResponded() callbacks + virtual gameserveritem_t *GetServerDetails( HServerListRequest hRequest, int iServer ) = 0; + + // Cancel an request which is operation on the given list type. You should call this to cancel + // any in-progress requests before destructing a callback object that may have been passed + // to one of the above list request calls. Not doing so may result in a crash when a callback + // occurs on the destructed object. + // Canceling a query does not release the allocated request handle. + // The request handle must be released using ReleaseRequest( hRequest ) + virtual void CancelQuery( HServerListRequest hRequest ) = 0; + + // Ping every server in your list again but don't update the list of servers + // Query callback installed when the server list was requested will be used + // again to post notifications and RefreshComplete, so the callback must remain + // valid until another RefreshComplete is called on it or the request + // is released with ReleaseRequest( hRequest ) + virtual void RefreshQuery( HServerListRequest hRequest ) = 0; + + // Returns true if the list is currently refreshing its server list + virtual bool IsRefreshing( HServerListRequest hRequest ) = 0; + + // How many servers in the given list, GetServerDetails above takes 0... GetServerCount() - 1 + virtual int GetServerCount( HServerListRequest hRequest ) = 0; + + // Refresh a single server inside of a query (rather than all the servers ) + virtual void RefreshServer( HServerListRequest hRequest, int iServer ) = 0; + + + //----------------------------------------------------------------------------- + // Queries to individual servers directly via IP/Port + //----------------------------------------------------------------------------- + + // Request updated ping time and other details from a single server + virtual HServerQuery PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse ) = 0; + + // Request the list of players currently playing on a server + virtual HServerQuery PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse ) = 0; + + // Request the list of rules that the server is running (See ISteamGameServer::SetKeyValue() to set the rules server side) + virtual HServerQuery ServerRules( uint32 unIP, uint16 usPort, ISteamMatchmakingRulesResponse *pRequestServersResponse ) = 0; + + // Cancel an outstanding Ping/Players/Rules query from above. You should call this to cancel + // any in-progress requests before destructing a callback object that may have been passed + // to one of the above calls to avoid crashing when callbacks occur. + virtual void CancelServerQuery( HServerQuery hServerQuery ) = 0; +}; +#define STEAMMATCHMAKINGSERVERS_INTERFACE_VERSION "SteamMatchMakingServers002" + +// game server flags +const uint32 k_unFavoriteFlagNone = 0x00; +const uint32 k_unFavoriteFlagFavorite = 0x01; // this game favorite entry is for the favorites list +const uint32 k_unFavoriteFlagHistory = 0x02; // this game favorite entry is for the history list + + +//----------------------------------------------------------------------------- +// Purpose: Used in ChatInfo messages - fields specific to a chat member - must fit in a uint32 +//----------------------------------------------------------------------------- +enum EChatMemberStateChange +{ + // Specific to joining / leaving the chatroom + k_EChatMemberStateChangeEntered = 0x0001, // This user has joined or is joining the chat room + k_EChatMemberStateChangeLeft = 0x0002, // This user has left or is leaving the chat room + k_EChatMemberStateChangeDisconnected = 0x0004, // User disconnected without leaving the chat first + k_EChatMemberStateChangeKicked = 0x0008, // User kicked + k_EChatMemberStateChangeBanned = 0x0010, // User kicked and banned +}; + +// returns true of the flags indicate that a user has been removed from the chat +#define BChatMemberStateChangeRemoved( rgfChatMemberStateChangeFlags ) ( rgfChatMemberStateChangeFlags & ( k_EChatMemberStateChangeDisconnected | k_EChatMemberStateChangeLeft | k_EChatMemberStateChangeKicked | k_EChatMemberStateChangeBanned ) ) + + +//----------------------------------------------------------------------------- +// Callbacks for ISteamMatchmaking (which go through the regular Steam callback registration system) +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: a server was added/removed from the favorites list, you should refresh now +//----------------------------------------------------------------------------- +struct FavoritesListChanged_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 2 }; + uint32 m_nIP; // an IP of 0 means reload the whole list, any other value means just one server + uint32 m_nQueryPort; + uint32 m_nConnPort; + uint32 m_nAppID; + uint32 m_nFlags; + bool m_bAdd; // true if this is adding the entry, otherwise it is a remove +}; + + +//----------------------------------------------------------------------------- +// Purpose: Someone has invited you to join a Lobby +// normally you don't need to do anything with this, since +// the Steam UI will also display a ' has invited you to the lobby, join?' dialog +// +// if the user outside a game chooses to join, your game will be launched with the parameter "+connect_lobby <64-bit lobby id>", +// or with the callback GameLobbyJoinRequested_t if they're already in-game +//----------------------------------------------------------------------------- +struct LobbyInvite_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 3 }; + + uint64 m_ulSteamIDUser; // Steam ID of the person making the invite + uint64 m_ulSteamIDLobby; // Steam ID of the Lobby + uint64 m_ulGameID; // GameID of the Lobby +}; + + +//----------------------------------------------------------------------------- +// Purpose: Sent on entering a lobby, or on failing to enter +// m_EChatRoomEnterResponse will be set to k_EChatRoomEnterResponseSuccess on success, +// or a higher value on failure (see enum EChatRoomEnterResponse) +//----------------------------------------------------------------------------- +struct LobbyEnter_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 4 }; + + uint64 m_ulSteamIDLobby; // SteamID of the Lobby you have entered + uint32 m_rgfChatPermissions; // Permissions of the current user + bool m_bLocked; // If true, then only invited users may join + uint32 m_EChatRoomEnterResponse; // EChatRoomEnterResponse +}; + + +//----------------------------------------------------------------------------- +// Purpose: The lobby metadata has changed +// if m_ulSteamIDMember is the steamID of a lobby member, use GetLobbyMemberData() to access per-user details +// if m_ulSteamIDMember == m_ulSteamIDLobby, use GetLobbyData() to access lobby metadata +//----------------------------------------------------------------------------- +struct LobbyDataUpdate_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 5 }; + + uint64 m_ulSteamIDLobby; // steamID of the Lobby + uint64 m_ulSteamIDMember; // steamID of the member whose data changed, or the room itself + uint8 m_bSuccess; // true if we lobby data was successfully changed; + // will only be false if RequestLobbyData() was called on a lobby that no longer exists +}; + + +//----------------------------------------------------------------------------- +// Purpose: The lobby chat room state has changed +// this is usually sent when a user has joined or left the lobby +//----------------------------------------------------------------------------- +struct LobbyChatUpdate_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 6 }; + + uint64 m_ulSteamIDLobby; // Lobby ID + uint64 m_ulSteamIDUserChanged; // user who's status in the lobby just changed - can be recipient + uint64 m_ulSteamIDMakingChange; // Chat member who made the change (different from SteamIDUserChange if kicking, muting, etc.) + // for example, if one user kicks another from the lobby, this will be set to the id of the user who initiated the kick + uint32 m_rgfChatMemberStateChange; // bitfield of EChatMemberStateChange values +}; + + +//----------------------------------------------------------------------------- +// Purpose: A chat message for this lobby has been sent +// use GetLobbyChatEntry( m_iChatID ) to retrieve the contents of this message +//----------------------------------------------------------------------------- +struct LobbyChatMsg_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 7 }; + + uint64 m_ulSteamIDLobby; // the lobby id this is in + uint64 m_ulSteamIDUser; // steamID of the user who has sent this message + uint8 m_eChatEntryType; // type of message + uint32 m_iChatID; // index of the chat entry to lookup +}; + + +//----------------------------------------------------------------------------- +// Purpose: A game created a game for all the members of the lobby to join, +// as triggered by a SetLobbyGameServer() +// it's up to the individual clients to take action on this; the usual +// game behavior is to leave the lobby and connect to the specified game server +//----------------------------------------------------------------------------- +struct LobbyGameCreated_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 9 }; + + uint64 m_ulSteamIDLobby; // the lobby we were in + uint64 m_ulSteamIDGameServer; // the new game server that has been created or found for the lobby members + uint32 m_unIP; // IP & Port of the game server (if any) + uint16 m_usPort; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Number of matching lobbies found +// iterate the returned lobbies with GetLobbyByIndex(), from values 0 to m_nLobbiesMatching-1 +//----------------------------------------------------------------------------- +struct LobbyMatchList_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 10 }; + uint32 m_nLobbiesMatching; // Number of lobbies that matched search criteria and we have SteamIDs for +}; + + +//----------------------------------------------------------------------------- +// Purpose: posted if a user is forcefully removed from a lobby +// can occur if a user loses connection to Steam +//----------------------------------------------------------------------------- +struct LobbyKicked_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 12 }; + uint64 m_ulSteamIDLobby; // Lobby + uint64 m_ulSteamIDAdmin; // User who kicked you - possibly the ID of the lobby itself + uint8 m_bKickedDueToDisconnect; // true if you were kicked from the lobby due to the user losing connection to Steam (currently always true) +}; + + +//----------------------------------------------------------------------------- +// Purpose: Result of our request to create a Lobby +// m_eResult == k_EResultOK on success +// at this point, the lobby has been joined and is ready for use +// a LobbyEnter_t callback will also be received (since the local user is joining their own lobby) +//----------------------------------------------------------------------------- +struct LobbyCreated_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 13 }; + + EResult m_eResult; // k_EResultOK - the lobby was successfully created + // k_EResultNoConnection - your Steam client doesn't have a connection to the back-end + // k_EResultTimeout - you the message to the Steam servers, but it didn't respond + // k_EResultFail - the server responded, but with an unknown internal error + // k_EResultAccessDenied - your game isn't set to allow lobbies, or your client does haven't rights to play the game + // k_EResultLimitExceeded - your game client has created too many lobbies + + uint64 m_ulSteamIDLobby; // chat room, zero if failed +}; + +// used by now obsolete RequestFriendsLobbiesResponse_t +// enum { k_iCallback = k_iSteamMatchmakingCallbacks + 14 }; + + +//----------------------------------------------------------------------------- +// Purpose: Result of CheckForPSNGameBootInvite +// m_eResult == k_EResultOK on success +// at this point, the local user may not have finishing joining this lobby; +// game code should wait until the subsequent LobbyEnter_t callback is received +//----------------------------------------------------------------------------- +struct PSNGameBootInviteResult_t +{ + enum { k_iCallback = k_iSteamMatchmakingCallbacks + 15 }; + + bool m_bGameBootInviteExists; + CSteamID m_steamIDLobby; // Should be valid if m_bGameBootInviteExists == true +}; +#pragma pack( pop ) + + +#endif // ISTEAMMATCHMAKING diff --git a/rehlds/public/steam/isteamnetworking.h b/rehlds/public/steam/isteamnetworking.h new file mode 100644 index 0000000..15f430c --- /dev/null +++ b/rehlds/public/steam/isteamnetworking.h @@ -0,0 +1,306 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to steam managing network connections between game clients & servers +// +//============================================================================= + +#ifndef ISTEAMNETWORKING +#define ISTEAMNETWORKING +#ifdef _WIN32 +#pragma once +#endif + +#include "steamtypes.h" +#include "steamclientpublic.h" + + +// list of possible errors returned by SendP2PPacket() API +// these will be posted in the P2PSessionConnectFail_t callback +enum EP2PSessionError +{ + k_EP2PSessionErrorNone = 0, + k_EP2PSessionErrorNotRunningApp = 1, // target is not running the same game + k_EP2PSessionErrorNoRightsToApp = 2, // local user doesn't own the app that is running + k_EP2PSessionErrorDestinationNotLoggedIn = 3, // target user isn't connected to Steam + k_EP2PSessionErrorTimeout = 4, // target isn't responding, perhaps not calling AcceptP2PSessionWithUser() + // corporate firewalls can also block this (NAT traversal is not firewall traversal) + // make sure that UDP ports 3478, 4379, and 4380 are open in an outbound direction + k_EP2PSessionErrorMax = 5 +}; + +// SendP2PPacket() send types +// Typically k_EP2PSendUnreliable is what you want for UDP-like packets, k_EP2PSendReliable for TCP-like packets +enum EP2PSend +{ + // Basic UDP send. Packets can't be bigger than 1200 bytes (your typical MTU size). Can be lost, or arrive out of order (rare). + // The sending API does have some knowledge of the underlying connection, so if there is no NAT-traversal accomplished or + // there is a recognized adjustment happening on the connection, the packet will be batched until the connection is open again. + k_EP2PSendUnreliable = 0, + + // As above, but if the underlying p2p connection isn't yet established the packet will just be thrown away. Using this on the first + // packet sent to a remote host almost guarantees the packet will be dropped. + // This is only really useful for kinds of data that should never buffer up, i.e. voice payload packets + k_EP2PSendUnreliableNoDelay = 1, + + // Reliable message send. Can send up to 1MB of data in a single message. + // Does fragmentation/re-assembly of messages under the hood, as well as a sliding window for efficient sends of large chunks of data. + k_EP2PSendReliable = 2, + + // As above, but applies the Nagle algorithm to the send - sends will accumulate + // until the current MTU size (typically ~1200 bytes, but can change) or ~200ms has passed (Nagle algorithm). + // Useful if you want to send a set of smaller messages but have the coalesced into a single packet + // Since the reliable stream is all ordered, you can do several small message sends with k_EP2PSendReliableWithBuffering and then + // do a normal k_EP2PSendReliable to force all the buffered data to be sent. + k_EP2PSendReliableWithBuffering = 3, + +}; + + +// connection state to a specified user, returned by GetP2PSessionState() +// this is under-the-hood info about what's going on with a SendP2PPacket(), shouldn't be needed except for debuggin +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct P2PSessionState_t +{ + uint8 m_bConnectionActive; // true if we've got an active open connection + uint8 m_bConnecting; // true if we're currently trying to establish a connection + uint8 m_eP2PSessionError; // last error recorded (see enum above) + uint8 m_bUsingRelay; // true if it's going through a relay server (TURN) + int32 m_nBytesQueuedForSend; + int32 m_nPacketsQueuedForSend; + uint32 m_nRemoteIP; // potential IP:Port of remote host. Could be TURN server. + uint16 m_nRemotePort; // Only exists for compatibility with older authentication api's +}; +#pragma pack( pop ) + + +// handle to a socket +typedef uint32 SNetSocket_t; // CreateP2PConnectionSocket() +typedef uint32 SNetListenSocket_t; // CreateListenSocket() + +// connection progress indicators, used by CreateP2PConnectionSocket() +enum ESNetSocketState +{ + k_ESNetSocketStateInvalid = 0, + + // communication is valid + k_ESNetSocketStateConnected = 1, + + // states while establishing a connection + k_ESNetSocketStateInitiated = 10, // the connection state machine has started + + // p2p connections + k_ESNetSocketStateLocalCandidatesFound = 11, // we've found our local IP info + k_ESNetSocketStateReceivedRemoteCandidates = 12,// we've received information from the remote machine, via the Steam back-end, about their IP info + + // direct connections + k_ESNetSocketStateChallengeHandshake = 15, // we've received a challenge packet from the server + + // failure states + k_ESNetSocketStateDisconnecting = 21, // the API shut it down, and we're in the process of telling the other end + k_ESNetSocketStateLocalDisconnect = 22, // the API shut it down, and we've completed shutdown + k_ESNetSocketStateTimeoutDuringConnect = 23, // we timed out while trying to creating the connection + k_ESNetSocketStateRemoteEndDisconnected = 24, // the remote end has disconnected from us + k_ESNetSocketStateConnectionBroken = 25, // connection has been broken; either the other end has disappeared or our local network connection has broke + +}; + +// describes how the socket is currently connected +enum ESNetSocketConnectionType +{ + k_ESNetSocketConnectionTypeNotConnected = 0, + k_ESNetSocketConnectionTypeUDP = 1, + k_ESNetSocketConnectionTypeUDPRelay = 2, +}; + + +//----------------------------------------------------------------------------- +// Purpose: Functions for making connections and sending data between clients, +// traversing NAT's where possible +//----------------------------------------------------------------------------- +class ISteamNetworking +{ +public: + //////////////////////////////////////////////////////////////////////////////////////////// + // Session-less connection functions + // automatically establishes NAT-traversing or Relay server connections + + // Sends a P2P packet to the specified user + // UDP-like, unreliable and a max packet size of 1200 bytes + // the first packet send may be delayed as the NAT-traversal code runs + // if we can't get through to the user, an error will be posted via the callback P2PSessionConnectFail_t + // see EP2PSend enum above for the descriptions of the different ways of sending packets + // + // nChannel is a routing number you can use to help route message to different systems - you'll have to call ReadP2PPacket() + // with the same channel number in order to retrieve the data on the other end + // using different channels to talk to the same user will still use the same underlying p2p connection, saving on resources + virtual bool SendP2PPacket( CSteamID steamIDRemote, const void *pubData, uint32 cubData, EP2PSend eP2PSendType, int nChannel = 0 ) = 0; + + // returns true if any data is available for read, and the amount of data that will need to be read + virtual bool IsP2PPacketAvailable( uint32 *pcubMsgSize, int nChannel = 0 ) = 0; + + // reads in a packet that has been sent from another user via SendP2PPacket() + // returns the size of the message and the steamID of the user who sent it in the last two parameters + // if the buffer passed in is too small, the message will be truncated + // this call is not blocking, and will return false if no data is available + virtual bool ReadP2PPacket( void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, CSteamID *psteamIDRemote, int nChannel = 0 ) = 0; + + // AcceptP2PSessionWithUser() should only be called in response to a P2PSessionRequest_t callback + // P2PSessionRequest_t will be posted if another user tries to send you a packet that you haven't talked to yet + // if you don't want to talk to the user, just ignore the request + // if the user continues to send you packets, another P2PSessionRequest_t will be posted periodically + // this may be called multiple times for a single user + // (if you've called SendP2PPacket() on the other user, this implicitly accepts the session request) + virtual bool AcceptP2PSessionWithUser( CSteamID steamIDRemote ) = 0; + + // call CloseP2PSessionWithUser() when you're done talking to a user, will free up resources under-the-hood + // if the remote user tries to send data to you again, another P2PSessionRequest_t callback will be posted + virtual bool CloseP2PSessionWithUser( CSteamID steamIDRemote ) = 0; + + // call CloseP2PChannelWithUser() when you're done talking to a user on a specific channel. Once all channels + // open channels to a user have been closed, the open session to the user will be closed and new data from this + // user will trigger a P2PSessionRequest_t callback + virtual bool CloseP2PChannelWithUser( CSteamID steamIDRemote, int nChannel ) = 0; + + // fills out P2PSessionState_t structure with details about the underlying connection to the user + // should only needed for debugging purposes + // returns false if no connection exists to the specified user + virtual bool GetP2PSessionState( CSteamID steamIDRemote, P2PSessionState_t *pConnectionState ) = 0; + + // Allow P2P connections to fall back to being relayed through the Steam servers if a direct connection + // or NAT-traversal cannot be established. Only applies to connections created after setting this value, + // or to existing connections that need to automatically reconnect after this value is set. + // + // P2P packet relay is allowed by default + virtual bool AllowP2PPacketRelay( bool bAllow ) = 0; + + + //////////////////////////////////////////////////////////////////////////////////////////// + // LISTEN / CONNECT style interface functions + // + // This is an older set of functions designed around the Berkeley TCP sockets model + // it's preferential that you use the above P2P functions, they're more robust + // and these older functions will be removed eventually + // + //////////////////////////////////////////////////////////////////////////////////////////// + + + // creates a socket and listens others to connect + // will trigger a SocketStatusCallback_t callback on another client connecting + // nVirtualP2PPort is the unique ID that the client will connect to, in case you have multiple ports + // this can usually just be 0 unless you want multiple sets of connections + // unIP is the local IP address to bind to + // pass in 0 if you just want the default local IP + // unPort is the port to use + // pass in 0 if you don't want users to be able to connect via IP/Port, but expect to be always peer-to-peer connections only + virtual SNetListenSocket_t CreateListenSocket( int nVirtualP2PPort, uint32 nIP, uint16 nPort, bool bAllowUseOfPacketRelay ) = 0; + + // creates a socket and begin connection to a remote destination + // can connect via a known steamID (client or game server), or directly to an IP + // on success will trigger a SocketStatusCallback_t callback + // on failure or timeout will trigger a SocketStatusCallback_t callback with a failure code in m_eSNetSocketState + virtual SNetSocket_t CreateP2PConnectionSocket( CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay ) = 0; + virtual SNetSocket_t CreateConnectionSocket( uint32 nIP, uint16 nPort, int nTimeoutSec ) = 0; + + // disconnects the connection to the socket, if any, and invalidates the handle + // any unread data on the socket will be thrown away + // if bNotifyRemoteEnd is set, socket will not be completely destroyed until the remote end acknowledges the disconnect + virtual bool DestroySocket( SNetSocket_t hSocket, bool bNotifyRemoteEnd ) = 0; + // destroying a listen socket will automatically kill all the regular sockets generated from it + virtual bool DestroyListenSocket( SNetListenSocket_t hSocket, bool bNotifyRemoteEnd ) = 0; + + // sending data + // must be a handle to a connected socket + // data is all sent via UDP, and thus send sizes are limited to 1200 bytes; after this, many routers will start dropping packets + // use the reliable flag with caution; although the resend rate is pretty aggressive, + // it can still cause stalls in receiving data (like TCP) + virtual bool SendDataOnSocket( SNetSocket_t hSocket, void *pubData, uint32 cubData, bool bReliable ) = 0; + + // receiving data + // returns false if there is no data remaining + // fills out *pcubMsgSize with the size of the next message, in bytes + virtual bool IsDataAvailableOnSocket( SNetSocket_t hSocket, uint32 *pcubMsgSize ) = 0; + + // fills in pubDest with the contents of the message + // messages are always complete, of the same size as was sent (i.e. packetized, not streaming) + // if *pcubMsgSize < cubDest, only partial data is written + // returns false if no data is available + virtual bool RetrieveDataFromSocket( SNetSocket_t hSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize ) = 0; + + // checks for data from any socket that has been connected off this listen socket + // returns false if there is no data remaining + // fills out *pcubMsgSize with the size of the next message, in bytes + // fills out *phSocket with the socket that data is available on + virtual bool IsDataAvailable( SNetListenSocket_t hListenSocket, uint32 *pcubMsgSize, SNetSocket_t *phSocket ) = 0; + + // retrieves data from any socket that has been connected off this listen socket + // fills in pubDest with the contents of the message + // messages are always complete, of the same size as was sent (i.e. packetized, not streaming) + // if *pcubMsgSize < cubDest, only partial data is written + // returns false if no data is available + // fills out *phSocket with the socket that data is available on + virtual bool RetrieveData( SNetListenSocket_t hListenSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, SNetSocket_t *phSocket ) = 0; + + // returns information about the specified socket, filling out the contents of the pointers + virtual bool GetSocketInfo( SNetSocket_t hSocket, CSteamID *pSteamIDRemote, int *peSocketStatus, uint32 *punIPRemote, uint16 *punPortRemote ) = 0; + + // returns which local port the listen socket is bound to + // *pnIP and *pnPort will be 0 if the socket is set to listen for P2P connections only + virtual bool GetListenSocketInfo( SNetListenSocket_t hListenSocket, uint32 *pnIP, uint16 *pnPort ) = 0; + + // returns true to describe how the socket ended up connecting + virtual ESNetSocketConnectionType GetSocketConnectionType( SNetSocket_t hSocket ) = 0; + + // max packet size, in bytes + virtual int GetMaxPacketSize( SNetSocket_t hSocket ) = 0; +}; +#define STEAMNETWORKING_INTERFACE_VERSION "SteamNetworking005" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +// callback notification - a user wants to talk to us over the P2P channel via the SendP2PPacket() API +// in response, a call to AcceptP2PPacketsFromUser() needs to be made, if you want to talk with them +struct P2PSessionRequest_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 2 }; + CSteamID m_steamIDRemote; // user who wants to talk to us +}; + + +// callback notification - packets can't get through to the specified user via the SendP2PPacket() API +// all packets queued packets unsent at this point will be dropped +// further attempts to send will retry making the connection (but will be dropped if we fail again) +struct P2PSessionConnectFail_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 3 }; + CSteamID m_steamIDRemote; // user we were sending packets to + uint8 m_eP2PSessionError; // EP2PSessionError indicating why we're having trouble +}; + + +// callback notification - status of a socket has changed +// used as part of the CreateListenSocket() / CreateP2PConnectionSocket() +struct SocketStatusCallback_t +{ + enum { k_iCallback = k_iSteamNetworkingCallbacks + 1 }; + SNetSocket_t m_hSocket; // the socket used to send/receive data to the remote host + SNetListenSocket_t m_hListenSocket; // this is the server socket that we were listening on; NULL if this was an outgoing connection + CSteamID m_steamIDRemote; // remote steamID we have connected to, if it has one + int m_eSNetSocketState; // socket state, ESNetSocketState +}; + +#pragma pack( pop ) + +#endif // ISTEAMNETWORKING diff --git a/rehlds/public/steam/isteamremotestorage.h b/rehlds/public/steam/isteamremotestorage.h new file mode 100644 index 0000000..d282556 --- /dev/null +++ b/rehlds/public/steam/isteamremotestorage.h @@ -0,0 +1,610 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: public interface to user remote file storage in Steam +// +//============================================================================= + +#ifndef ISTEAMREMOTESTORAGE_H +#define ISTEAMREMOTESTORAGE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + + +//----------------------------------------------------------------------------- +// Purpose: Defines the largest allowed file size. Cloud files cannot be written +// in a single chunk over 100MB (and cannot be over 200MB total.) +//----------------------------------------------------------------------------- +const uint32 k_unMaxCloudFileChunkSize = 100 * 1024 * 1024; + + +//----------------------------------------------------------------------------- +// Purpose: Structure that contains an array of const char * strings and the number of those strings +//----------------------------------------------------------------------------- +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct SteamParamStringArray_t +{ + const char ** m_ppStrings; + int32 m_nNumStrings; +}; +#pragma pack( pop ) + +// A handle to a piece of user generated content +typedef uint64 UGCHandle_t; +typedef uint64 PublishedFileUpdateHandle_t; +typedef uint64 PublishedFileId_t; +const UGCHandle_t k_UGCHandleInvalid = 0xffffffffffffffffull; +const PublishedFileUpdateHandle_t k_PublishedFileUpdateHandleInvalid = 0xffffffffffffffffull; + +// Handle for writing to Steam Cloud +typedef uint64 UGCFileWriteStreamHandle_t; +const UGCFileWriteStreamHandle_t k_UGCFileStreamHandleInvalid = 0xffffffffffffffffull; + +const uint32 k_cchPublishedDocumentTitleMax = 128 + 1; +const uint32 k_cchPublishedDocumentDescriptionMax = 8000; +const uint32 k_cchPublishedDocumentChangeDescriptionMax = 8000; +const uint32 k_unEnumeratePublishedFilesMaxResults = 50; +const uint32 k_cchTagListMax = 1024 + 1; +const uint32 k_cchFilenameMax = 260; +const uint32 k_cchPublishedFileURLMax = 256; + +// Ways to handle a synchronization conflict +enum EResolveConflict +{ + k_EResolveConflictKeepClient = 1, // The local version of each file will be used to overwrite the server version + k_EResolveConflictKeepServer = 2, // The server version of each file will be used to overwrite the local version +}; + +enum ERemoteStoragePlatform +{ + k_ERemoteStoragePlatformNone = 0, + k_ERemoteStoragePlatformWindows = (1 << 0), + k_ERemoteStoragePlatformOSX = (1 << 1), + k_ERemoteStoragePlatformPS3 = (1 << 2), + k_ERemoteStoragePlatformLinux = (1 << 3), + k_ERemoteStoragePlatformReserved2 = (1 << 4), + + k_ERemoteStoragePlatformAll = 0xffffffff +}; + +enum ERemoteStoragePublishedFileVisibility +{ + k_ERemoteStoragePublishedFileVisibilityPublic = 0, + k_ERemoteStoragePublishedFileVisibilityFriendsOnly = 1, + k_ERemoteStoragePublishedFileVisibilityPrivate = 2, +}; + + +enum EWorkshopFileType +{ + k_EWorkshopFileTypeFirst = 0, + + k_EWorkshopFileTypeCommunity = 0, + k_EWorkshopFileTypeMicrotransaction = 1, + k_EWorkshopFileTypeCollection = 2, + k_EWorkshopFileTypeArt = 3, + k_EWorkshopFileTypeVideo = 4, + k_EWorkshopFileTypeScreenshot = 5, + k_EWorkshopFileTypeGame = 6, + k_EWorkshopFileTypeSoftware = 7, + k_EWorkshopFileTypeConcept = 8, + k_EWorkshopFileTypeWebGuide = 9, + k_EWorkshopFileTypeIntegratedGuide = 10, + k_EWorkshopFileTypeMerch = 11, + + // Update k_EWorkshopFileTypeMax if you add values + k_EWorkshopFileTypeMax = 12 + +}; + +enum EWorkshopVote +{ + k_EWorkshopVoteUnvoted = 0, + k_EWorkshopVoteFor = 1, + k_EWorkshopVoteAgainst = 2, +}; + +enum EWorkshopFileAction +{ + k_EWorkshopFileActionPlayed = 0, + k_EWorkshopFileActionCompleted = 1, +}; + +enum EWorkshopEnumerationType +{ + k_EWorkshopEnumerationTypeRankedByVote = 0, + k_EWorkshopEnumerationTypeRecent = 1, + k_EWorkshopEnumerationTypeTrending = 2, + k_EWorkshopEnumerationTypeFavoritesOfFriends = 3, + k_EWorkshopEnumerationTypeVotedByFriends = 4, + k_EWorkshopEnumerationTypeContentByFriends = 5, + k_EWorkshopEnumerationTypeRecentFromFollowedUsers = 6, +}; + +enum EWorkshopVideoProvider +{ + k_EWorkshopVideoProviderNone = 0, + k_EWorkshopVideoProviderYoutube = 1 +}; + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing, reading and writing files stored remotely +// and cached locally +//----------------------------------------------------------------------------- +class ISteamRemoteStorage +{ + public: + // NOTE + // + // Filenames are case-insensitive, and will be converted to lowercase automatically. + // So "foo.bar" and "Foo.bar" are the same file, and if you write "Foo.bar" then + // iterate the files, the filename returned will be "foo.bar". + // + + // file operations + virtual bool FileWrite( const char *pchFile, const void *pvData, int32 cubData ) = 0; + virtual int32 FileRead( const char *pchFile, void *pvData, int32 cubDataToRead ) = 0; + virtual bool FileForget( const char *pchFile ) = 0; + virtual bool FileDelete( const char *pchFile ) = 0; + virtual SteamAPICall_t FileShare( const char *pchFile ) = 0; + virtual bool SetSyncPlatforms( const char *pchFile, ERemoteStoragePlatform eRemoteStoragePlatform ) = 0; + + // file operations that cause network IO + virtual UGCFileWriteStreamHandle_t FileWriteStreamOpen( const char *pchFile ) = 0; + virtual bool FileWriteStreamWriteChunk( UGCFileWriteStreamHandle_t writeHandle, const void *pvData, int32 cubData ) = 0; + virtual bool FileWriteStreamClose( UGCFileWriteStreamHandle_t writeHandle ) = 0; + virtual bool FileWriteStreamCancel( UGCFileWriteStreamHandle_t writeHandle ) = 0; + + // file information + virtual bool FileExists( const char *pchFile ) = 0; + virtual bool FilePersisted( const char *pchFile ) = 0; + virtual int32 GetFileSize( const char *pchFile ) = 0; + virtual int64 GetFileTimestamp( const char *pchFile ) = 0; + virtual ERemoteStoragePlatform GetSyncPlatforms( const char *pchFile ) = 0; + + // iteration + virtual int32 GetFileCount() = 0; + virtual const char *GetFileNameAndSize( int iFile, int32 *pnFileSizeInBytes ) = 0; + + // configuration management + virtual bool GetQuota( int32 *pnTotalBytes, int32 *puAvailableBytes ) = 0; + virtual bool IsCloudEnabledForAccount() = 0; + virtual bool IsCloudEnabledForApp() = 0; + virtual void SetCloudEnabledForApp( bool bEnabled ) = 0; + + // user generated content + + // Downloads a UGC file. A priority value of 0 will download the file immediately, + // otherwise it will wait to download the file until all downloads with a lower priority + // value are completed. Downloads with equal priority will occur simultaneously. + virtual SteamAPICall_t UGCDownload( UGCHandle_t hContent, uint32 unPriority ) = 0; + + // Gets the amount of data downloaded so far for a piece of content. pnBytesExpected can be 0 if function returns false + // or if the transfer hasn't started yet, so be careful to check for that before dividing to get a percentage + virtual bool GetUGCDownloadProgress( UGCHandle_t hContent, int32 *pnBytesDownloaded, int32 *pnBytesExpected ) = 0; + + // Gets metadata for a file after it has been downloaded. This is the same metadata given in the RemoteStorageDownloadUGCResult_t call result + virtual bool GetUGCDetails( UGCHandle_t hContent, AppId_t *pnAppID, char **ppchName, int32 *pnFileSizeInBytes, CSteamID *pSteamIDOwner ) = 0; + + // After download, gets the content of the file. + // Small files can be read all at once by calling this function with an offset of 0 and cubDataToRead equal to the size of the file. + // Larger files can be read in chunks to reduce memory usage (since both sides of the IPC client and the game itself must allocate + // enough memory for each chunk). Once the last byte is read, the file is implicitly closed and further calls to UGCRead will fail + // unless UGCDownload is called again. + // For especially large files (anything over 100MB) it is a requirement that the file is read in chunks. + virtual int32 UGCRead( UGCHandle_t hContent, void *pvData, int32 cubDataToRead, uint32 cOffset ) = 0; + + // Functions to iterate through UGC that has finished downloading but has not yet been read via UGCRead() + virtual int32 GetCachedUGCCount() = 0; + virtual UGCHandle_t GetCachedUGCHandle( int32 iCachedContent ) = 0; + + // The following functions are only necessary on the Playstation 3. On PC & Mac, the Steam client will handle these operations for you + // On Playstation 3, the game controls which files are stored in the cloud, via FilePersist, FileFetch, and FileForget. + +#if defined(_PS3) || defined(_SERVER) + // Connect to Steam and get a list of files in the Cloud - results in a RemoteStorageAppSyncStatusCheck_t callback + virtual void GetFileListFromServer() = 0; + // Indicate this file should be downloaded in the next sync + virtual bool FileFetch( const char *pchFile ) = 0; + // Indicate this file should be persisted in the next sync + virtual bool FilePersist( const char *pchFile ) = 0; + // Pull any requested files down from the Cloud - results in a RemoteStorageAppSyncedClient_t callback + virtual bool SynchronizeToClient() = 0; + // Upload any requested files to the Cloud - results in a RemoteStorageAppSyncedServer_t callback + virtual bool SynchronizeToServer() = 0; + // Reset any fetch/persist/etc requests + virtual bool ResetFileRequestState() = 0; +#endif + + // publishing UGC + virtual SteamAPICall_t PublishWorkshopFile( const char *pchFile, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags, EWorkshopFileType eWorkshopFileType ) = 0; + virtual PublishedFileUpdateHandle_t CreatePublishedFileUpdateRequest( PublishedFileId_t unPublishedFileId ) = 0; + virtual bool UpdatePublishedFileFile( PublishedFileUpdateHandle_t updateHandle, const char *pchFile ) = 0; + virtual bool UpdatePublishedFilePreviewFile( PublishedFileUpdateHandle_t updateHandle, const char *pchPreviewFile ) = 0; + virtual bool UpdatePublishedFileTitle( PublishedFileUpdateHandle_t updateHandle, const char *pchTitle ) = 0; + virtual bool UpdatePublishedFileDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchDescription ) = 0; + virtual bool UpdatePublishedFileVisibility( PublishedFileUpdateHandle_t updateHandle, ERemoteStoragePublishedFileVisibility eVisibility ) = 0; + virtual bool UpdatePublishedFileTags( PublishedFileUpdateHandle_t updateHandle, SteamParamStringArray_t *pTags ) = 0; + virtual SteamAPICall_t CommitPublishedFileUpdate( PublishedFileUpdateHandle_t updateHandle ) = 0; + // Gets published file details for the given publishedfileid. If unMaxSecondsOld is greater than 0, + // cached data may be returned, depending on how long ago it was cached. A value of 0 will force a refresh, + // a value of -1 will use cached data if it exists, no matter how old it is. + virtual SteamAPICall_t GetPublishedFileDetails( PublishedFileId_t unPublishedFileId, uint32 unMaxSecondsOld ) = 0; + virtual SteamAPICall_t DeletePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + // enumerate the files that the current user published with this app + virtual SteamAPICall_t EnumerateUserPublishedFiles( uint32 unStartIndex ) = 0; + virtual SteamAPICall_t SubscribePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + virtual SteamAPICall_t EnumerateUserSubscribedFiles( uint32 unStartIndex ) = 0; + virtual SteamAPICall_t UnsubscribePublishedFile( PublishedFileId_t unPublishedFileId ) = 0; + virtual bool UpdatePublishedFileSetChangeDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchChangeDescription ) = 0; + virtual SteamAPICall_t GetPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) = 0; + virtual SteamAPICall_t UpdateUserPublishedItemVote( PublishedFileId_t unPublishedFileId, bool bVoteUp ) = 0; + virtual SteamAPICall_t GetUserPublishedItemVoteDetails( PublishedFileId_t unPublishedFileId ) = 0; + virtual SteamAPICall_t EnumerateUserSharedWorkshopFiles( CSteamID steamId, uint32 unStartIndex, SteamParamStringArray_t *pRequiredTags, SteamParamStringArray_t *pExcludedTags ) = 0; + virtual SteamAPICall_t PublishVideo( EWorkshopVideoProvider eVideoProvider, const char *pchVideoAccount, const char *pchVideoIdentifier, const char *pchPreviewFile, AppId_t nConsumerAppId, const char *pchTitle, const char *pchDescription, ERemoteStoragePublishedFileVisibility eVisibility, SteamParamStringArray_t *pTags ) = 0; + virtual SteamAPICall_t SetUserPublishedFileAction( PublishedFileId_t unPublishedFileId, EWorkshopFileAction eAction ) = 0; + virtual SteamAPICall_t EnumeratePublishedFilesByUserAction( EWorkshopFileAction eAction, uint32 unStartIndex ) = 0; + // this method enumerates the public view of workshop files + virtual SteamAPICall_t EnumeratePublishedWorkshopFiles( EWorkshopEnumerationType eEnumerationType, uint32 unStartIndex, uint32 unCount, uint32 unDays, SteamParamStringArray_t *pTags, SteamParamStringArray_t *pUserTags ) = 0; + + virtual SteamAPICall_t UGCDownloadToLocation( UGCHandle_t hContent, const char *pchLocation, uint32 unPriority ) = 0; +}; + +#define STEAMREMOTESTORAGE_INTERFACE_VERSION "STEAMREMOTESTORAGE_INTERFACE_VERSION011" + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: sent when the local file cache is fully synced with the server for an app +// That means that an application can be started and has all latest files +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncedClient_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 1 }; + AppId_t m_nAppID; + EResult m_eResult; + int m_unNumDownloads; +}; + +//----------------------------------------------------------------------------- +// Purpose: sent when the server is fully synced with the local file cache for an app +// That means that we can shutdown Steam and our data is stored on the server +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncedServer_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 2 }; + AppId_t m_nAppID; + EResult m_eResult; + int m_unNumUploads; +}; + +//----------------------------------------------------------------------------- +// Purpose: Status of up and downloads during a sync session +// +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncProgress_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 3 }; + char m_rgchCurrentFile[k_cchFilenameMax]; // Current file being transferred + AppId_t m_nAppID; // App this info relates to + uint32 m_uBytesTransferredThisChunk; // Bytes transferred this chunk + double m_dAppPercentComplete; // Percent complete that this app's transfers are + bool m_bUploading; // if false, downloading +}; + +// +// IMPORTANT! k_iClientRemoteStorageCallbacks + 4 is used, see iclientremotestorage.h +// + + +//----------------------------------------------------------------------------- +// Purpose: Sent after we've determined the list of files that are out of sync +// with the server. +//----------------------------------------------------------------------------- +struct RemoteStorageAppSyncStatusCheck_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 5 }; + AppId_t m_nAppID; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: Sent after a conflict resolution attempt. +//----------------------------------------------------------------------------- +struct RemoteStorageConflictResolution_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 6 }; + AppId_t m_nAppID; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to FileShare() +//----------------------------------------------------------------------------- +struct RemoteStorageFileShareResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 7 }; + EResult m_eResult; // The result of the operation + UGCHandle_t m_hFile; // The handle that can be shared with users and features +}; + + +// k_iClientRemoteStorageCallbacks + 8 is deprecated! Do not reuse + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to PublishFile() +//----------------------------------------------------------------------------- +struct RemoteStoragePublishFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 9 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to DeletePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageDeletePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 11 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to EnumerateUserPublishedFiles() +//----------------------------------------------------------------------------- +struct RemoteStorageEnumerateUserPublishedFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 12 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to SubscribePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageSubscribePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 13 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to EnumerateSubscribePublishedFiles() +//----------------------------------------------------------------------------- +struct RemoteStorageEnumerateUserSubscribedFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 14 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + uint32 m_rgRTimeSubscribed[ k_unEnumeratePublishedFilesMaxResults ]; +}; + +#if defined(VALVE_CALLBACK_PACK_SMALL) + VALVE_COMPILE_TIME_ASSERT( sizeof( RemoteStorageEnumerateUserSubscribedFilesResult_t ) == (1 + 1 + 1 + 50 + 100) * 4 ); +#elif defined(VALVE_CALLBACK_PACK_LARGE) + VALVE_COMPILE_TIME_ASSERT( sizeof( RemoteStorageEnumerateUserSubscribedFilesResult_t ) == (1 + 1 + 1 + 50 + 100) * 4 + 4 ); +#else +#warning You must first include isteamclient.h +#endif + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UnsubscribePublishedFile() +//----------------------------------------------------------------------------- +struct RemoteStorageUnsubscribePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 15 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to CommitPublishedFileUpdate() +//----------------------------------------------------------------------------- +struct RemoteStorageUpdatePublishedFileResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 16 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + bool m_bUserNeedsToAcceptWorkshopLegalAgreement; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UGCDownload() +//----------------------------------------------------------------------------- +struct RemoteStorageDownloadUGCResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 17 }; + EResult m_eResult; // The result of the operation. + UGCHandle_t m_hFile; // The handle to the file that was attempted to be downloaded. + AppId_t m_nAppID; // ID of the app that created this file. + int32 m_nSizeInBytes; // The size of the file that was downloaded, in bytes. + char m_pchFileName[k_cchFilenameMax]; // The name of the file that was downloaded. + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetPublishedFileDetails() +//----------------------------------------------------------------------------- +struct RemoteStorageGetPublishedFileDetailsResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 18 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; + AppId_t m_nCreatorAppID; // ID of the app that created this file. + AppId_t m_nConsumerAppID; // ID of the app that will consume this file. + char m_rgchTitle[k_cchPublishedDocumentTitleMax]; // title of document + char m_rgchDescription[k_cchPublishedDocumentDescriptionMax]; // description of document + UGCHandle_t m_hFile; // The handle of the primary file + UGCHandle_t m_hPreviewFile; // The handle of the preview file + uint64 m_ulSteamIDOwner; // Steam ID of the user who created this content. + uint32 m_rtimeCreated; // time when the published file was created + uint32 m_rtimeUpdated; // time when the published file was last updated + ERemoteStoragePublishedFileVisibility m_eVisibility; + bool m_bBanned; + char m_rgchTags[k_cchTagListMax]; // comma separated list of all tags associated with this file + bool m_bTagsTruncated; // whether the list of tags was too long to be returned in the provided buffer + char m_pchFileName[k_cchFilenameMax]; // The name of the primary file + int32 m_nFileSize; // Size of the primary file + int32 m_nPreviewFileSize; // Size of the preview file + char m_rgchURL[k_cchPublishedFileURLMax]; // URL (for a video or a website) + EWorkshopFileType m_eFileType; // Type of the file +}; + + +struct RemoteStorageEnumerateWorkshopFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 19 }; + EResult m_eResult; + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + float m_rgScore[ k_unEnumeratePublishedFilesMaxResults ]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of GetPublishedItemVoteDetails +//----------------------------------------------------------------------------- +struct RemoteStorageGetPublishedItemVoteDetailsResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 20 }; + EResult m_eResult; + PublishedFileId_t m_unPublishedFileId; + int32 m_nVotesFor; + int32 m_nVotesAgainst; + int32 m_nReports; + float m_fScore; +}; + + +//----------------------------------------------------------------------------- +// Purpose: User subscribed to a file for the app (from within the app or on the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileSubscribed_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 21 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + +//----------------------------------------------------------------------------- +// Purpose: User unsubscribed from a file for the app (from within the app or on the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileUnsubscribed_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 22 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + + +//----------------------------------------------------------------------------- +// Purpose: Published file that a user owns was deleted (from within the app or the web) +//----------------------------------------------------------------------------- +struct RemoteStoragePublishedFileDeleted_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 23 }; + PublishedFileId_t m_nPublishedFileId; // The published file id + AppId_t m_nAppID; // ID of the app that will consume this file. +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to UpdateUserPublishedItemVote() +//----------------------------------------------------------------------------- +struct RemoteStorageUpdateUserPublishedItemVoteResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 24 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id +}; + + +//----------------------------------------------------------------------------- +// Purpose: The result of a call to GetUserPublishedItemVoteDetails() +//----------------------------------------------------------------------------- +struct RemoteStorageUserVoteDetails_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 25 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id + EWorkshopVote m_eVote; // what the user voted +}; + +struct RemoteStorageEnumerateUserSharedWorkshopFilesResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 26 }; + EResult m_eResult; // The result of the operation. + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; +}; + +struct RemoteStorageSetUserPublishedFileActionResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 27 }; + EResult m_eResult; // The result of the operation. + PublishedFileId_t m_nPublishedFileId; // The published file id + EWorkshopFileAction m_eAction; // the action that was attempted +}; + +struct RemoteStorageEnumeratePublishedFilesByUserActionResult_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 28 }; + EResult m_eResult; // The result of the operation. + EWorkshopFileAction m_eAction; // the action that was filtered on + int32 m_nResultsReturned; + int32 m_nTotalResultCount; + PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ]; + uint32 m_rgRTimeUpdated[ k_unEnumeratePublishedFilesMaxResults ]; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Called periodically while a PublishWorkshopFile is in progress +//----------------------------------------------------------------------------- +struct RemoteStoragePublishFileProgress_t +{ + enum { k_iCallback = k_iClientRemoteStorageCallbacks + 29 }; + double m_dPercentFile; + bool m_bPreview; +}; + + + +#pragma pack( pop ) + + +#endif // ISTEAMREMOTESTORAGE_H diff --git a/rehlds/public/steam/isteamscreenshots.h b/rehlds/public/steam/isteamscreenshots.h new file mode 100644 index 0000000..f77acc2 --- /dev/null +++ b/rehlds/public/steam/isteamscreenshots.h @@ -0,0 +1,96 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: public interface to user remote file storage in Steam +// +//============================================================================= + +#ifndef ISTEAMSCREENSHOTS_H +#define ISTEAMSCREENSHOTS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +const uint32 k_nScreenshotMaxTaggedUsers = 32; +const uint32 k_nScreenshotMaxTaggedPublishedFiles = 32; +const int k_cubUFSTagTypeMax = 255; +const int k_cubUFSTagValueMax = 255; + +// Required with of a thumbnail provided to AddScreenshotToLibrary. If you do not provide a thumbnail +// one will be generated. +const int k_ScreenshotThumbWidth = 200; + +// Handle is valid for the lifetime of your process and no longer +typedef uint32 ScreenshotHandle; +#define INVALID_SCREENSHOT_HANDLE 0 + +//----------------------------------------------------------------------------- +// Purpose: Functions for adding screenshots to the user's screenshot library +//----------------------------------------------------------------------------- +class ISteamScreenshots +{ +public: + // Writes a screenshot to the user's screenshot library given the raw image data, which must be in RGB format. + // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. + virtual ScreenshotHandle WriteScreenshot( void *pubRGB, uint32 cubRGB, int nWidth, int nHeight ) = 0; + + // Adds a screenshot to the user's screenshot library from disk. If a thumbnail is provided, it must be 200 pixels wide and the same aspect ratio + // as the screenshot, otherwise a thumbnail will be generated if the user uploads the screenshot. The screenshots must be in either JPEG or TGA format. + // The return value is a handle that is valid for the duration of the game process and can be used to apply tags. + // JPEG, TGA, and PNG formats are supported. + virtual ScreenshotHandle AddScreenshotToLibrary( const char *pchFilename, const char *pchThumbnailFilename, int nWidth, int nHeight ) = 0; + + // Causes the Steam overlay to take a screenshot. If screenshots are being hooked by the game then a ScreenshotRequested_t callback is sent back to the game instead. + virtual void TriggerScreenshot() = 0; + + // Toggles whether the overlay handles screenshots when the user presses the screenshot hotkey, or the game handles them. If the game is hooking screenshots, + // then the ScreenshotRequested_t callback will be sent if the user presses the hotkey, and the game is expected to call WriteScreenshot or AddScreenshotToLibrary + // in response. + virtual void HookScreenshots( bool bHook ) = 0; + + // Sets metadata about a screenshot's location (for example, the name of the map) + virtual bool SetLocation( ScreenshotHandle hScreenshot, const char *pchLocation ) = 0; + + // Tags a user as being visible in the screenshot + virtual bool TagUser( ScreenshotHandle hScreenshot, CSteamID steamID ) = 0; + + // Tags a published file as being visible in the screenshot + virtual bool TagPublishedFile( ScreenshotHandle hScreenshot, PublishedFileId_t unPublishedFileID ) = 0; +}; + +#define STEAMSCREENSHOTS_INTERFACE_VERSION "STEAMSCREENSHOTS_INTERFACE_VERSION002" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +//----------------------------------------------------------------------------- +// Purpose: Screenshot successfully written or otherwise added to the library +// and can now be tagged +//----------------------------------------------------------------------------- +struct ScreenshotReady_t +{ + enum { k_iCallback = k_iSteamScreenshotsCallbacks + 1 }; + ScreenshotHandle m_hLocal; + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// Purpose: Screenshot has been requested by the user. Only sent if +// HookScreenshots() has been called, in which case Steam will not take +// the screenshot itself. +//----------------------------------------------------------------------------- +struct ScreenshotRequested_t +{ + enum { k_iCallback = k_iSteamScreenshotsCallbacks + 2 }; +}; + +#pragma pack( pop ) + + +#endif // ISTEAMSCREENSHOTS_H diff --git a/rehlds/public/steam/isteamunifiedmessages.h b/rehlds/public/steam/isteamunifiedmessages.h new file mode 100644 index 0000000..8e87dc9 --- /dev/null +++ b/rehlds/public/steam/isteamunifiedmessages.h @@ -0,0 +1,63 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Interface to unified messages client +// +// You should not need to use this interface except if your product is using a language other than C++. +// Contact your Steam Tech contact for more details. +// +//============================================================================= + +#ifndef ISTEAMUNIFIEDMESSAGES_H +#define ISTEAMUNIFIEDMESSAGES_H +#ifdef _WIN32 +#pragma once +#endif + +typedef uint64 ClientUnifiedMessageHandle; + +class ISteamUnifiedMessages +{ +public: + static const ClientUnifiedMessageHandle k_InvalidUnifiedMessageHandle = 0; + + // Sends a service method (in binary serialized form) using the Steam Client. + // Returns a unified message handle (k_InvalidUnifiedMessageHandle if could not send the message). + virtual ClientUnifiedMessageHandle SendMethod( const char *pchServiceMethod, const void *pRequestBuffer, uint32 unRequestBufferSize, uint64 unContext ) = 0; + + // Gets the size of the response and the EResult. Returns false if the response is not ready yet. + virtual bool GetMethodResponseInfo( ClientUnifiedMessageHandle hHandle, uint32 *punResponseSize, EResult *peResult ) = 0; + + // Gets a response in binary serialized form (and optionally release the corresponding allocated memory). + virtual bool GetMethodResponseData( ClientUnifiedMessageHandle hHandle, void *pResponseBuffer, uint32 unResponseBufferSize, bool bAutoRelease ) = 0; + + // Releases the message and its corresponding allocated memory. + virtual bool ReleaseMethod( ClientUnifiedMessageHandle hHandle ) = 0; + + // Sends a service notification (in binary serialized form) using the Steam Client. + // Returns true if the notification was sent successfully. + virtual bool SendNotification( const char *pchServiceNotification, const void *pNotificationBuffer, uint32 unNotificationBufferSize ) = 0; +}; + +#define STEAMUNIFIEDMESSAGES_INTERFACE_VERSION "STEAMUNIFIEDMESSAGES_INTERFACE_VERSION001" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +struct SteamUnifiedMessagesSendMethodResult_t +{ + enum { k_iCallback = k_iClientUnifiedMessagesCallbacks + 1 }; + ClientUnifiedMessageHandle m_hHandle; // The handle returned by SendMethod(). + uint64 m_unContext; // Context provided when calling SendMethod(). + EResult m_eResult; // The result of the method call. + uint32 m_unResponseSize; // The size of the response. +}; + +#pragma pack( pop ) + +#endif // ISTEAMUNIFIEDMESSAGES_H diff --git a/rehlds/public/steam/isteamuser.h b/rehlds/public/steam/isteamuser.h new file mode 100644 index 0000000..7e04616 --- /dev/null +++ b/rehlds/public/steam/isteamuser.h @@ -0,0 +1,339 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to user account information in Steam +// +//============================================================================= + +#ifndef ISTEAMUSER_H +#define ISTEAMUSER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + +// structure that contains client callback data +// see callbacks documentation for more details +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif +struct CallbackMsg_t +{ + HSteamUser m_hSteamUser; + int m_iCallback; + uint8 *m_pubParam; + int m_cubParam; +}; +#pragma pack( pop ) + +// reference to a steam call, to filter results by +typedef int32 HSteamCall; + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing and manipulating a steam account +// associated with one client instance +//----------------------------------------------------------------------------- +class ISteamUser +{ +public: + // returns the HSteamUser this interface represents + // this is only used internally by the API, and by a few select interfaces that support multi-user + virtual HSteamUser GetHSteamUser() = 0; + + // returns true if the Steam client current has a live connection to the Steam servers. + // If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy. + // The Steam client will automatically be trying to recreate the connection as often as possible. + virtual bool BLoggedOn() = 0; + + // returns the CSteamID of the account currently logged into the Steam client + // a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API + virtual CSteamID GetSteamID() = 0; + + // Multiplayer Authentication functions + + // InitiateGameConnection() starts the state machine for authenticating the game client with the game server + // It is the client portion of a three-way handshake between the client, the game server, and the steam servers + // + // Parameters: + // void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token. + // int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes. + // CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client + // CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( ) + // uint32 unIPServer, uint16 usPortServer - the IP address of the game server + // bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running) + // + // return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed + // The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process. + virtual int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure ) = 0; + + // notify of disconnect + // needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call + virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0; + + // Legacy functions + + // used by only a few games to track usage events + virtual void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo = "" ) = 0; + + // get the local storage folder for current Steam account to write application data, e.g. save games, configs etc. + // this will usually be something like "C:\Progam Files\Steam\userdata\\\local" + virtual bool GetUserDataFolder( char *pchBuffer, int cubBuffer ) = 0; + + // Starts voice recording. Once started, use GetVoice() to get the data + virtual void StartVoiceRecording( ) = 0; + + // Stops voice recording. Because people often release push-to-talk keys early, the system will keep recording for + // a little bit after this function is called. GetVoice() should continue to be called until it returns + // k_eVoiceResultNotRecording + virtual void StopVoiceRecording( ) = 0; + + // Determine the amount of captured audio data that is available in bytes. + // This provides both the compressed and uncompressed data. Please note that the uncompressed + // data is not the raw feed from the microphone: data may only be available if audible + // levels of speech are detected. + // nUncompressedVoiceDesiredSampleRate is necessary to know the number of bytes to return in pcbUncompressed - can be set to 0 if you don't need uncompressed (the usual case) + // If you're upgrading from an older Steamworks API, you'll want to pass in 11025 to nUncompressedVoiceDesiredSampleRate + virtual EVoiceResult GetAvailableVoice(uint32 *pcbCompressed, uint32 *pcbUncompressed, uint32 nUncompressedVoiceDesiredSampleRate) = 0; + + // Gets the latest voice data from the microphone. Compressed data is an arbitrary format, and is meant to be handed back to + // DecompressVoice() for playback later as a binary blob. Uncompressed data is 16-bit, signed integer, 11025Hz PCM format. + // Please note that the uncompressed data is not the raw feed from the microphone: data may only be available if audible + // levels of speech are detected, and may have passed through denoising filters, etc. + // This function should be called as often as possible once recording has started; once per frame at least. + // nBytesWritten is set to the number of bytes written to pDestBuffer. + // nUncompressedBytesWritten is set to the number of bytes written to pUncompressedDestBuffer. + // You must grab both compressed and uncompressed here at the same time, if you want both. + // Matching data that is not read during this call will be thrown away. + // GetAvailableVoice() can be used to determine how much data is actually available. + // If you're upgrading from an older Steamworks API, you'll want to pass in 11025 to nUncompressedVoiceDesiredSampleRate + virtual EVoiceResult GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed, void *pUncompressedDestBuffer, uint32 cbUncompressedDestBufferSize, uint32 *nUncompressBytesWritten, uint32 nUncompressedVoiceDesiredSampleRate ) = 0; + + // Decompresses a chunk of compressed data produced by GetVoice(). + // nBytesWritten is set to the number of bytes written to pDestBuffer unless the return value is k_EVoiceResultBufferTooSmall. + // In that case, nBytesWritten is set to the size of the buffer required to decompress the given + // data. The suggested buffer size for the destination buffer is 22 kilobytes. + // The output format of the data is 16-bit signed at the requested samples per second. + // If you're upgrading from an older Steamworks API, you'll want to pass in 11025 to nDesiredSampleRate + virtual EVoiceResult DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, uint32 nDesiredSampleRate ) = 0; + + // This returns the frequency of the voice data as it's stored internally; calling DecompressVoice() with this size will yield the best results + virtual uint32 GetVoiceOptimalSampleRate() = 0; + + // Retrieve ticket to be sent to the entity who wishes to authenticate you. + // pcbTicket retrieves the length of the actual ticket. + virtual HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + + // Authenticate ticket from entity steamID to be sure it is valid and isnt reused + // Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse ) + virtual EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID ) = 0; + + // Stop tracking started by BeginAuthSession - called when no longer playing game with this entity + virtual void EndAuthSession( CSteamID steamID ) = 0; + + // Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to + virtual void CancelAuthTicket( HAuthTicket hAuthTicket ) = 0; + + // After receiving a user's authentication data, and passing it to BeginAuthSession, use this function + // to determine if the user owns downloadable content specified by the provided AppID. + virtual EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID ) = 0; + + // returns true if this users looks like they are behind a NAT device. Only valid once the user has connected to steam + // (i.e a SteamServersConnected_t has been issued) and may not catch all forms of NAT. + virtual bool BIsBehindNAT() = 0; + + // set data to be replicated to friends so that they can join your game + // CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client + // uint32 unIPServer, uint16 usPortServer - the IP address of the game server + virtual void AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer ) = 0; + + // Requests a ticket encrypted with an app specific shared key + // pDataToInclude, cbDataToInclude will be encrypted into the ticket + // ( This is asynchronous, you must wait for the ticket to be completed by the server ) + virtual SteamAPICall_t RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude ) = 0; + + // retrieve a finished ticket + virtual bool GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket ) = 0; + +#ifdef _PS3 + // Initiates PS3 Logon request using just PSN ticket. + // + // PARAMS: bInteractive - If set tells Steam to go ahead and show the PS3 NetStart dialog if needed to + // prompt the user for network setup/PSN logon before initiating the Steam side of the logon. + // + // Listen for SteamServersConnected_t or SteamServerConnectFailure_t for status. SteamServerConnectFailure_t + // may return with EResult k_EResultExternalAccountUnlinked if the PSN account is unknown to Steam. You should + // then call LogOnAndLinkSteamAccountToPSN() after prompting the user for credentials to establish a link. + // Future calls to LogOn() after the one time link call should succeed as long as the user is connected to PSN. + virtual void LogOn( bool bInteractive ) = 0; + + // Initiates a request to logon with a specific steam username/password and create a PSN account link at + // the same time. Should call this only if LogOn() has failed and indicated the PSN account is unlinked. + // + // PARAMS: bInteractive - If set tells Steam to go ahead and show the PS3 NetStart dialog if needed to + // prompt the user for network setup/PSN logon before initiating the Steam side of the logon. pchUserName + // should be the users Steam username, and pchPassword should be the users Steam password. + // + // Listen for SteamServersConnected_t or SteamServerConnectFailure_t for status. SteamServerConnectFailure_t + // may return with EResult k_EResultOtherAccountAlreadyLinked if already linked to another account. + virtual void LogOnAndLinkSteamAccountToPSN( bool bInteractive, const char *pchUserName, const char *pchPassword ) = 0; + + // Final logon option for PS3, this logs into an existing account if already linked, but if not already linked + // creates a new account using the info in the PSN ticket to generate a unique account name. The new account is + // then linked to the PSN ticket. This is the faster option for new users who don't have an existing Steam account + // to get into multiplayer. + // + // PARAMS: bInteractive - If set tells Steam to go ahead and show the PS3 NetStart dialog if needed to + // prompt the user for network setup/PSN logon before initiating the Steam side of the logon. + virtual void LogOnAndCreateNewSteamAccountIfNeeded( bool bInteractive ) = 0; + + // Returns a special SteamID that represents the user's PSN information. Can be used to query the user's PSN avatar, + // online name, etc. through the standard Steamworks interfaces. + virtual CSteamID GetConsoleSteamID() = 0; +#endif + +}; + +#define STEAMUSER_INTERFACE_VERSION "SteamUser016" + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when a connections to the Steam back-end has been established +// this means the Steam client now has a working connection to the Steam servers +// usually this will have occurred before the game has launched, and should +// only be seen if the user has dropped connection due to a networking issue +// or a Steam server update +//----------------------------------------------------------------------------- +struct SteamServersConnected_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 1 }; +}; + +//----------------------------------------------------------------------------- +// Purpose: called when a connection attempt has failed +// this will occur periodically if the Steam client is not connected, +// and has failed in it's retry to establish a connection +//----------------------------------------------------------------------------- +struct SteamServerConnectFailure_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 2 }; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called if the client has lost connection to the Steam servers +// real-time services will be disabled until a matching SteamServersConnected_t has been posted +//----------------------------------------------------------------------------- +struct SteamServersDisconnected_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 3 }; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Sent by the Steam server to the client telling it to disconnect from the specified game server, +// which it may be in the process of or already connected to. +// The game client should immediately disconnect upon receiving this message. +// This can usually occur if the user doesn't have rights to play on the game server. +//----------------------------------------------------------------------------- +struct ClientGameServerDeny_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 13 }; + + uint32 m_uAppID; + uint32 m_unGameServerIP; + uint16 m_usGameServerPort; + uint16 m_bSecure; + uint32 m_uReason; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when the callback system for this client is in an error state (and has flushed pending callbacks) +// When getting this message the client should disconnect from Steam, reset any stored Steam state and reconnect. +// This usually occurs in the rare event the Steam client has some kind of fatal error. +//----------------------------------------------------------------------------- +struct IPCFailure_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 17 }; + enum EFailureType + { + k_EFailureFlushedCallbackQueue, + k_EFailurePipeFail, + }; + uint8 m_eFailureType; +}; + + +//----------------------------------------------------------------------------- +// callback for BeginAuthSession +//----------------------------------------------------------------------------- +struct ValidateAuthTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 43 }; + CSteamID m_SteamID; + EAuthSessionResponse m_eAuthSessionResponse; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when a user has responded to a microtransaction authorization request +//----------------------------------------------------------------------------- +struct MicroTxnAuthorizationResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 52 }; + + uint32 m_unAppID; // AppID for this microtransaction + uint64 m_ulOrderID; // OrderID provided for the microtransaction + uint8 m_bAuthorized; // if user authorized transaction +}; + + +//----------------------------------------------------------------------------- +// Purpose: Result from RequestEncryptedAppTicket +//----------------------------------------------------------------------------- +struct EncryptedAppTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 54 }; + + EResult m_eResult; +}; + +//----------------------------------------------------------------------------- +// callback for GetAuthSessionTicket +//----------------------------------------------------------------------------- +struct GetAuthSessionTicketResponse_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 63 }; + HAuthTicket m_hAuthTicket; + EResult m_eResult; +}; + + +//----------------------------------------------------------------------------- +// Purpose: sent to your game in response to a steam://gamewebcallback/ command +//----------------------------------------------------------------------------- +struct GameWebCallback_t +{ + enum { k_iCallback = k_iSteamUserCallbacks + 64 }; + char m_szURL[256]; +}; + + +#pragma pack( pop ) + +#endif // ISTEAMUSER_H diff --git a/rehlds/public/steam/isteamuserstats.h b/rehlds/public/steam/isteamuserstats.h new file mode 100644 index 0000000..897c086 --- /dev/null +++ b/rehlds/public/steam/isteamuserstats.h @@ -0,0 +1,463 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to stats, achievements, and leaderboards +// +//============================================================================= + +#ifndef ISTEAMUSERSTATS_H +#define ISTEAMUSERSTATS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "isteamremotestorage.h" + +// size limit on stat or achievement name (UTF-8 encoded) +enum { k_cchStatNameMax = 128 }; + +// maximum number of bytes for a leaderboard name (UTF-8 encoded) +enum { k_cchLeaderboardNameMax = 128 }; + +// maximum number of details int32's storable for a single leaderboard entry +enum { k_cLeaderboardDetailsMax = 64 }; + +// handle to a single leaderboard +typedef uint64 SteamLeaderboard_t; + +// handle to a set of downloaded entries in a leaderboard +typedef uint64 SteamLeaderboardEntries_t; + +// type of data request, when downloading leaderboard entries +enum ELeaderboardDataRequest +{ + k_ELeaderboardDataRequestGlobal = 0, + k_ELeaderboardDataRequestGlobalAroundUser = 1, + k_ELeaderboardDataRequestFriends = 2, + k_ELeaderboardDataRequestUsers = 3 +}; + +// the sort order of a leaderboard +enum ELeaderboardSortMethod +{ + k_ELeaderboardSortMethodNone = 0, + k_ELeaderboardSortMethodAscending = 1, // top-score is lowest number + k_ELeaderboardSortMethodDescending = 2, // top-score is highest number +}; + +// the display type (used by the Steam Community web site) for a leaderboard +enum ELeaderboardDisplayType +{ + k_ELeaderboardDisplayTypeNone = 0, + k_ELeaderboardDisplayTypeNumeric = 1, // simple numerical score + k_ELeaderboardDisplayTypeTimeSeconds = 2, // the score represents a time, in seconds + k_ELeaderboardDisplayTypeTimeMilliSeconds = 3, // the score represents a time, in milliseconds +}; + +enum ELeaderboardUploadScoreMethod +{ + k_ELeaderboardUploadScoreMethodNone = 0, + k_ELeaderboardUploadScoreMethodKeepBest = 1, // Leaderboard will keep user's best score + k_ELeaderboardUploadScoreMethodForceUpdate = 2, // Leaderboard will always replace score with specified +}; + +// a single entry in a leaderboard, as returned by GetDownloadedLeaderboardEntry() +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +struct LeaderboardEntry_t +{ + CSteamID m_steamIDUser; // user with the entry - use SteamFriends()->GetFriendPersonaName() & SteamFriends()->GetFriendAvatar() to get more info + int32 m_nGlobalRank; // [1..N], where N is the number of users with an entry in the leaderboard + int32 m_nScore; // score as set in the leaderboard + int32 m_cDetails; // number of int32 details available for this entry + UGCHandle_t m_hUGC; // handle for UGC attached to the entry +}; + +#pragma pack( pop ) + + +//----------------------------------------------------------------------------- +// Purpose: Functions for accessing stats, achievements, and leaderboard information +//----------------------------------------------------------------------------- +class ISteamUserStats +{ +public: + // Ask the server to send down this user's data and achievements for this game + virtual bool RequestCurrentStats() = 0; + + // Data accessors + virtual bool GetStat( const char *pchName, int32 *pData ) = 0; + virtual bool GetStat( const char *pchName, float *pData ) = 0; + + // Set / update data + virtual bool SetStat( const char *pchName, int32 nData ) = 0; + virtual bool SetStat( const char *pchName, float fData ) = 0; + virtual bool UpdateAvgRateStat( const char *pchName, float flCountThisSession, double dSessionLength ) = 0; + + // Achievement flag accessors + virtual bool GetAchievement( const char *pchName, bool *pbAchieved ) = 0; + virtual bool SetAchievement( const char *pchName ) = 0; + virtual bool ClearAchievement( const char *pchName ) = 0; + + // Get the achievement status, and the time it was unlocked if unlocked. + // If the return value is true, but the unlock time is zero, that means it was unlocked before Steam + // began tracking achievement unlock times (December 2009). Time is seconds since January 1, 1970. + virtual bool GetAchievementAndUnlockTime( const char *pchName, bool *pbAchieved, uint32 *punUnlockTime ) = 0; + + // Store the current data on the server, will get a callback when set + // And one callback for every new achievement + // + // If the callback has a result of k_EResultInvalidParam, one or more stats + // uploaded has been rejected, either because they broke constraints + // or were out of date. In this case the server sends back updated values. + // The stats should be re-iterated to keep in sync. + virtual bool StoreStats() = 0; + + // Achievement / GroupAchievement metadata + + // Gets the icon of the achievement, which is a handle to be used in ISteamUtils::GetImageRGBA(), or 0 if none set. + // A return value of 0 may indicate we are still fetching data, and you can wait for the UserAchievementIconFetched_t callback + // which will notify you when the bits are ready. If the callback still returns zero, then there is no image set for the + // specified achievement. + virtual int GetAchievementIcon( const char *pchName ) = 0; + + // Get general attributes for an achievement. Accepts the following keys: + // - "name" and "desc" for retrieving the localized achievement name and description (returned in UTF8) + // - "hidden" for retrieving if an achievement is hidden (returns "0" when not hidden, "1" when hidden) + virtual const char *GetAchievementDisplayAttribute( const char *pchName, const char *pchKey ) = 0; + + // Achievement progress - triggers an AchievementProgress callback, that is all. + // Calling this w/ N out of N progress will NOT set the achievement, the game must still do that. + virtual bool IndicateAchievementProgress( const char *pchName, uint32 nCurProgress, uint32 nMaxProgress ) = 0; + + // Used for iterating achievements. In general games should not need these functions because they should have a + // list of existing achievements compiled into them + virtual uint32 GetNumAchievements() = 0; + // Get achievement name iAchievement in [0,GetNumAchievements) + virtual const char *GetAchievementName( uint32 iAchievement ) = 0; + + // Friends stats & achievements + + // downloads stats for the user + // returns a UserStatsReceived_t received when completed + // if the other user has no stats, UserStatsReceived_t.m_eResult will be set to k_EResultFail + // these stats won't be auto-updated; you'll need to call RequestUserStats() again to refresh any data + virtual SteamAPICall_t RequestUserStats( CSteamID steamIDUser ) = 0; + + // requests stat information for a user, usable after a successful call to RequestUserStats() + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, int32 *pData ) = 0; + virtual bool GetUserStat( CSteamID steamIDUser, const char *pchName, float *pData ) = 0; + virtual bool GetUserAchievement( CSteamID steamIDUser, const char *pchName, bool *pbAchieved ) = 0; + // See notes for GetAchievementAndUnlockTime above + virtual bool GetUserAchievementAndUnlockTime( CSteamID steamIDUser, const char *pchName, bool *pbAchieved, uint32 *punUnlockTime ) = 0; + + // Reset stats + virtual bool ResetAllStats( bool bAchievementsToo ) = 0; + + // Leaderboard functions + + // asks the Steam back-end for a leaderboard by name, and will create it if it's not yet + // This call is asynchronous, with the result returned in LeaderboardFindResult_t + virtual SteamAPICall_t FindOrCreateLeaderboard( const char *pchLeaderboardName, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType ) = 0; + + // as above, but won't create the leaderboard if it's not found + // This call is asynchronous, with the result returned in LeaderboardFindResult_t + virtual SteamAPICall_t FindLeaderboard( const char *pchLeaderboardName ) = 0; + + // returns the name of a leaderboard + virtual const char *GetLeaderboardName( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the total number of entries in a leaderboard, as of the last request + virtual int GetLeaderboardEntryCount( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the sort method of the leaderboard + virtual ELeaderboardSortMethod GetLeaderboardSortMethod( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // returns the display type of the leaderboard + virtual ELeaderboardDisplayType GetLeaderboardDisplayType( SteamLeaderboard_t hSteamLeaderboard ) = 0; + + // Asks the Steam back-end for a set of rows in the leaderboard. + // This call is asynchronous, with the result returned in LeaderboardScoresDownloaded_t + // LeaderboardScoresDownloaded_t will contain a handle to pull the results from GetDownloadedLeaderboardEntries() (below) + // You can ask for more entries than exist, and it will return as many as do exist. + // k_ELeaderboardDataRequestGlobal requests rows in the leaderboard from the full table, with nRangeStart & nRangeEnd in the range [1, TotalEntries] + // k_ELeaderboardDataRequestGlobalAroundUser requests rows around the current user, nRangeStart being negate + // e.g. DownloadLeaderboardEntries( hLeaderboard, k_ELeaderboardDataRequestGlobalAroundUser, -3, 3 ) will return 7 rows, 3 before the user, 3 after + // k_ELeaderboardDataRequestFriends requests all the rows for friends of the current user + virtual SteamAPICall_t DownloadLeaderboardEntries( SteamLeaderboard_t hSteamLeaderboard, ELeaderboardDataRequest eLeaderboardDataRequest, int nRangeStart, int nRangeEnd ) = 0; + // as above, but downloads leaderboard entries for an arbitrary set of users - ELeaderboardDataRequest is k_ELeaderboardDataRequestUsers + // if a user doesn't have a leaderboard entry, they won't be included in the result + // a max of 100 users can be downloaded at a time, with only one outstanding call at a time + virtual SteamAPICall_t DownloadLeaderboardEntriesForUsers( SteamLeaderboard_t hSteamLeaderboard, CSteamID *prgUsers, int cUsers ) = 0; + + // Returns data about a single leaderboard entry + // use a for loop from 0 to LeaderboardScoresDownloaded_t::m_cEntryCount to get all the downloaded entries + // e.g. + // void OnLeaderboardScoresDownloaded( LeaderboardScoresDownloaded_t *pLeaderboardScoresDownloaded ) + // { + // for ( int index = 0; index < pLeaderboardScoresDownloaded->m_cEntryCount; index++ ) + // { + // LeaderboardEntry_t leaderboardEntry; + // int32 details[3]; // we know this is how many we've stored previously + // GetDownloadedLeaderboardEntry( pLeaderboardScoresDownloaded->m_hSteamLeaderboardEntries, index, &leaderboardEntry, details, 3 ); + // assert( leaderboardEntry.m_cDetails == 3 ); + // ... + // } + // once you've accessed all the entries, the data will be free'd, and the SteamLeaderboardEntries_t handle will become invalid + virtual bool GetDownloadedLeaderboardEntry( SteamLeaderboardEntries_t hSteamLeaderboardEntries, int index, LeaderboardEntry_t *pLeaderboardEntry, int32 *pDetails, int cDetailsMax ) = 0; + + // Uploads a user score to the Steam back-end. + // This call is asynchronous, with the result returned in LeaderboardScoreUploaded_t + // Details are extra game-defined information regarding how the user got that score + // pScoreDetails points to an array of int32's, cScoreDetailsCount is the number of int32's in the list + virtual SteamAPICall_t UploadLeaderboardScore( SteamLeaderboard_t hSteamLeaderboard, ELeaderboardUploadScoreMethod eLeaderboardUploadScoreMethod, int32 nScore, const int32 *pScoreDetails, int cScoreDetailsCount ) = 0; + + // Attaches a piece of user generated content the user's entry on a leaderboard. + // hContent is a handle to a piece of user generated content that was shared using ISteamUserRemoteStorage::FileShare(). + // This call is asynchronous, with the result returned in LeaderboardUGCSet_t. + virtual SteamAPICall_t AttachLeaderboardUGC( SteamLeaderboard_t hSteamLeaderboard, UGCHandle_t hUGC ) = 0; + + // Retrieves the number of players currently playing your game (online + offline) + // This call is asynchronous, with the result returned in NumberOfCurrentPlayers_t + virtual SteamAPICall_t GetNumberOfCurrentPlayers() = 0; + + // Requests that Steam fetch data on the percentage of players who have received each achievement + // for the game globally. + // This call is asynchronous, with the result returned in GlobalAchievementPercentagesReady_t. + virtual SteamAPICall_t RequestGlobalAchievementPercentages() = 0; + + // Get the info on the most achieved achievement for the game, returns an iterator index you can use to fetch + // the next most achieved afterwards. Will return -1 if there is no data on achievement + // percentages (ie, you haven't called RequestGlobalAchievementPercentages and waited on the callback). + virtual int GetMostAchievedAchievementInfo( char *pchName, uint32 unNameBufLen, float *pflPercent, bool *pbAchieved ) = 0; + + // Get the info on the next most achieved achievement for the game. Call this after GetMostAchievedAchievementInfo or another + // GetNextMostAchievedAchievementInfo call passing the iterator from the previous call. Returns -1 after the last + // achievement has been iterated. + virtual int GetNextMostAchievedAchievementInfo( int iIteratorPrevious, char *pchName, uint32 unNameBufLen, float *pflPercent, bool *pbAchieved ) = 0; + + // Returns the percentage of users who have achieved the specified achievement. + virtual bool GetAchievementAchievedPercent( const char *pchName, float *pflPercent ) = 0; + + // Requests global stats data, which is available for stats marked as "aggregated". + // This call is asynchronous, with the results returned in GlobalStatsReceived_t. + // nHistoryDays specifies how many days of day-by-day history to retrieve in addition + // to the overall totals. The limit is 60. + virtual SteamAPICall_t RequestGlobalStats( int nHistoryDays ) = 0; + + // Gets the lifetime totals for an aggregated stat + virtual bool GetGlobalStat( const char *pchStatName, int64 *pData ) = 0; + virtual bool GetGlobalStat( const char *pchStatName, double *pData ) = 0; + + // Gets history for an aggregated stat. pData will be filled with daily values, starting with today. + // So when called, pData[0] will be today, pData[1] will be yesterday, and pData[2] will be two days ago, + // etc. cubData is the size in bytes of the pubData buffer. Returns the number of + // elements actually set. + virtual int32 GetGlobalStatHistory( const char *pchStatName, int64 *pData, uint32 cubData ) = 0; + virtual int32 GetGlobalStatHistory( const char *pchStatName, double *pData, uint32 cubData ) = 0; + +#ifdef _PS3 + // Call to kick off installation of the PS3 trophies. This call is asynchronous, and the results will be returned in a PS3TrophiesInstalled_t + // callback. + virtual bool InstallPS3Trophies() = 0; + + // Returns the amount of space required at boot to install trophies. This value can be used when comparing the amount of space needed + // by the game to the available space value passed to the game at boot. The value is set during InstallPS3Trophies(). + virtual uint64 GetTrophySpaceRequiredBeforeInstall() = 0; + + // On PS3, user stats & achievement progress through Steam must be stored with the user's saved game data. + // At startup, before calling RequestCurrentStats(), you must pass the user's stats data to Steam via this method. + // If you do not have any user data, call this function with pvData = NULL and cubData = 0 + virtual bool SetUserStatsData( const void *pvData, uint32 cubData ) = 0; + + // Call to get the user's current stats data. You should retrieve this data after receiving successful UserStatsReceived_t & UserStatsStored_t + // callbacks, and store the data with the user's save game data. You can call this method with pvData = NULL and cubData = 0 to get the required + // buffer size. + virtual bool GetUserStatsData( void *pvData, uint32 cubData, uint32 *pcubWritten ) = 0; +#endif +}; + +#define STEAMUSERSTATS_INTERFACE_VERSION "STEAMUSERSTATS_INTERFACE_VERSION011" + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: called when the latests stats and achievements have been received +// from the server +//----------------------------------------------------------------------------- +struct UserStatsReceived_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 1 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // Success / error fetching the stats + CSteamID m_steamIDUser; // The user for whom the stats are retrieved for +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the user stats for a game +//----------------------------------------------------------------------------- +struct UserStatsStored_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 2 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // success / error +}; + + +//----------------------------------------------------------------------------- +// Purpose: result of a request to store the achievements for a game, or an +// "indicate progress" call. If both m_nCurProgress and m_nMaxProgress +// are zero, that means the achievement has been fully unlocked. +//----------------------------------------------------------------------------- +struct UserAchievementStored_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 3 }; + + uint64 m_nGameID; // Game this is for + bool m_bGroupAchievement; // if this is a "group" achievement + char m_rgchAchievementName[k_cchStatNameMax]; // name of the achievement + uint32 m_nCurProgress; // current progress towards the achievement + uint32 m_nMaxProgress; // "out of" this many +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result for finding a leaderboard, returned as a result of FindOrCreateLeaderboard() or FindLeaderboard() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardFindResult_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 4 }; + SteamLeaderboard_t m_hSteamLeaderboard; // handle to the leaderboard serarched for, 0 if no leaderboard found + uint8 m_bLeaderboardFound; // 0 if no leaderboard found +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating scores for a leaderboard have been downloaded and are ready to be retrieved, returned as a result of DownloadLeaderboardEntries() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardScoresDownloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 5 }; + SteamLeaderboard_t m_hSteamLeaderboard; + SteamLeaderboardEntries_t m_hSteamLeaderboardEntries; // the handle to pass into GetDownloadedLeaderboardEntries() + int m_cEntryCount; // the number of entries downloaded +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating scores has been uploaded, returned as a result of UploadLeaderboardScore() +// use CCallResult<> to map this async result to a member function +//----------------------------------------------------------------------------- +struct LeaderboardScoreUploaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 6 }; + uint8 m_bSuccess; // 1 if the call was successful + SteamLeaderboard_t m_hSteamLeaderboard; // the leaderboard handle that was + int32 m_nScore; // the score that was attempted to set + uint8 m_bScoreChanged; // true if the score in the leaderboard change, false if the existing score was better + int m_nGlobalRankNew; // the new global rank of the user in this leaderboard + int m_nGlobalRankPrevious; // the previous global rank of the user in this leaderboard; 0 if the user had no existing entry in the leaderboard +}; + +struct NumberOfCurrentPlayers_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 7 }; + uint8 m_bSuccess; // 1 if the call was successful + int32 m_cPlayers; // Number of players currently playing +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that a user's stats have been unloaded. +// Call RequestUserStats again to access stats for this user +//----------------------------------------------------------------------------- +struct UserStatsUnloaded_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 8 }; + CSteamID m_steamIDUser; // User whose stats have been unloaded +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that an achievement icon has been fetched +//----------------------------------------------------------------------------- +struct UserAchievementIconFetched_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 9 }; + + CGameID m_nGameID; // Game this is for + char m_rgchAchievementName[k_cchStatNameMax]; // name of the achievement + bool m_bAchieved; // Is the icon for the achieved or not achieved version? + int m_nIconHandle; // Handle to the image, which can be used in SteamUtils()->GetImageRGBA(), 0 means no image is set for the achievement +}; + + +//----------------------------------------------------------------------------- +// Purpose: Callback indicating that global achievement percentages are fetched +//----------------------------------------------------------------------------- +struct GlobalAchievementPercentagesReady_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 10 }; + + uint64 m_nGameID; // Game this is for + EResult m_eResult; // Result of the operation +}; + + +//----------------------------------------------------------------------------- +// Purpose: call result indicating UGC has been uploaded, returned as a result of SetLeaderboardUGC() +//----------------------------------------------------------------------------- +struct LeaderboardUGCSet_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 11 }; + EResult m_eResult; // The result of the operation + SteamLeaderboard_t m_hSteamLeaderboard; // the leaderboard handle that was +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating that PS3 trophies have been installed +//----------------------------------------------------------------------------- +struct PS3TrophiesInstalled_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 12 }; + uint64 m_nGameID; // Game these stats are for + EResult m_eResult; // The result of the operation + uint64 m_ulRequiredDiskSpace; // If m_eResult is k_EResultDiskFull, will contain the amount of space needed to install trophies + +}; + + +//----------------------------------------------------------------------------- +// Purpose: callback indicating global stats have been received. +// Returned as a result of RequestGlobalStats() +//----------------------------------------------------------------------------- +struct GlobalStatsReceived_t +{ + enum { k_iCallback = k_iSteamUserStatsCallbacks + 12 }; + uint64 m_nGameID; // Game global stats were requested for + EResult m_eResult; // The result of the request +}; + +#pragma pack( pop ) + + +#endif // ISTEAMUSER_H diff --git a/rehlds/public/steam/isteamutils.h b/rehlds/public/steam/isteamutils.h new file mode 100644 index 0000000..d0bf2c6 --- /dev/null +++ b/rehlds/public/steam/isteamutils.h @@ -0,0 +1,304 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: interface to utility functions in Steam +// +//============================================================================= + +#ifndef ISTEAMUTILS_H +#define ISTEAMUTILS_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" + + +// Steam API call failure results +enum ESteamAPICallFailure +{ + k_ESteamAPICallFailureNone = -1, // no failure + k_ESteamAPICallFailureSteamGone = 0, // the local Steam process has gone away + k_ESteamAPICallFailureNetworkFailure = 1, // the network connection to Steam has been broken, or was already broken + // SteamServersDisconnected_t callback will be sent around the same time + // SteamServersConnected_t will be sent when the client is able to talk to the Steam servers again + k_ESteamAPICallFailureInvalidHandle = 2, // the SteamAPICall_t handle passed in no longer exists + k_ESteamAPICallFailureMismatchedCallback = 3,// GetAPICallResult() was called with the wrong callback type for this API call +}; + + +// Input modes for the Big Picture gamepad text entry +enum EGamepadTextInputMode +{ + k_EGamepadTextInputModeNormal = 0, + k_EGamepadTextInputModePassword = 1 +}; + + +// Controls number of allowed lines for the Big Picture gamepad text entry +enum EGamepadTextInputLineMode +{ + k_EGamepadTextInputLineModeSingleLine = 0, + k_EGamepadTextInputLineModeMultipleLines = 1 +}; + + +// function prototype for warning message hook +#if defined( POSIX ) +#define __cdecl +#endif +extern "C" typedef void (__cdecl *SteamAPIWarningMessageHook_t)(int, const char *); + +//----------------------------------------------------------------------------- +// Purpose: interface to user independent utility functions +//----------------------------------------------------------------------------- +class ISteamUtils +{ +public: + // return the number of seconds since the user + virtual uint32 GetSecondsSinceAppActive() = 0; + virtual uint32 GetSecondsSinceComputerActive() = 0; + + // the universe this client is connecting to + virtual EUniverse GetConnectedUniverse() = 0; + + // Steam server time - in PST, number of seconds since January 1, 1970 (i.e unix time) + virtual uint32 GetServerRealTime() = 0; + + // returns the 2 digit ISO 3166-1-alpha-2 format country code this client is running in (as looked up via an IP-to-location database) + // e.g "US" or "UK". + virtual const char *GetIPCountry() = 0; + + // returns true if the image exists, and valid sizes were filled out + virtual bool GetImageSize( int iImage, uint32 *pnWidth, uint32 *pnHeight ) = 0; + + // returns true if the image exists, and the buffer was successfully filled out + // results are returned in RGBA format + // the destination buffer size should be 4 * height * width * sizeof(char) + virtual bool GetImageRGBA( int iImage, uint8 *pubDest, int nDestBufferSize ) = 0; + + // returns the IP of the reporting server for valve - currently only used in Source engine games + virtual bool GetCSERIPPort( uint32 *unIP, uint16 *usPort ) = 0; + + // return the amount of battery power left in the current system in % [0..100], 255 for being on AC power + virtual uint8 GetCurrentBatteryPower() = 0; + + // returns the appID of the current process + virtual uint32 GetAppID() = 0; + + // Sets the position where the overlay instance for the currently calling game should show notifications. + // This position is per-game and if this function is called from outside of a game context it will do nothing. + virtual void SetOverlayNotificationPosition( ENotificationPosition eNotificationPosition ) = 0; + + // API asynchronous call results + // can be used directly, but more commonly used via the callback dispatch API (see steam_api.h) + virtual bool IsAPICallCompleted( SteamAPICall_t hSteamAPICall, bool *pbFailed ) = 0; + virtual ESteamAPICallFailure GetAPICallFailureReason( SteamAPICall_t hSteamAPICall ) = 0; + virtual bool GetAPICallResult( SteamAPICall_t hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed ) = 0; + + // this needs to be called every frame to process matchmaking results + // redundant if you're already calling SteamAPI_RunCallbacks() + virtual void RunFrame() = 0; + + // returns the number of IPC calls made since the last time this function was called + // Used for perf debugging so you can understand how many IPC calls your game makes per frame + // Every IPC call is at minimum a thread context switch if not a process one so you want to rate + // control how often you do them. + virtual uint32 GetIPCCallCount() = 0; + + // API warning handling + // 'int' is the severity; 0 for msg, 1 for warning + // 'const char *' is the text of the message + // callbacks will occur directly after the API function is called that generated the warning or message + virtual void SetWarningMessageHook( SteamAPIWarningMessageHook_t pFunction ) = 0; + + // Returns true if the overlay is running & the user can access it. The overlay process could take a few seconds to + // start & hook the game process, so this function will initially return false while the overlay is loading. + virtual bool IsOverlayEnabled() = 0; + + // Normally this call is unneeded if your game has a constantly running frame loop that calls the + // D3D Present API, or OGL SwapBuffers API every frame. + // + // However, if you have a game that only refreshes the screen on an event driven basis then that can break + // the overlay, as it uses your Present/SwapBuffers calls to drive it's internal frame loop and it may also + // need to Present() to the screen any time an even needing a notification happens or when the overlay is + // brought up over the game by a user. You can use this API to ask the overlay if it currently need a present + // in that case, and then you can check for this periodically (roughly 33hz is desirable) and make sure you + // refresh the screen with Present or SwapBuffers to allow the overlay to do it's work. + virtual bool BOverlayNeedsPresent() = 0; + +#ifndef _PS3 + // Asynchronous call to check if an executable file has been signed using the public key set on the signing tab + // of the partner site, for example to refuse to load modified executable files. + // The result is returned in CheckFileSignature_t. + // k_ECheckFileSignatureNoSignaturesFoundForThisApp - This app has not been configured on the signing tab of the partner site to enable this function. + // k_ECheckFileSignatureNoSignaturesFoundForThisFile - This file is not listed on the signing tab for the partner site. + // k_ECheckFileSignatureFileNotFound - The file does not exist on disk. + // k_ECheckFileSignatureInvalidSignature - The file exists, and the signing tab has been set for this file, but the file is either not signed or the signature does not match. + // k_ECheckFileSignatureValidSignature - The file is signed and the signature is valid. + virtual SteamAPICall_t CheckFileSignature( const char *szFileName ) = 0; +#endif + +#ifdef _PS3 + virtual void PostPS3SysutilCallback( uint64_t status, uint64_t param, void* userdata ) = 0; + virtual bool BIsReadyToShutdown() = 0; + virtual bool BIsPSNOnline() = 0; + + // Call this with localized strings for the language the game is running in, otherwise default english + // strings will be used by Steam. + virtual void SetPSNGameBootInviteStrings( const char *pchSubject, const char *pchBody ) = 0; +#endif + + // Activates the Big Picture text input dialog which only supports gamepad input + virtual bool ShowGamepadTextInput( EGamepadTextInputMode eInputMode, EGamepadTextInputLineMode eLineInputMode, const char *pchDescription, uint32 unCharMax ) = 0; + + // Returns previously entered text & length + virtual uint32 GetEnteredGamepadTextLength() = 0; + virtual bool GetEnteredGamepadTextInput( char *pchText, uint32 cchText ) = 0; + + // returns the language the steam client is running in, you probably want ISteamApps::GetCurrentGameLanguage instead, this is for very special usage cases + virtual const char *GetSteamUILanguage() = 0; +}; + +#define STEAMUTILS_INTERFACE_VERSION "SteamUtils006" + + +// callbacks +#if defined( VALVE_CALLBACK_PACK_SMALL ) +#pragma pack( push, 4 ) +#elif defined( VALVE_CALLBACK_PACK_LARGE ) +#pragma pack( push, 8 ) +#else +#error isteamclient.h must be included +#endif + +//----------------------------------------------------------------------------- +// Purpose: The country of the user changed +//----------------------------------------------------------------------------- +struct IPCountry_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 1 }; +}; + + +//----------------------------------------------------------------------------- +// Purpose: Fired when running on a laptop and less than 10 minutes of battery is left, fires then every minute +//----------------------------------------------------------------------------- +struct LowBatteryPower_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 2 }; + uint8 m_nMinutesBatteryLeft; +}; + + +//----------------------------------------------------------------------------- +// Purpose: called when a SteamAsyncCall_t has completed (or failed) +//----------------------------------------------------------------------------- +struct SteamAPICallCompleted_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 3 }; + SteamAPICall_t m_hAsyncCall; +}; + + +//----------------------------------------------------------------------------- +// called when Steam wants to shutdown +//----------------------------------------------------------------------------- +struct SteamShutdown_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 4 }; +}; + +//----------------------------------------------------------------------------- +// results for CheckFileSignature +//----------------------------------------------------------------------------- +enum ECheckFileSignature +{ + k_ECheckFileSignatureInvalidSignature = 0, + k_ECheckFileSignatureValidSignature = 1, + k_ECheckFileSignatureFileNotFound = 2, + k_ECheckFileSignatureNoSignaturesFoundForThisApp = 3, + k_ECheckFileSignatureNoSignaturesFoundForThisFile = 4, +}; + +//----------------------------------------------------------------------------- +// callback for CheckFileSignature +//----------------------------------------------------------------------------- +struct CheckFileSignature_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 5 }; + ECheckFileSignature m_eCheckFileSignature; +}; + +#ifdef _PS3 +//----------------------------------------------------------------------------- +// callback for NetCtlNetStartDialog finishing on PS3 +//----------------------------------------------------------------------------- +struct NetStartDialogFinished_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 6 }; +}; + +//----------------------------------------------------------------------------- +// callback for NetCtlNetStartDialog unloaded on PS3 +//----------------------------------------------------------------------------- +struct NetStartDialogUnloaded_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 7 }; +}; + +//----------------------------------------------------------------------------- +// callback for system menu closing on PS3 - should trigger resyncronizing friends list, etc. +//----------------------------------------------------------------------------- +struct PS3SystemMenuClosed_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 8 }; +}; + +//----------------------------------------------------------------------------- +// callback for NP message being selected by user on PS3 - should trigger handling of message if it's a lobby invite, etc. +//----------------------------------------------------------------------------- +struct PS3NPMessageSelected_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 9 }; + uint32 dataid; +}; + +//----------------------------------------------------------------------------- +// callback for when the PS3 keyboard dialog closes +//----------------------------------------------------------------------------- +struct PS3KeyboardDialogFinished_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 10 }; +}; + +// k_iSteamUtilsCallbacks + 11 is taken + +//----------------------------------------------------------------------------- +// callback for PSN status changing on PS3 +//----------------------------------------------------------------------------- +struct PS3PSNStatusChange_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 12 }; + bool m_bPSNOnline; +}; + +#endif + +// k_iSteamUtilsCallbacks + 13 is taken + + +//----------------------------------------------------------------------------- +// Big Picture gamepad text input has been closed +//----------------------------------------------------------------------------- +struct GamepadTextInputDismissed_t +{ + enum { k_iCallback = k_iSteamUtilsCallbacks + 14 }; + bool m_bSubmitted; // true if user entered & accepted text (Call ISteamUtils::GetEnteredGamepadTextInput() for text), false if canceled input + uint32 m_unSubmittedText; +}; + +// k_iSteamUtilsCallbacks + 15 is taken + +#pragma pack( pop ) + +#endif // ISTEAMUTILS_H diff --git a/rehlds/public/steam/matchmakingtypes.h b/rehlds/public/steam/matchmakingtypes.h new file mode 100644 index 0000000..bb06925 --- /dev/null +++ b/rehlds/public/steam/matchmakingtypes.h @@ -0,0 +1,249 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef MATCHMAKINGTYPES_H +#define MATCHMAKINGTYPES_H + +#ifdef _WIN32 +#pragma once +#endif + +#ifdef POSIX +#ifndef _snprintf +#define _snprintf snprintf +#endif +#endif + +#include +#include + +#include "common.h" //Q_snprinf + +// +// Max size (in bytes of UTF-8 data, not in characters) of server fields, including null terminator. +// WARNING: These cannot be changed easily, without breaking clients using old interfaces. +// +const int k_cbMaxGameServerGameDir = 32; +const int k_cbMaxGameServerMapName = 32; +const int k_cbMaxGameServerGameDescription = 64; +const int k_cbMaxGameServerName = 64; +const int k_cbMaxGameServerTags = 128; +const int k_cbMaxGameServerGameData = 2048; + +struct MatchMakingKeyValuePair_t +{ + MatchMakingKeyValuePair_t() { m_szKey[0] = m_szValue[0] = 0; } + MatchMakingKeyValuePair_t( const char *pchKey, const char *pchValue ) + { + strncpy( m_szKey, pchKey, sizeof(m_szKey) ); // this is a public header, use basic c library string funcs only! + m_szKey[ sizeof( m_szKey ) - 1 ] = '\0'; + strncpy( m_szValue, pchValue, sizeof(m_szValue) ); + m_szValue[ sizeof( m_szValue ) - 1 ] = '\0'; + } + char m_szKey[ 256 ]; + char m_szValue[ 256 ]; +}; + + +enum EMatchMakingServerResponse +{ + eServerResponded = 0, + eServerFailedToRespond, + eNoServersListedOnMasterServer // for the Internet query type, returned in response callback if no servers of this type match +}; + +// servernetadr_t is all the addressing info the serverbrowser needs to know about a game server, +// namely: its IP, its connection port, and its query port. +class servernetadr_t +{ +public: + + void Init( unsigned int ip, uint16 usQueryPort, uint16 usConnectionPort ); + +// Uncompatible feature commented +//#ifdef NETADR_H +// netadr_t GetIPAndQueryPort(); +//#endif + + // Access the query port. + uint16 GetQueryPort() const; + void SetQueryPort( uint16 usPort ); + + // Access the connection port. + uint16 GetConnectionPort() const; + void SetConnectionPort( uint16 usPort ); + + // Access the IP + uint32 GetIP() const; + void SetIP( uint32 ); + + // This gets the 'a.b.c.d:port' string with the connection port (instead of the query port). + const char *GetConnectionAddressString() const; + const char *GetQueryAddressString() const; + + // Comparison operators and functions. + bool operator<(const servernetadr_t &netadr) const; + void operator=( const servernetadr_t &that ) + { + m_usConnectionPort = that.m_usConnectionPort; + m_usQueryPort = that.m_usQueryPort; + m_unIP = that.m_unIP; + } + + +private: + const char *ToString( uint32 unIP, uint16 usPort ) const; + uint16 m_usConnectionPort; // (in HOST byte order) + uint16 m_usQueryPort; + uint32 m_unIP; +}; + + +inline void servernetadr_t::Init( unsigned int ip, uint16 usQueryPort, uint16 usConnectionPort ) +{ + m_unIP = ip; + m_usQueryPort = usQueryPort; + m_usConnectionPort = usConnectionPort; +} + +// Uncompatible feature commented +//#ifdef NETADR_H +//inline netadr_t servernetadr_t::GetIPAndQueryPort() +//{ +// return netadr_t( m_unIP, m_usQueryPort ); +//} +//#endif + +inline uint16 servernetadr_t::GetQueryPort() const +{ + return m_usQueryPort; +} + +inline void servernetadr_t::SetQueryPort( uint16 usPort ) +{ + m_usQueryPort = usPort; +} + +inline uint16 servernetadr_t::GetConnectionPort() const +{ + return m_usConnectionPort; +} + +inline void servernetadr_t::SetConnectionPort( uint16 usPort ) +{ + m_usConnectionPort = usPort; +} + +inline uint32 servernetadr_t::GetIP() const +{ + return m_unIP; +} + +inline void servernetadr_t::SetIP( uint32 unIP ) +{ + m_unIP = unIP; +} + +inline const char *servernetadr_t::ToString( uint32 unIP, uint16 usPort ) const +{ + static char s[4][64]; + static int nBuf = 0; + unsigned char *ipByte = (unsigned char *)&unIP; +#ifdef VALVE_BIG_ENDIAN + Q_snprintf (s[nBuf], sizeof( s[nBuf] ), "%u.%u.%u.%u:%i", (int)(ipByte[0]), (int)(ipByte[1]), (int)(ipByte[2]), (int)(ipByte[3]), usPort ); +#else + Q_snprintf (s[nBuf], sizeof( s[nBuf] ), "%u.%u.%u.%u:%i", (int)(ipByte[3]), (int)(ipByte[2]), (int)(ipByte[1]), (int)(ipByte[0]), usPort ); +#endif + const char *pchRet = s[nBuf]; + ++nBuf; + nBuf %= ( (sizeof(s)/sizeof(s[0])) ); + return pchRet; +} + +inline const char* servernetadr_t::GetConnectionAddressString() const +{ + return ToString( m_unIP, m_usConnectionPort ); +} + +inline const char* servernetadr_t::GetQueryAddressString() const +{ + return ToString( m_unIP, m_usQueryPort ); +} + +inline bool servernetadr_t::operator<(const servernetadr_t &netadr) const +{ + return ( m_unIP < netadr.m_unIP ) || ( m_unIP == netadr.m_unIP && m_usQueryPort < netadr.m_usQueryPort ); +} + +//----------------------------------------------------------------------------- +// Purpose: Data describing a single server +//----------------------------------------------------------------------------- +class gameserveritem_t +{ +public: + gameserveritem_t(); + + const char* GetName() const; + void SetName( const char *pName ); + +public: + servernetadr_t m_NetAdr; ///< IP/Query Port/Connection Port for this server + int m_nPing; ///< current ping time in milliseconds + bool m_bHadSuccessfulResponse; ///< server has responded successfully in the past + bool m_bDoNotRefresh; ///< server is marked as not responding and should no longer be refreshed + char m_szGameDir[k_cbMaxGameServerGameDir]; ///< current game directory + char m_szMap[k_cbMaxGameServerMapName]; ///< current map + char m_szGameDescription[k_cbMaxGameServerGameDescription]; ///< game description + uint32 m_nAppID; ///< Steam App ID of this server + int m_nPlayers; ///< total number of players currently on the server. INCLUDES BOTS!! + int m_nMaxPlayers; ///< Maximum players that can join this server + int m_nBotPlayers; ///< Number of bots (i.e simulated players) on this server + bool m_bPassword; ///< true if this server needs a password to join + bool m_bSecure; ///< Is this server protected by VAC + uint32 m_ulTimeLastPlayed; ///< time (in unix time) when this server was last played on (for favorite/history servers) + int m_nServerVersion; ///< server version as reported to Steam + +private: + + /// Game server name + char m_szServerName[k_cbMaxGameServerName]; + + // For data added after SteamMatchMaking001 add it here +public: + /// the tags this server exposes + char m_szGameTags[k_cbMaxGameServerTags]; + + /// steamID of the game server - invalid if it's doesn't have one (old server, or not connected to Steam) + CSteamID m_steamID; +}; + + +inline gameserveritem_t::gameserveritem_t() +{ + m_szGameDir[0] = m_szMap[0] = m_szGameDescription[0] = m_szServerName[0] = 0; + m_bHadSuccessfulResponse = m_bDoNotRefresh = m_bPassword = m_bSecure = false; + m_nPing = m_nAppID = m_nPlayers = m_nMaxPlayers = m_nBotPlayers = m_ulTimeLastPlayed = m_nServerVersion = 0; + m_szGameTags[0] = 0; +} + +inline const char* gameserveritem_t::GetName() const +{ + // Use the IP address as the name if nothing is set yet. + if ( m_szServerName[0] == 0 ) + return m_NetAdr.GetConnectionAddressString(); + else + return m_szServerName; +} + +inline void gameserveritem_t::SetName( const char *pName ) +{ + strncpy( m_szServerName, pName, sizeof( m_szServerName ) ); + m_szServerName[ sizeof( m_szServerName ) - 1 ] = '\0'; +} + + +#endif // MATCHMAKINGTYPES_H diff --git a/rehlds/public/steam/steam_api.h b/rehlds/public/steam/steam_api.h new file mode 100644 index 0000000..10f3037 --- /dev/null +++ b/rehlds/public/steam/steam_api.h @@ -0,0 +1,536 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef STEAM_API_H +#define STEAM_API_H +#ifdef _WIN32 +#pragma once +#endif + +#include "isteamclient.h" +#include "isteamuser.h" +#include "isteamfriends.h" +#include "isteamutils.h" +#include "isteammatchmaking.h" +#include "isteamuserstats.h" +#include "isteamapps.h" +#include "isteamnetworking.h" +#include "isteamremotestorage.h" +#include "isteamscreenshots.h" +#include "isteamhttp.h" +#include "isteamunifiedmessages.h" +#include "isteamcontroller.h" + +#if defined( _PS3 ) +#include "steamps3params.h" +#endif + + + +// Steam API export macro +#if defined( _WIN32 ) && !defined( _X360 ) + #if defined( STEAM_API_EXPORTS ) + #define S_API extern "C" __declspec( dllexport ) + #elif defined( STEAM_API_NODLL ) + #define S_API extern "C" + #else + #define S_API extern "C" __declspec( dllimport ) + #endif // STEAM_API_EXPORTS +#elif defined( GNUC ) + #if defined( STEAM_API_EXPORTS ) + #define S_API extern "C" __attribute__ ((visibility("default"))) + #else + #define S_API extern "C" + #endif // STEAM_API_EXPORTS +#else // !WIN32 + #if defined( STEAM_API_EXPORTS ) + #define S_API extern "C" + #else + #define S_API extern "C" + #endif // STEAM_API_EXPORTS +#endif + +class CCallbackBase; + +#include "rehlds/platform.h" + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// Steam API setup & shutdown +// +// These functions manage loading, initializing and shutdown of the steamclient.dll +// +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +// S_API void SteamAPI_Init(); (see below) +S_API void SteamAPI_Shutdown(); + +// checks if a local Steam client is running +S_API bool SteamAPI_IsSteamRunning(); + +// Detects if your executable was launched through the Steam client, and restarts your game through +// the client if necessary. The Steam client will be started if it is not running. +// +// Returns: true if your executable was NOT launched through the Steam client. This function will +// then start your application through the client. Your current process should exit. +// +// false if your executable was started through the Steam client or a steam_appid.txt file +// is present in your game's directory (for development). Your current process should continue. +// +// NOTE: This function should be used only if you are using CEG or not using Steam's DRM. Once applied +// to your executable, Steam's DRM will handle restarting through Steam if necessary. +S_API bool SteamAPI_RestartAppIfNecessary( uint32 unOwnAppID ); + +// crash dump recording functions +S_API void SteamAPI_WriteMiniDump( uint32 uStructuredExceptionCode, void* pvExceptionInfo, uint32 uBuildID ); +S_API void SteamAPI_SetMiniDumpComment( const char *pchMsg ); + +// interface pointers, configured by SteamAPI_Init() +S_API ISteamClient *SteamClient(); + + +// +// VERSION_SAFE_STEAM_API_INTERFACES is usually not necessary, but it provides safety against releasing +// new steam_api.dll's without recompiling/rereleasing modules that use it. +// +// If you use VERSION_SAFE_STEAM_API_INTERFACES, then you should call SteamAPI_InitSafe(). Also, to get the +// Steam interfaces, you must create and Init() a CSteamAPIContext (below) and use the interfaces in there. +// +// If you don't use VERSION_SAFE_STEAM_API_INTERFACES, then you can use SteamAPI_Init() and the SteamXXXX() +// functions below to get at the Steam interfaces. +// +#ifdef VERSION_SAFE_STEAM_API_INTERFACES +S_API bool SteamAPI_InitSafe(); +#else + +#if defined(_PS3) +S_API bool SteamAPI_Init( SteamPS3Params_t *pParams ); +#else +S_API bool SteamAPI_Init(); +#endif + +S_API ISteamUser *SteamUser(); +S_API ISteamFriends *SteamFriends(); +S_API ISteamUtils *SteamUtils(); +S_API ISteamMatchmaking *SteamMatchmaking(); +S_API ISteamUserStats *SteamUserStats(); +S_API ISteamApps *SteamApps(); +S_API ISteamNetworking *SteamNetworking(); +S_API ISteamMatchmakingServers *SteamMatchmakingServers(); +S_API ISteamRemoteStorage *SteamRemoteStorage(); +S_API ISteamScreenshots *SteamScreenshots(); +S_API ISteamHTTP *SteamHTTP(); +S_API ISteamUnifiedMessages *SteamUnifiedMessages(); +#ifdef _PS3 +S_API ISteamPS3OverlayRender * SteamPS3OverlayRender(); +#endif +#endif // VERSION_SAFE_STEAM_API_INTERFACES + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// steam callback helper functions +// +// The following classes/macros are used to be able to easily multiplex callbacks +// from the Steam API into various objects in the app in a thread-safe manner +// +// These functors are triggered via the SteamAPI_RunCallbacks() function, mapping the callback +// to as many functions/objects as are registered to it +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +S_API void SteamAPI_RunCallbacks(); + + + +// functions used by the utility CCallback objects to receive callbacks +S_API void SteamAPI_RegisterCallback( class CCallbackBase *pCallback, int iCallback ); +S_API void SteamAPI_UnregisterCallback( class CCallbackBase *pCallback ); +// functions used by the utility CCallResult objects to receive async call results +S_API void SteamAPI_RegisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall ); +S_API void SteamAPI_UnregisterCallResult( class CCallbackBase *pCallback, SteamAPICall_t hAPICall ); + + +//----------------------------------------------------------------------------- +// Purpose: base for callbacks, +// used only by CCallback, shouldn't be used directly +//----------------------------------------------------------------------------- +class CCallbackBase +{ +public: + CCallbackBase() { m_nCallbackFlags = 0; m_iCallback = 0; } + // don't add a virtual destructor because we export this binary interface across dll's + virtual void Run( void *pvParam ) = 0; + virtual void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ) = 0; + int GetICallback() { return m_iCallback; } + virtual int GetCallbackSizeBytes() = 0; + + //Added for hooking support + uint8 GetFlags() { return m_nCallbackFlags; } + void SetFlags(uint8 flags) { m_nCallbackFlags = flags; } + void SetICallback(int cb) { m_iCallback = cb; } + +protected: + enum { k_ECallbackFlagsRegistered = 0x01, k_ECallbackFlagsGameServer = 0x02 }; + uint8 m_nCallbackFlags; + int m_iCallback; + friend class CCallbackMgr; +}; + + +//----------------------------------------------------------------------------- +// Purpose: maps a steam async call result to a class member function +// template params: T = local class, P = parameter struct +//----------------------------------------------------------------------------- +template< class T, class P > +class CCallResult : private CCallbackBase +{ +public: + typedef void (T::*func_t)( P*, bool ); + + CCallResult() + { + m_hAPICall = k_uAPICallInvalid; + m_pObj = NULL; + m_Func = NULL; + m_iCallback = P::k_iCallback; + } + + void Set( SteamAPICall_t hAPICall, T *p, func_t func ) + { + if ( m_hAPICall ) + SteamAPI_UnregisterCallResult( this, m_hAPICall ); + + m_hAPICall = hAPICall; + m_pObj = p; + m_Func = func; + + if ( hAPICall ) + SteamAPI_RegisterCallResult( this, hAPICall ); + } + + bool IsActive() const + { + return ( m_hAPICall != k_uAPICallInvalid ); + } + + void Cancel() + { + if ( m_hAPICall != k_uAPICallInvalid ) + { + SteamAPI_UnregisterCallResult( this, m_hAPICall ); + m_hAPICall = k_uAPICallInvalid; + } + + } + + ~CCallResult() + { + Cancel(); + } + + void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; } +private: + virtual void Run( void *pvParam ) + { + m_hAPICall = k_uAPICallInvalid; // caller unregisters for us + (m_pObj->*m_Func)( (P *)pvParam, false ); + } + void Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall ) + { + if ( hSteamAPICall == m_hAPICall ) + { + m_hAPICall = k_uAPICallInvalid; // caller unregisters for us + (m_pObj->*m_Func)( (P *)pvParam, bIOFailure ); + } + } + int GetCallbackSizeBytes() + { + return sizeof( P ); + } + + SteamAPICall_t m_hAPICall; + T *m_pObj; + func_t m_Func; +}; + + + +//----------------------------------------------------------------------------- +// Purpose: maps a steam callback to a class member function +// template params: T = local class, P = parameter struct +//----------------------------------------------------------------------------- +template< class T, class P, bool bGameServer > +class CCallback : protected CCallbackBase +{ +public: + typedef void (T::*func_t)( P* ); + + // If you can't support constructing a callback with the correct parameters + // then uncomment the empty constructor below and manually call + // ::Register() for your object + // Or, just call the regular constructor with (NULL, NULL) + // CCallback() {} + + // constructor for initializing this object in owner's constructor + CCallback( T *pObj, func_t func ) : m_pObj( pObj ), m_Func( func ) + { + if ( pObj && func ) + Register( pObj, func ); + } + + ~CCallback() + { + if ( m_nCallbackFlags & k_ECallbackFlagsRegistered ) + Unregister(); + } + + // manual registration of the callback + void Register( T *pObj, func_t func ) + { + if ( !pObj || !func ) + return; + + if ( m_nCallbackFlags & k_ECallbackFlagsRegistered ) + Unregister(); + + if ( bGameServer ) + { + m_nCallbackFlags |= k_ECallbackFlagsGameServer; + } + m_pObj = pObj; + m_Func = func; + // SteamAPI_RegisterCallback sets k_ECallbackFlagsRegistered + CRehldsPlatformHolder::get()->SteamAPI_RegisterCallback(this, P::k_iCallback); + } + + void Unregister() + { + // SteamAPI_UnregisterCallback removes k_ECallbackFlagsRegistered + CRehldsPlatformHolder::get()->SteamAPI_UnregisterCallback(this); + } + + void SetGameserverFlag() { m_nCallbackFlags |= k_ECallbackFlagsGameServer; } +protected: + virtual void Run( void *pvParam ) + { + (m_pObj->*m_Func)( (P *)pvParam ); + } + virtual void Run( void *pvParam, bool, SteamAPICall_t ) + { + (m_pObj->*m_Func)( (P *)pvParam ); + } + int GetCallbackSizeBytes() + { + return sizeof( P ); + } + + T *m_pObj; + func_t m_Func; +}; + +// Allows you to defer registration of the callback +template< class T, class P, bool bGameServer > +class CCallbackManual : public CCallback< T, P, bGameServer > +{ +public: + CCallbackManual() : CCallback< T, P, bGameServer >( NULL, NULL ) {} +}; + +// utility macro for declaring the function and callback object together +#define STEAM_CALLBACK( thisclass, func, param, var ) CCallback< thisclass, param, false > var; void func( param *pParam ) + +// same as above, but lets you defer the callback binding by calling Register later +#define STEAM_CALLBACK_MANUAL( thisclass, func, param, var ) CCallbackManual< thisclass, param, false > var; void func( param *pParam ) + + +#ifdef _WIN32 +// disable this warning; this pattern need for steam callback registration +#pragma warning( disable: 4355 ) // 'this' : used in base member initializer list +#endif + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// steamclient.dll private wrapper functions +// +// The following functions are part of abstracting API access to the steamclient.dll, but should only be used in very specific cases +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +// pumps out all the steam messages, calling the register callback +S_API void Steam_RunCallbacks( HSteamPipe hSteamPipe, bool bGameServerCallbacks ); + +// register the callback funcs to use to interact with the steam dll +S_API void Steam_RegisterInterfaceFuncs( void *hModule ); + +// returns the HSteamUser of the last user to dispatch a callback +S_API HSteamUser Steam_GetHSteamUserCurrent(); + +// returns the filename path of the current running Steam process, used if you need to load an explicit steam dll by name +S_API const char *SteamAPI_GetSteamInstallPath(); + +// returns the pipe we are communicating to Steam with +S_API HSteamPipe SteamAPI_GetHSteamPipe(); + +// sets whether or not Steam_RunCallbacks() should do a try {} catch (...) {} around calls to issuing callbacks +S_API void SteamAPI_SetTryCatchCallbacks( bool bTryCatchCallbacks ); + +// backwards compat export, passes through to SteamAPI_ variants +S_API HSteamPipe GetHSteamPipe(); +S_API HSteamUser GetHSteamUser(); + +#ifdef VERSION_SAFE_STEAM_API_INTERFACES +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// VERSION_SAFE_STEAM_API_INTERFACES uses CSteamAPIContext to provide interfaces to each module in a way that +// lets them each specify the interface versions they are compiled with. +// +// It's important that these stay inlined in the header so the calling module specifies the interface versions +// for whatever Steam API version it has. +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +S_API HSteamUser SteamAPI_GetHSteamUser(); + +class CSteamAPIContext +{ +public: + CSteamAPIContext(); + void Clear(); + + bool Init(); + + ISteamUser* SteamUser() { return m_pSteamUser; } + ISteamFriends* SteamFriends() { return m_pSteamFriends; } + ISteamUtils* SteamUtils() { return m_pSteamUtils; } + ISteamMatchmaking* SteamMatchmaking() { return m_pSteamMatchmaking; } + ISteamUserStats* SteamUserStats() { return m_pSteamUserStats; } + ISteamApps* SteamApps() { return m_pSteamApps; } + ISteamMatchmakingServers* SteamMatchmakingServers() { return m_pSteamMatchmakingServers; } + ISteamNetworking* SteamNetworking() { return m_pSteamNetworking; } + ISteamRemoteStorage* SteamRemoteStorage() { return m_pSteamRemoteStorage; } + ISteamScreenshots* SteamScreenshots() { return m_pSteamScreenshots; } + ISteamHTTP* SteamHTTP() { return m_pSteamHTTP; } + ISteamUnifiedMessages* SteamUnifiedMessages() { return m_pSteamUnifiedMessages; } +#ifdef _PS3 + ISteamPS3OverlayRender* SteamPS3OverlayRender() { return m_pSteamPS3OverlayRender; } +#endif + +private: + ISteamUser *m_pSteamUser; + ISteamFriends *m_pSteamFriends; + ISteamUtils *m_pSteamUtils; + ISteamMatchmaking *m_pSteamMatchmaking; + ISteamUserStats *m_pSteamUserStats; + ISteamApps *m_pSteamApps; + ISteamMatchmakingServers *m_pSteamMatchmakingServers; + ISteamNetworking *m_pSteamNetworking; + ISteamRemoteStorage *m_pSteamRemoteStorage; + ISteamScreenshots *m_pSteamScreenshots; + ISteamHTTP *m_pSteamHTTP; + ISteamUnifiedMessages*m_pSteamUnifiedMessages; + ISteamController *m_pController; +#ifdef _PS3 + ISteamPS3OverlayRender *m_pSteamPS3OverlayRender; +#endif +}; + +inline CSteamAPIContext::CSteamAPIContext() +{ + Clear(); +} + +inline void CSteamAPIContext::Clear() +{ + m_pSteamUser = NULL; + m_pSteamFriends = NULL; + m_pSteamUtils = NULL; + m_pSteamMatchmaking = NULL; + m_pSteamUserStats = NULL; + m_pSteamApps = NULL; + m_pSteamMatchmakingServers = NULL; + m_pSteamNetworking = NULL; + m_pSteamRemoteStorage = NULL; + m_pSteamHTTP = NULL; + m_pSteamScreenshots = NULL; + m_pSteamUnifiedMessages = NULL; +#ifdef _PS3 + m_pSteamPS3OverlayRender = NULL; +#endif +} + +// This function must be inlined so the module using steam_api.dll gets the version names they want. +inline bool CSteamAPIContext::Init() +{ + if ( !SteamClient() ) + return false; + + HSteamUser hSteamUser = SteamAPI_GetHSteamUser(); + HSteamPipe hSteamPipe = SteamAPI_GetHSteamPipe(); + + m_pSteamUser = SteamClient()->GetISteamUser( hSteamUser, hSteamPipe, STEAMUSER_INTERFACE_VERSION ); + if ( !m_pSteamUser ) + return false; + + m_pSteamFriends = SteamClient()->GetISteamFriends( hSteamUser, hSteamPipe, STEAMFRIENDS_INTERFACE_VERSION ); + if ( !m_pSteamFriends ) + return false; + + m_pSteamUtils = SteamClient()->GetISteamUtils( hSteamPipe, STEAMUTILS_INTERFACE_VERSION ); + if ( !m_pSteamUtils ) + return false; + + m_pSteamMatchmaking = SteamClient()->GetISteamMatchmaking( hSteamUser, hSteamPipe, STEAMMATCHMAKING_INTERFACE_VERSION ); + if ( !m_pSteamMatchmaking ) + return false; + + m_pSteamMatchmakingServers = SteamClient()->GetISteamMatchmakingServers( hSteamUser, hSteamPipe, STEAMMATCHMAKINGSERVERS_INTERFACE_VERSION ); + if ( !m_pSteamMatchmakingServers ) + return false; + + m_pSteamUserStats = SteamClient()->GetISteamUserStats( hSteamUser, hSteamPipe, STEAMUSERSTATS_INTERFACE_VERSION ); + if ( !m_pSteamUserStats ) + return false; + + m_pSteamApps = SteamClient()->GetISteamApps( hSteamUser, hSteamPipe, STEAMAPPS_INTERFACE_VERSION ); + if ( !m_pSteamApps ) + return false; + + m_pSteamNetworking = SteamClient()->GetISteamNetworking( hSteamUser, hSteamPipe, STEAMNETWORKING_INTERFACE_VERSION ); + if ( !m_pSteamNetworking ) + return false; + + m_pSteamRemoteStorage = SteamClient()->GetISteamRemoteStorage( hSteamUser, hSteamPipe, STEAMREMOTESTORAGE_INTERFACE_VERSION ); + if ( !m_pSteamRemoteStorage ) + return false; + + m_pSteamScreenshots = SteamClient()->GetISteamScreenshots( hSteamUser, hSteamPipe, STEAMSCREENSHOTS_INTERFACE_VERSION ); + if ( !m_pSteamScreenshots ) + return false; + + m_pSteamHTTP = SteamClient()->GetISteamHTTP( hSteamUser, hSteamPipe, STEAMHTTP_INTERFACE_VERSION ); + if ( !m_pSteamHTTP ) + return false; + + m_pSteamUnifiedMessages = SteamClient()->GetISteamUnifiedMessages( hSteamUser, hSteamPipe, STEAMUNIFIEDMESSAGES_INTERFACE_VERSION ); + if ( !m_pSteamUnifiedMessages ) + return false; + +#ifdef _PS3 + m_pSteamPS3OverlayRender = SteamClient()->GetISteamPS3OverlayRender(); +#endif + + return true; +} + +#endif // VERSION_SAFE_STEAM_API_INTERFACES + +#if defined(USE_BREAKPAD_HANDLER) || defined(STEAM_API_EXPORTS) +// this should be called before the game initialized the steam APIs +// pchDate should be of the format "Mmm dd yyyy" (such as from the __DATE __ macro ) +// pchTime should be of the format "hh:mm:ss" (such as from the __TIME __ macro ) +// bFullMemoryDumps (Win32 only) -- writes out a uuid-full.dmp in the client/dumps folder +// pvContext-- can be NULL, will be the void * context passed into m_pfnPreMinidumpCallback +// PFNPreMinidumpCallback m_pfnPreMinidumpCallback -- optional callback which occurs just before a .dmp file is written during a crash. Applications can hook this to allow adding additional information into the .dmp comment stream. +S_API void SteamAPI_UseBreakpadCrashHandler( char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback ); +S_API void SteamAPI_SetBreakpadAppID( uint32 unAppID ); +#endif + +#endif // STEAM_API_H diff --git a/rehlds/public/steam/steam_gameserver.h b/rehlds/public/steam/steam_gameserver.h new file mode 100644 index 0000000..47cb784 --- /dev/null +++ b/rehlds/public/steam/steam_gameserver.h @@ -0,0 +1,163 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef STEAM_GAMESERVER_H +#define STEAM_GAMESERVER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "steam_api.h" +#include "isteamgameserver.h" +#include "isteamgameserverstats.h" + +enum EServerMode +{ + eServerModeInvalid = 0, // DO NOT USE + eServerModeNoAuthentication = 1, // Don't authenticate user logins and don't list on the server list + eServerModeAuthentication = 2, // Authenticate users, list on the server list, don't run VAC on clients that connect + eServerModeAuthenticationAndSecure = 3, // Authenticate users, list on the server list and VAC protect clients +}; + +// Initialize ISteamGameServer interface object, and set server properties which may not be changed. +// +// After calling this function, you should set any additional server parameters, and then +// call ISteamGameServer::LogOnAnonymous() or ISteamGameServer::LogOn() +// +// - usSteamPort is the local port used to communicate with the steam servers. +// - usGamePort is the port that clients will connect to for gameplay. +// - usQueryPort is the port that will manage server browser related duties and info +// pings from clients. If you pass MASTERSERVERUPDATERPORT_USEGAMESOCKETSHARE for usQueryPort, then it +// will use "GameSocketShare" mode, which means that the game is responsible for sending and receiving +// UDP packets for the master server updater. See references to GameSocketShare in isteamgameserver.h. +// - The version string is usually in the form x.x.x.x, and is used by the master server to detect when the +// server is out of date. (Only servers with the latest version will be listed.) +#ifndef _PS3 + +#ifdef VERSION_SAFE_STEAM_API_INTERFACES +S_API bool SteamGameServer_InitSafe( uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ); +#else +S_API bool SteamGameServer_Init( uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ); +#endif + +#else + +#ifdef VERSION_SAFE_STEAM_API_INTERFACES +S_API bool SteamGameServer_InitSafe( const SteamPS3Params_t *ps3Params, uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ); +#else +S_API bool SteamGameServer_Init( const SteamPS3Params_t *ps3Params, uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString ); +#endif + +#endif + +#ifndef VERSION_SAFE_STEAM_API_INTERFACES +S_API ISteamGameServer *SteamGameServer(); +S_API ISteamUtils *SteamGameServerUtils(); +S_API ISteamNetworking *SteamGameServerNetworking(); +S_API ISteamGameServerStats *SteamGameServerStats(); +S_API ISteamHTTP *SteamGameServerHTTP(); +#endif + +S_API void SteamGameServer_Shutdown(); +S_API void SteamGameServer_RunCallbacks(); + +S_API bool SteamGameServer_BSecure(); +S_API uint64 SteamGameServer_GetSteamID(); + +#define STEAM_GAMESERVER_CALLBACK( thisclass, func, param, var ) CCallback< thisclass, param, true > var; void func( param *pParam ) + + +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// steamclient.dll private wrapper functions +// +// The following functions are part of abstracting API access to the steamclient.dll, but should only be used in very specific cases +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +S_API HSteamPipe SteamGameServer_GetHSteamPipe(); + +#ifdef VERSION_SAFE_STEAM_API_INTERFACES +//----------------------------------------------------------------------------------------------------------------------------------------------------------// +// VERSION_SAFE_STEAM_API_INTERFACES uses CSteamAPIContext to provide interfaces to each module in a way that +// lets them each specify the interface versions they are compiled with. +// +// It's important that these stay inlined in the header so the calling module specifies the interface versions +// for whatever Steam API version it has. +//----------------------------------------------------------------------------------------------------------------------------------------------------------// + +S_API HSteamUser SteamGameServer_GetHSteamUser(); + +class CSteamGameServerAPIContext +{ +public: + CSteamGameServerAPIContext(); + void Clear(); + + bool Init(); + + ISteamGameServer *SteamGameServer() { return m_pSteamGameServer; } + ISteamUtils *SteamGameServerUtils() { return m_pSteamGameServerUtils; } + ISteamNetworking *SteamGameServerNetworking() { return m_pSteamGameServerNetworking; } + ISteamGameServerStats *SteamGameServerStats() { return m_pSteamGameServerStats; } + ISteamHTTP *SteamHTTP() { return m_pSteamHTTP; } + +private: + ISteamGameServer *m_pSteamGameServer; + ISteamUtils *m_pSteamGameServerUtils; + ISteamNetworking *m_pSteamGameServerNetworking; + ISteamGameServerStats *m_pSteamGameServerStats; + ISteamHTTP *m_pSteamHTTP; +}; + +inline CSteamGameServerAPIContext::CSteamGameServerAPIContext() +{ + Clear(); +} + +inline void CSteamGameServerAPIContext::Clear() +{ + m_pSteamGameServer = NULL; + m_pSteamGameServerUtils = NULL; + m_pSteamGameServerNetworking = NULL; + m_pSteamGameServerStats = NULL; + m_pSteamHTTP = NULL; +} + +S_API ISteamClient *g_pSteamClientGameServer; +// This function must be inlined so the module using steam_api.dll gets the version names they want. +inline bool CSteamGameServerAPIContext::Init() +{ + if ( !g_pSteamClientGameServer ) + return false; + + HSteamUser hSteamUser = SteamGameServer_GetHSteamUser(); + HSteamPipe hSteamPipe = SteamGameServer_GetHSteamPipe(); + + m_pSteamGameServer = g_pSteamClientGameServer->GetISteamGameServer( hSteamUser, hSteamPipe, STEAMGAMESERVER_INTERFACE_VERSION ); + if ( !m_pSteamGameServer ) + return false; + + m_pSteamGameServerUtils = g_pSteamClientGameServer->GetISteamUtils( hSteamPipe, STEAMUTILS_INTERFACE_VERSION ); + if ( !m_pSteamGameServerUtils ) + return false; + + m_pSteamGameServerNetworking = g_pSteamClientGameServer->GetISteamNetworking( hSteamUser, hSteamPipe, STEAMNETWORKING_INTERFACE_VERSION ); + if ( !m_pSteamGameServerNetworking ) + return false; + + m_pSteamGameServerStats = g_pSteamClientGameServer->GetISteamGameServerStats( hSteamUser, hSteamPipe, STEAMGAMESERVERSTATS_INTERFACE_VERSION ); + if ( !m_pSteamGameServerStats ) + return false; + + m_pSteamHTTP = g_pSteamClientGameServer->GetISteamHTTP( hSteamUser, hSteamPipe, STEAMHTTP_INTERFACE_VERSION ); + if ( !m_pSteamGameServerStats ) + return false; + + return true; +} + +#endif // VERSION_SAFE_STEAM_API_INTERFACES + + +#endif // STEAM_GAMESERVER_H diff --git a/rehlds/public/steam/steamclientpublic.h b/rehlds/public/steam/steamclientpublic.h new file mode 100644 index 0000000..d9d076a --- /dev/null +++ b/rehlds/public/steam/steamclientpublic.h @@ -0,0 +1,1086 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef STEAMCLIENTPUBLIC_H +#define STEAMCLIENTPUBLIC_H +#ifdef _WIN32 +#pragma once +#endif +//lint -save -e1931 -e1927 -e1924 -e613 -e726 + +// This header file defines the interface between the calling application and the code that +// knows how to communicate with the connection manager (CM) from the Steam service + +// This header file is intended to be portable; ideally this 1 header file plus a lib or dll +// is all you need to integrate the client library into some other tree. So please avoid +// including or requiring other header files if possible. This header should only describe the +// interface layer, no need to include anything about the implementation. + +#include "steamtypes.h" + + +// General result codes +enum EResult +{ + k_EResultOK = 1, // success + k_EResultFail = 2, // generic failure + k_EResultNoConnection = 3, // no/failed network connection +// k_EResultNoConnectionRetry = 4, // OBSOLETE - removed + k_EResultInvalidPassword = 5, // password/ticket is invalid + k_EResultLoggedInElsewhere = 6, // same user logged in elsewhere + k_EResultInvalidProtocolVer = 7, // protocol version is incorrect + k_EResultInvalidParam = 8, // a parameter is incorrect + k_EResultFileNotFound = 9, // file was not found + k_EResultBusy = 10, // called method busy - action not taken + k_EResultInvalidState = 11, // called object was in an invalid state + k_EResultInvalidName = 12, // name is invalid + k_EResultInvalidEmail = 13, // email is invalid + k_EResultDuplicateName = 14, // name is not unique + k_EResultAccessDenied = 15, // access is denied + k_EResultTimeout = 16, // operation timed out + k_EResultBanned = 17, // VAC2 banned + k_EResultAccountNotFound = 18, // account not found + k_EResultInvalidSteamID = 19, // steamID is invalid + k_EResultServiceUnavailable = 20, // The requested service is currently unavailable + k_EResultNotLoggedOn = 21, // The user is not logged on + k_EResultPending = 22, // Request is pending (may be in process, or waiting on third party) + k_EResultEncryptionFailure = 23, // Encryption or Decryption failed + k_EResultInsufficientPrivilege = 24, // Insufficient privilege + k_EResultLimitExceeded = 25, // Too much of a good thing + k_EResultRevoked = 26, // Access has been revoked (used for revoked guest passes) + k_EResultExpired = 27, // License/Guest pass the user is trying to access is expired + k_EResultAlreadyRedeemed = 28, // Guest pass has already been redeemed by account, cannot be acked again + k_EResultDuplicateRequest = 29, // The request is a duplicate and the action has already occurred in the past, ignored this time + k_EResultAlreadyOwned = 30, // All the games in this guest pass redemption request are already owned by the user + k_EResultIPNotFound = 31, // IP address not found + k_EResultPersistFailed = 32, // failed to write change to the data store + k_EResultLockingFailed = 33, // failed to acquire access lock for this operation + k_EResultLogonSessionReplaced = 34, + k_EResultConnectFailed = 35, + k_EResultHandshakeFailed = 36, + k_EResultIOFailure = 37, + k_EResultRemoteDisconnect = 38, + k_EResultShoppingCartNotFound = 39, // failed to find the shopping cart requested + k_EResultBlocked = 40, // a user didn't allow it + k_EResultIgnored = 41, // target is ignoring sender + k_EResultNoMatch = 42, // nothing matching the request found + k_EResultAccountDisabled = 43, + k_EResultServiceReadOnly = 44, // this service is not accepting content changes right now + k_EResultAccountNotFeatured = 45, // account doesn't have value, so this feature isn't available + k_EResultAdministratorOK = 46, // allowed to take this action, but only because requester is admin + k_EResultContentVersion = 47, // A Version mismatch in content transmitted within the Steam protocol. + k_EResultTryAnotherCM = 48, // The current CM can't service the user making a request, user should try another. + k_EResultPasswordRequiredToKickSession = 49,// You are already logged in elsewhere, this cached credential login has failed. + k_EResultAlreadyLoggedInElsewhere = 50, // You are already logged in elsewhere, you must wait + k_EResultSuspended = 51, // Long running operation (content download) suspended/paused + k_EResultCancelled = 52, // Operation canceled (typically by user: content download) + k_EResultDataCorruption = 53, // Operation canceled because data is ill formed or unrecoverable + k_EResultDiskFull = 54, // Operation canceled - not enough disk space. + k_EResultRemoteCallFailed = 55, // an remote call or IPC call failed + k_EResultPasswordUnset = 56, // Password could not be verified as it's unset server side + k_EResultExternalAccountUnlinked = 57, // External account (PSN, Facebook...) is not linked to a Steam account + k_EResultPSNTicketInvalid = 58, // PSN ticket was invalid + k_EResultExternalAccountAlreadyLinked = 59, // External account (PSN, Facebook...) is already linked to some other account, must explicitly request to replace/delete the link first + k_EResultRemoteFileConflict = 60, // The sync cannot resume due to a conflict between the local and remote files + k_EResultIllegalPassword = 61, // The requested new password is not legal + k_EResultSameAsPreviousValue = 62, // new value is the same as the old one ( secret question and answer ) + k_EResultAccountLogonDenied = 63, // account login denied due to 2nd factor authentication failure + k_EResultCannotUseOldPassword = 64, // The requested new password is not legal + k_EResultInvalidLoginAuthCode = 65, // account login denied due to auth code invalid + k_EResultAccountLogonDeniedNoMail = 66, // account login denied due to 2nd factor auth failure - and no mail has been sent + k_EResultHardwareNotCapableOfIPT = 67, // + k_EResultIPTInitError = 68, // + k_EResultParentalControlRestricted = 69, // operation failed due to parental control restrictions for current user + k_EResultFacebookQueryError = 70, // Facebook query returned an error + k_EResultExpiredLoginAuthCode = 71, // account login denied due to auth code expired + k_EResultIPLoginRestrictionFailed = 72, + k_EResultAccountLockedDown = 73, + k_EResultAccountLogonDeniedVerifiedEmailRequired = 74, + k_EResultNoMatchingURL = 75, + k_EResultBadResponse = 76, // parse failure, missing field, etc. + k_EResultRequirePasswordReEntry = 77, // The user cannot complete the action until they re-enter their password + k_EResultValueOutOfRange = 78 // the value entered is outside the acceptable range +}; + +// Error codes for use with the voice functions +enum EVoiceResult +{ + k_EVoiceResultOK = 0, + k_EVoiceResultNotInitialized = 1, + k_EVoiceResultNotRecording = 2, + k_EVoiceResultNoData = 3, + k_EVoiceResultBufferTooSmall = 4, + k_EVoiceResultDataCorrupted = 5, + k_EVoiceResultRestricted = 6, + k_EVoiceResultUnsupportedCodec = 7, + +}; + +// Result codes to GSHandleClientDeny/Kick +typedef enum +{ + k_EDenyInvalid = 0, + k_EDenyInvalidVersion = 1, + k_EDenyGeneric = 2, + k_EDenyNotLoggedOn = 3, + k_EDenyNoLicense = 4, + k_EDenyCheater = 5, + k_EDenyLoggedInElseWhere = 6, + k_EDenyUnknownText = 7, + k_EDenyIncompatibleAnticheat = 8, + k_EDenyMemoryCorruption = 9, + k_EDenyIncompatibleSoftware = 10, + k_EDenySteamConnectionLost = 11, + k_EDenySteamConnectionError = 12, + k_EDenySteamResponseTimedOut = 13, + k_EDenySteamValidationStalled = 14, + k_EDenySteamOwnerLeftGuestUser = 15, +} EDenyReason; + +// return type of GetAuthSessionTicket +typedef uint32 HAuthTicket; +const HAuthTicket k_HAuthTicketInvalid = 0; + +// results from BeginAuthSession +typedef enum +{ + k_EBeginAuthSessionResultOK = 0, // Ticket is valid for this game and this steamID. + k_EBeginAuthSessionResultInvalidTicket = 1, // Ticket is not valid. + k_EBeginAuthSessionResultDuplicateRequest = 2, // A ticket has already been submitted for this steamID + k_EBeginAuthSessionResultInvalidVersion = 3, // Ticket is from an incompatible interface version + k_EBeginAuthSessionResultGameMismatch = 4, // Ticket is not for this game + k_EBeginAuthSessionResultExpiredTicket = 5, // Ticket has expired +} EBeginAuthSessionResult; + +// Callback values for callback ValidateAuthTicketResponse_t which is a response to BeginAuthSession +typedef enum +{ + k_EAuthSessionResponseOK = 0, // Steam has verified the user is online, the ticket is valid and ticket has not been reused. + k_EAuthSessionResponseUserNotConnectedToSteam = 1, // The user in question is not connected to steam + k_EAuthSessionResponseNoLicenseOrExpired = 2, // The license has expired. + k_EAuthSessionResponseVACBanned = 3, // The user is VAC banned for this game. + k_EAuthSessionResponseLoggedInElseWhere = 4, // The user account has logged in elsewhere and the session containing the game instance has been disconnected. + k_EAuthSessionResponseVACCheckTimedOut = 5, // VAC has been unable to perform anti-cheat checks on this user + k_EAuthSessionResponseAuthTicketCanceled = 6, // The ticket has been canceled by the issuer + k_EAuthSessionResponseAuthTicketInvalidAlreadyUsed = 7, // This ticket has already been used, it is not valid. + k_EAuthSessionResponseAuthTicketInvalid = 8, // This ticket is not from a user instance currently connected to steam. +} EAuthSessionResponse; + +// results from UserHasLicenseForApp +typedef enum +{ + k_EUserHasLicenseResultHasLicense = 0, // User has a license for specified app + k_EUserHasLicenseResultDoesNotHaveLicense = 1, // User does not have a license for the specified app + k_EUserHasLicenseResultNoAuth = 2, // User has not been authenticated +} EUserHasLicenseForAppResult; + + +// Steam universes. Each universe is a self-contained Steam instance. +enum EUniverse +{ + k_EUniverseInvalid = 0, + k_EUniversePublic = 1, + k_EUniverseBeta = 2, + k_EUniverseInternal = 3, + k_EUniverseDev = 4, + // k_EUniverseRC = 5, // no such universe anymore + k_EUniverseMax +}; + +// Steam account types +enum EAccountType +{ + k_EAccountTypeInvalid = 0, + k_EAccountTypeIndividual = 1, // single user account + k_EAccountTypeMultiseat = 2, // multiseat (e.g. cybercafe) account + k_EAccountTypeGameServer = 3, // game server account + k_EAccountTypeAnonGameServer = 4, // anonymous game server account + k_EAccountTypePending = 5, // pending + k_EAccountTypeContentServer = 6, // content server + k_EAccountTypeClan = 7, + k_EAccountTypeChat = 8, + k_EAccountTypeConsoleUser = 9, // Fake SteamID for local PSN account on PS3 or Live account on 360, etc. + k_EAccountTypeAnonUser = 10, + + // Max of 16 items in this field + k_EAccountTypeMax +}; + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +enum EAppReleaseState +{ + k_EAppReleaseState_Unknown = 0, // unknown, required appinfo or license info is missing + k_EAppReleaseState_Unavailable = 1, // even if user 'just' owns it, can see game at all + k_EAppReleaseState_Prerelease = 2, // can be purchased and is visible in games list, nothing else. Common appInfo section released + k_EAppReleaseState_PreloadOnly = 3, // owners can preload app, not play it. AppInfo fully released. + k_EAppReleaseState_Released = 4, // owners can download and play app. +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +enum EAppOwernshipFlags +{ + k_EAppOwernshipFlags_None = 0, // unknown + k_EAppOwernshipFlags_OwnsLicense = 1, // owns license for this game + k_EAppOwernshipFlags_FreeLicense = 2, // not paid for game + k_EAppOwernshipFlags_RegionRestricted = 4, // owns app, but not allowed to play in current region + k_EAppOwernshipFlags_LowViolence = 8, // only low violence version + k_EAppOwernshipFlags_InvalidPlatform = 16, // app not supported on current platform + k_EAppOwernshipFlags_DeviceLicense = 32, // license was granted by authorized local device +}; + + +//----------------------------------------------------------------------------- +// Purpose: designed as flags to allow filters masks +//----------------------------------------------------------------------------- +enum EAppType +{ + k_EAppType_Invalid = 0x000, // unknown / invalid + k_EAppType_Game = 0x001, // playable game, default type + k_EAppType_Application = 0x002, // software application + k_EAppType_Tool = 0x004, // SDKs, editors & dedicated servers + k_EAppType_Demo = 0x008, // game demo + k_EAppType_Media = 0x010, // media trailer + k_EAppType_DLC = 0x020, // down loadable content + k_EAppType_Guide = 0x040, // game guide, PDF etc + k_EAppType_Driver = 0x080, // hardware driver updater (ATI, Razor etc) + + k_EAppType_Shortcut = 0x40000000, // just a shortcut, client side only + k_EAppType_DepotOnly = 0x80000000, // placeholder since depots and apps share the same namespace +}; + + +//----------------------------------------------------------------------------- +// types of user game stats fields +// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN DATABASE +//----------------------------------------------------------------------------- +enum ESteamUserStatType +{ + k_ESteamUserStatTypeINVALID = 0, + k_ESteamUserStatTypeINT = 1, + k_ESteamUserStatTypeFLOAT = 2, + // Read as FLOAT, set with count / session length + k_ESteamUserStatTypeAVGRATE = 3, + k_ESteamUserStatTypeACHIEVEMENTS = 4, + k_ESteamUserStatTypeGROUPACHIEVEMENTS = 5, + + // max, for sanity checks + k_ESteamUserStatTypeMAX +}; + + +//----------------------------------------------------------------------------- +// Purpose: Chat Entry Types (previously was only friend-to-friend message types) +//----------------------------------------------------------------------------- +enum EChatEntryType +{ + k_EChatEntryTypeInvalid = 0, + k_EChatEntryTypeChatMsg = 1, // Normal text message from another user + k_EChatEntryTypeTyping = 2, // Another user is typing (not used in multi-user chat) + k_EChatEntryTypeInviteGame = 3, // Invite from other user into that users current game + k_EChatEntryTypeEmote = 4, // text emote message (deprecated, should be treated as ChatMsg) + //k_EChatEntryTypeLobbyGameStart = 5, // lobby game is starting (dead - listen for LobbyGameCreated_t callback instead) + k_EChatEntryTypeLeftConversation = 6, // user has left the conversation ( closed chat window ) + // Above are previous FriendMsgType entries, now merged into more generic chat entry types + k_EChatEntryTypeEntered = 7, // user has entered the conversation (used in multi-user chat and group chat) + k_EChatEntryTypeWasKicked = 8, // user was kicked (data: 64-bit steamid of actor performing the kick) + k_EChatEntryTypeWasBanned = 9, // user was banned (data: 64-bit steamid of actor performing the ban) + k_EChatEntryTypeDisconnected = 10, // user disconnected + k_EChatEntryTypeHistoricalChat = 11, // a chat message from user's chat history or offilne message + +}; + + +//----------------------------------------------------------------------------- +// Purpose: Chat Room Enter Responses +//----------------------------------------------------------------------------- +enum EChatRoomEnterResponse +{ + k_EChatRoomEnterResponseSuccess = 1, // Success + k_EChatRoomEnterResponseDoesntExist = 2, // Chat doesn't exist (probably closed) + k_EChatRoomEnterResponseNotAllowed = 3, // General Denied - You don't have the permissions needed to join the chat + k_EChatRoomEnterResponseFull = 4, // Chat room has reached its maximum size + k_EChatRoomEnterResponseError = 5, // Unexpected Error + k_EChatRoomEnterResponseBanned = 6, // You are banned from this chat room and may not join + k_EChatRoomEnterResponseLimited = 7, // Joining this chat is not allowed because you are a limited user (no value on account) + k_EChatRoomEnterResponseClanDisabled = 8, // Attempt to join a clan chat when the clan is locked or disabled + k_EChatRoomEnterResponseCommunityBan = 9, // Attempt to join a chat when the user has a community lock on their account + k_EChatRoomEnterResponseMemberBlockedYou = 10, // Join failed - some member in the chat has blocked you from joining + k_EChatRoomEnterResponseYouBlockedMember = 11, // Join failed - you have blocked some member already in the chat + // k_EChatRoomEnterResponseNoRankingDataLobby = 12, // No longer used + // k_EChatRoomEnterResponseNoRankingDataUser = 13, // No longer used + // k_EChatRoomEnterResponseRankOutOfRange = 14, // No longer used +}; + + +//----------------------------------------------------------------------------- +// Purpose: Status of a given depot version, these are stored in the DB, don't renumber +//----------------------------------------------------------------------------- +enum EStatusDepotVersion +{ + k_EStatusDepotVersionInvalid = 0, + k_EStatusDepotVersionDisabled = 1, // version was disabled, no manifest & content available + k_EStatusDepotVersionAvailable = 2, // manifest & content is available, but not current + k_EStatusDepotVersionCurrent = 3, // current depot version. The can be multiple, one for public and one for each beta key +}; + + +typedef void (*PFNLegacyKeyRegistration)( const char *pchCDKey, const char *pchInstallPath ); +typedef bool (*PFNLegacyKeyInstalled)(); + +const unsigned int k_unSteamAccountIDMask = 0xFFFFFFFF; +const unsigned int k_unSteamAccountInstanceMask = 0x000FFFFF; +// we allow 3 simultaneous user account instances right now, 1= desktop, 2 = console, 4 = web, 0 = all +const unsigned int k_unSteamUserDesktopInstance = 1; +const unsigned int k_unSteamUserConsoleInstance = 2; +const unsigned int k_unSteamUserWebInstance = 4; + +// Special flags for Chat accounts - they go in the top 8 bits +// of the steam ID's "instance", leaving 12 for the actual instances +enum EChatSteamIDInstanceFlags +{ + k_EChatAccountInstanceMask = 0x00000FFF, // top 8 bits are flags + + k_EChatInstanceFlagClan = ( k_unSteamAccountInstanceMask + 1 ) >> 1, // top bit + k_EChatInstanceFlagLobby = ( k_unSteamAccountInstanceMask + 1 ) >> 2, // next one down, etc + k_EChatInstanceFlagMMSLobby = ( k_unSteamAccountInstanceMask + 1 ) >> 3, // next one down, etc + + // Max of 8 flags +}; + + +//----------------------------------------------------------------------------- +// Purpose: Marketing message flags that change how a client should handle them +//----------------------------------------------------------------------------- +enum EMarketingMessageFlags +{ + k_EMarketingMessageFlagsNone = 0, + k_EMarketingMessageFlagsHighPriority = 1 << 0, + k_EMarketingMessageFlagsPlatformWindows = 1 << 1, + k_EMarketingMessageFlagsPlatformMac = 1 << 2, + k_EMarketingMessageFlagsPlatformLinux = 1 << 3, + + //aggregate flags + k_EMarketingMessageFlagsPlatformRestrictions = + k_EMarketingMessageFlagsPlatformWindows | + k_EMarketingMessageFlagsPlatformMac | + k_EMarketingMessageFlagsPlatformLinux, +}; + + + +//----------------------------------------------------------------------------- +// Purpose: Possible positions to tell the overlay to show notifications in +//----------------------------------------------------------------------------- +enum ENotificationPosition +{ + k_EPositionTopLeft = 0, + k_EPositionTopRight = 1, + k_EPositionBottomLeft = 2, + k_EPositionBottomRight = 3, +}; + + +#pragma pack( push, 1 ) + +#define CSTEAMID_DEFINED + +// Steam ID structure (64 bits total) +class CSteamID +{ +public: + + //----------------------------------------------------------------------------- + // Purpose: Constructor + //----------------------------------------------------------------------------- + CSteamID() + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = k_EAccountTypeInvalid; + m_steamid.m_comp.m_EUniverse = k_EUniverseInvalid; + m_steamid.m_comp.m_unAccountInstance = 0; + } + + + //----------------------------------------------------------------------------- + // Purpose: Constructor + // Input : unAccountID - 32-bit account ID + // eUniverse - Universe this account belongs to + // eAccountType - Type of account + //----------------------------------------------------------------------------- + CSteamID( uint32 unAccountID, EUniverse eUniverse, EAccountType eAccountType ) + { + Set( unAccountID, eUniverse, eAccountType ); + } + + + //----------------------------------------------------------------------------- + // Purpose: Constructor + // Input : unAccountID - 32-bit account ID + // unAccountInstance - instance + // eUniverse - Universe this account belongs to + // eAccountType - Type of account + //----------------------------------------------------------------------------- + CSteamID( uint32 unAccountID, unsigned int unAccountInstance, EUniverse eUniverse, EAccountType eAccountType ) + { +#if defined(_SERVER) && defined(Assert) + Assert( ! ( ( k_EAccountTypeIndividual == eAccountType ) && ( unAccountInstance > k_unSteamUserWebInstance ) ) ); // enforce that for individual accounts, instance is always 1 +#endif // _SERVER + InstancedSet( unAccountID, unAccountInstance, eUniverse, eAccountType ); + } + + + //----------------------------------------------------------------------------- + // Purpose: Constructor + // Input : ulSteamID - 64-bit representation of a Steam ID + // Note: Will not accept a uint32 or int32 as input, as that is a probable mistake. + // See the stubbed out overloads in the private: section for more info. + //----------------------------------------------------------------------------- + CSteamID( uint64 ulSteamID ) + { + SetFromUint64( ulSteamID ); + } + + + //----------------------------------------------------------------------------- + // Purpose: Sets parameters for steam ID + // Input : unAccountID - 32-bit account ID + // eUniverse - Universe this account belongs to + // eAccountType - Type of account + //----------------------------------------------------------------------------- + void Set( uint32 unAccountID, EUniverse eUniverse, EAccountType eAccountType ) + { + m_steamid.m_comp.m_unAccountID = unAccountID; + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_EAccountType = eAccountType; + + if ( eAccountType == k_EAccountTypeClan ) + { + m_steamid.m_comp.m_unAccountInstance = 0; + } + else + { + // by default we pick the desktop instance + m_steamid.m_comp.m_unAccountInstance = k_unSteamUserDesktopInstance; + } + } + + + //----------------------------------------------------------------------------- + // Purpose: Sets parameters for steam ID + // Input : unAccountID - 32-bit account ID + // eUniverse - Universe this account belongs to + // eAccountType - Type of account + //----------------------------------------------------------------------------- + void InstancedSet( uint32 unAccountID, uint32 unInstance, EUniverse eUniverse, EAccountType eAccountType ) + { + m_steamid.m_comp.m_unAccountID = unAccountID; + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_EAccountType = eAccountType; + m_steamid.m_comp.m_unAccountInstance = unInstance; + } + + + //----------------------------------------------------------------------------- + // Purpose: Initializes a steam ID from its 52 bit parts and universe/type + // Input : ulIdentifier - 52 bits of goodness + //----------------------------------------------------------------------------- + void FullSet( uint64 ulIdentifier, EUniverse eUniverse, EAccountType eAccountType ) + { + m_steamid.m_comp.m_unAccountID = ( ulIdentifier & k_unSteamAccountIDMask ); // account ID is low 32 bits + m_steamid.m_comp.m_unAccountInstance = ( ( ulIdentifier >> 32 ) & k_unSteamAccountInstanceMask ); // account instance is next 20 bits + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_EAccountType = eAccountType; + } + + + //----------------------------------------------------------------------------- + // Purpose: Initializes a steam ID from its 64-bit representation + // Input : ulSteamID - 64-bit representation of a Steam ID + //----------------------------------------------------------------------------- + void SetFromUint64( uint64 ulSteamID ) + { + m_steamid.m_unAll64Bits = ulSteamID; + } + + + //----------------------------------------------------------------------------- + // Purpose: Clear all fields, leaving an invalid ID. + //----------------------------------------------------------------------------- + void Clear() + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = k_EAccountTypeInvalid; + m_steamid.m_comp.m_EUniverse = k_EUniverseInvalid; + m_steamid.m_comp.m_unAccountInstance = 0; + } + + +#if defined( INCLUDED_STEAM_COMMON_STEAMCOMMON_H ) + //----------------------------------------------------------------------------- + // Purpose: Initializes a steam ID from a Steam2 ID structure + // Input: pTSteamGlobalUserID - Steam2 ID to convert + // eUniverse - universe this ID belongs to + //----------------------------------------------------------------------------- + void SetFromSteam2( TSteamGlobalUserID *pTSteamGlobalUserID, EUniverse eUniverse ) + { + m_steamid.m_comp.m_unAccountID = pTSteamGlobalUserID->m_SteamLocalUserID.Split.Low32bits * 2 + + pTSteamGlobalUserID->m_SteamLocalUserID.Split.High32bits; + m_steamid.m_comp.m_EUniverse = eUniverse; // set the universe + m_steamid.m_comp.m_EAccountType = k_EAccountTypeIndividual; // Steam 2 accounts always map to account type of individual + m_steamid.m_comp.m_unAccountInstance = k_unSteamUserDesktopInstance; // Steam2 only knew desktop instances + } + + //----------------------------------------------------------------------------- + // Purpose: Fills out a Steam2 ID structure + // Input: pTSteamGlobalUserID - Steam2 ID to write to + //----------------------------------------------------------------------------- + void ConvertToSteam2( TSteamGlobalUserID *pTSteamGlobalUserID ) const + { + // only individual accounts have any meaning in Steam 2, only they can be mapped + // Assert( m_steamid.m_comp.m_EAccountType == k_EAccountTypeIndividual ); + + pTSteamGlobalUserID->m_SteamInstanceID = 0; + pTSteamGlobalUserID->m_SteamLocalUserID.Split.High32bits = m_steamid.m_comp.m_unAccountID % 2; + pTSteamGlobalUserID->m_SteamLocalUserID.Split.Low32bits = m_steamid.m_comp.m_unAccountID / 2; + } +#endif // defined( INCLUDED_STEAM_COMMON_STEAMCOMMON_H ) + + //----------------------------------------------------------------------------- + // Purpose: Converts steam ID to its 64-bit representation + // Output : 64-bit representation of a Steam ID + //----------------------------------------------------------------------------- + uint64 ConvertToUint64() const + { + return m_steamid.m_unAll64Bits; + } + + + //----------------------------------------------------------------------------- + // Purpose: Converts the static parts of a steam ID to a 64-bit representation. + // For multiseat accounts, all instances of that account will have the + // same static account key, so they can be grouped together by the static + // account key. + // Output : 64-bit static account key + //----------------------------------------------------------------------------- + uint64 GetStaticAccountKey() const + { + // note we do NOT include the account instance (which is a dynamic property) in the static account key + return (uint64) ( ( ( (uint64) m_steamid.m_comp.m_EUniverse ) << 56 ) + ((uint64) m_steamid.m_comp.m_EAccountType << 52 ) + m_steamid.m_comp.m_unAccountID ); + } + + + //----------------------------------------------------------------------------- + // Purpose: create an anonymous game server login to be filled in by the AM + //----------------------------------------------------------------------------- + void CreateBlankAnonLogon( EUniverse eUniverse ) + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = k_EAccountTypeAnonGameServer; + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_unAccountInstance = 0; + } + + + //----------------------------------------------------------------------------- + // Purpose: create an anonymous game server login to be filled in by the AM + //----------------------------------------------------------------------------- + void CreateBlankAnonUserLogon( EUniverse eUniverse ) + { + m_steamid.m_comp.m_unAccountID = 0; + m_steamid.m_comp.m_EAccountType = k_EAccountTypeAnonUser; + m_steamid.m_comp.m_EUniverse = eUniverse; + m_steamid.m_comp.m_unAccountInstance = 0; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this an anonymous game server login that will be filled in? + //----------------------------------------------------------------------------- + bool BBlankAnonAccount() const + { + return m_steamid.m_comp.m_unAccountID == 0 && BAnonAccount() && m_steamid.m_comp.m_unAccountInstance == 0; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a game server account id? (Either persistent or anonymous) + //----------------------------------------------------------------------------- + bool BGameServerAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeGameServer || m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonGameServer; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a persistent (not anonymous) game server account id? + //----------------------------------------------------------------------------- + bool BPersistentGameServerAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeGameServer; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this an anonymous game server account id? + //----------------------------------------------------------------------------- + bool BAnonGameServerAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonGameServer; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a content server account id? + //----------------------------------------------------------------------------- + bool BContentServerAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeContentServer; + } + + + //----------------------------------------------------------------------------- + // Purpose: Is this a clan account id? + //----------------------------------------------------------------------------- + bool BClanAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeClan; + } + + + //----------------------------------------------------------------------------- + // Purpose: Is this a chat account id? + //----------------------------------------------------------------------------- + bool BChatAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeChat; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a chat account id? + //----------------------------------------------------------------------------- + bool IsLobby() const + { + return ( m_steamid.m_comp.m_EAccountType == k_EAccountTypeChat ) + && ( m_steamid.m_comp.m_unAccountInstance & k_EChatInstanceFlagLobby ); + } + + + //----------------------------------------------------------------------------- + // Purpose: Is this an individual user account id? + //----------------------------------------------------------------------------- + bool BIndividualAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeIndividual || m_steamid.m_comp.m_EAccountType == k_EAccountTypeConsoleUser; + } + + + //----------------------------------------------------------------------------- + // Purpose: Is this an anonymous account? + //----------------------------------------------------------------------------- + bool BAnonAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonUser || m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonGameServer; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this an anonymous user account? ( used to create an account or reset a password ) + //----------------------------------------------------------------------------- + bool BAnonUserAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeAnonUser; + } + + //----------------------------------------------------------------------------- + // Purpose: Is this a faked up Steam ID for a PSN friend account? + //----------------------------------------------------------------------------- + bool BConsoleUserAccount() const + { + return m_steamid.m_comp.m_EAccountType == k_EAccountTypeConsoleUser; + } + + // simple accessors + void SetAccountID( uint32 unAccountID ) { m_steamid.m_comp.m_unAccountID = unAccountID; } + void SetAccountInstance( uint32 unInstance ){ m_steamid.m_comp.m_unAccountInstance = unInstance; } + void ClearIndividualInstance() { if ( BIndividualAccount() ) m_steamid.m_comp.m_unAccountInstance = 0; } + bool HasNoIndividualInstance() const { return BIndividualAccount() && (m_steamid.m_comp.m_unAccountInstance==0); } + AccountID_t GetAccountID() const { return m_steamid.m_comp.m_unAccountID; } + uint32 GetUnAccountInstance() const { return m_steamid.m_comp.m_unAccountInstance; } + EAccountType GetEAccountType() const { return ( EAccountType ) m_steamid.m_comp.m_EAccountType; } + EUniverse GetEUniverse() const { return m_steamid.m_comp.m_EUniverse; } + void SetEUniverse( EUniverse eUniverse ) { m_steamid.m_comp.m_EUniverse = eUniverse; } + bool IsValid() const; + + // this set of functions is hidden, will be moved out of class + explicit CSteamID( const char *pchSteamID, EUniverse eDefaultUniverse = k_EUniverseInvalid ); + const char * Render() const; // renders this steam ID to string + static const char * Render( uint64 ulSteamID ); // static method to render a uint64 representation of a steam ID to a string + + void SetFromString( const char *pchSteamID, EUniverse eDefaultUniverse ); + // SetFromString allows many partially-correct strings, constraining how + // we might be able to change things in the future. + // SetFromStringStrict requires the exact string forms that we support + // and is preferred when the caller knows it's safe to be strict. + // Returns whether the string parsed correctly. + bool SetFromStringStrict( const char *pchSteamID, EUniverse eDefaultUniverse ); + bool SetFromSteam2String( const char *pchSteam2ID, EUniverse eUniverse ); + + inline bool operator==( const CSteamID &val ) const { return m_steamid.m_unAll64Bits == val.m_steamid.m_unAll64Bits; } + inline bool operator!=( const CSteamID &val ) const { return !operator==( val ); } + inline bool operator<( const CSteamID &val ) const { return m_steamid.m_unAll64Bits < val.m_steamid.m_unAll64Bits; } + inline bool operator>( const CSteamID &val ) const { return m_steamid.m_unAll64Bits > val.m_steamid.m_unAll64Bits; } + + // DEBUG function + bool BValidExternalSteamID() const; + +private: + // These are defined here to prevent accidental implicit conversion of a u32AccountID to a CSteamID. + // If you get a compiler error about an ambiguous constructor/function then it may be because you're + // passing a 32-bit int to a function that takes a CSteamID. You should explicitly create the SteamID + // using the correct Universe and account Type/Instance values. + CSteamID( uint32 ); + CSteamID( int32 ); + + // 64 bits total + union SteamID_t + { + struct SteamIDComponent_t + { +#ifdef VALVE_BIG_ENDIAN + EUniverse m_EUniverse : 8; // universe this account belongs to + unsigned int m_EAccountType : 4; // type of account - can't show as EAccountType, due to signed / unsigned difference + unsigned int m_unAccountInstance : 20; // dynamic instance ID + uint32 m_unAccountID : 32; // unique account identifier +#else + uint32 m_unAccountID : 32; // unique account identifier + unsigned int m_unAccountInstance : 20; // dynamic instance ID + unsigned int m_EAccountType : 4; // type of account - can't show as EAccountType, due to signed / unsigned difference + EUniverse m_EUniverse : 8; // universe this account belongs to +#endif + } m_comp; + + uint64 m_unAll64Bits; + } m_steamid; +}; + +inline bool CSteamID::IsValid() const +{ + if ( m_steamid.m_comp.m_EAccountType <= k_EAccountTypeInvalid || m_steamid.m_comp.m_EAccountType >= k_EAccountTypeMax ) + return false; + + if ( m_steamid.m_comp.m_EUniverse <= k_EUniverseInvalid || m_steamid.m_comp.m_EUniverse >= k_EUniverseMax ) + return false; + + if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypeIndividual ) + { + if ( m_steamid.m_comp.m_unAccountID == 0 || m_steamid.m_comp.m_unAccountInstance > k_unSteamUserWebInstance ) + return false; + } + + if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypeClan ) + { + if ( m_steamid.m_comp.m_unAccountID == 0 || m_steamid.m_comp.m_unAccountInstance != 0 ) + return false; + } + + if ( m_steamid.m_comp.m_EAccountType == k_EAccountTypeGameServer ) + { + if ( m_steamid.m_comp.m_unAccountID == 0 ) + return false; + // Any limit on instances? We use them for local users and bots + } + return true; +} + +// generic invalid CSteamID +#define k_steamIDNil CSteamID() + +// This steamID comes from a user game connection to an out of date GS that hasnt implemented the protocol +// to provide its steamID +#define k_steamIDOutofDateGS CSteamID( 0, 0, k_EUniverseInvalid, k_EAccountTypeInvalid ) +// This steamID comes from a user game connection to an sv_lan GS +#define k_steamIDLanModeGS CSteamID( 0, 0, k_EUniversePublic, k_EAccountTypeInvalid ) +// This steamID can come from a user game connection to a GS that has just booted but hasnt yet even initialized +// its steam3 component and started logging on. +#define k_steamIDNotInitYetGS CSteamID( 1, 0, k_EUniverseInvalid, k_EAccountTypeInvalid ) +// This steamID can come from a user game connection to a GS that isn't using the steam authentication system but still +// wants to support the "Join Game" option in the friends list +#define k_steamIDNonSteamGS CSteamID( 2, 0, k_EUniverseInvalid, k_EAccountTypeInvalid ) + + +#ifdef STEAM +// Returns the matching chat steamID, with the default instance of 0 +// If the steamID passed in is already of type k_EAccountTypeChat it will be returned with the same instance +CSteamID ChatIDFromSteamID( const CSteamID &steamID ); +// Returns the matching clan steamID, with the default instance of 0 +// If the steamID passed in is already of type k_EAccountTypeClan it will be returned with the same instance +CSteamID ClanIDFromSteamID( const CSteamID &steamID ); +// Asserts steamID type before conversion +CSteamID ChatIDFromClanID( const CSteamID &steamIDClan ); +// Asserts steamID type before conversion +CSteamID ClanIDFromChatID( const CSteamID &steamIDChat ); + +#endif // _STEAM + + +//----------------------------------------------------------------------------- +// Purpose: encapsulates an appID/modID pair +//----------------------------------------------------------------------------- +class CGameID +{ +public: + + CGameID() + { + m_gameID.m_nType = k_EGameIDTypeApp; + m_gameID.m_nAppID = k_uAppIdInvalid; + m_gameID.m_nModID = 0; + } + + explicit CGameID( uint64 ulGameID ) + { + m_ulGameID = ulGameID; + } + + explicit CGameID( int32 nAppID ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = nAppID; + } + + explicit CGameID( uint32 nAppID ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = nAppID; + } + + CGameID( uint32 nAppID, uint32 nModID ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = nAppID; + m_gameID.m_nModID = nModID; + m_gameID.m_nType = k_EGameIDTypeGameMod; + } + + // Hidden functions used only by Steam + explicit CGameID( const char *pchGameID ); + const char *Render() const; // render this Game ID to string + static const char *Render( uint64 ulGameID ); // static method to render a uint64 representation of a Game ID to a string + + // must include checksum_crc.h first to get this functionality +#if defined( CHECKSUM_CRC_H ) + CGameID( uint32 nAppID, const char *pchModPath ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = nAppID; + m_gameID.m_nType = k_EGameIDTypeGameMod; + + char rgchModDir[MAX_PATH]; + Q_FileBase( pchModPath, rgchModDir, sizeof( rgchModDir ) ); + CRC32_t crc32; + CRC32_Init( &crc32 ); + CRC32_ProcessBuffer( &crc32, rgchModDir, Q_strlen( rgchModDir ) ); + CRC32_Final( &crc32 ); + + // set the high-bit on the mod-id + // reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique + // replacement for appID's + m_gameID.m_nModID = crc32 | (0x80000000); + } + + CGameID( const char *pchExePath, const char *pchAppName ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = k_uAppIdInvalid; + m_gameID.m_nType = k_EGameIDTypeShortcut; + + CRC32_t crc32; + CRC32_Init( &crc32 ); + CRC32_ProcessBuffer( &crc32, pchExePath, Q_strlen( pchExePath ) ); + CRC32_ProcessBuffer( &crc32, pchAppName, Q_strlen( pchAppName ) ); + CRC32_Final( &crc32 ); + + // set the high-bit on the mod-id + // reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique + // replacement for appID's + m_gameID.m_nModID = crc32 | (0x80000000); + } + +#if defined( VSTFILEID_H ) + + CGameID( VstFileID vstFileID ) + { + m_ulGameID = 0; + m_gameID.m_nAppID = k_uAppIdInvalid; + m_gameID.m_nType = k_EGameIDTypeP2P; + + CRC32_t crc32; + CRC32_Init( &crc32 ); + const char *pchFileId = vstFileID.Render(); + CRC32_ProcessBuffer( &crc32, pchFileId, Q_strlen( pchFileId ) ); + CRC32_Final( &crc32 ); + + // set the high-bit on the mod-id + // reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique + // replacement for appID's + m_gameID.m_nModID = crc32 | (0x80000000); + } + +#endif /* VSTFILEID_H */ + +#endif /* CHECKSUM_CRC_H */ + + + uint64 ToUint64() const + { + return m_ulGameID; + } + + uint64 *GetUint64Ptr() + { + return &m_ulGameID; + } + + void Set( uint64 ulGameID ) + { + m_ulGameID = ulGameID; + } + + bool IsMod() const + { + return ( m_gameID.m_nType == k_EGameIDTypeGameMod ); + } + + bool IsShortcut() const + { + return ( m_gameID.m_nType == k_EGameIDTypeShortcut ); + } + + bool IsP2PFile() const + { + return ( m_gameID.m_nType == k_EGameIDTypeP2P ); + } + + bool IsSteamApp() const + { + return ( m_gameID.m_nType == k_EGameIDTypeApp ); + } + + uint32 ModID() const + { + return m_gameID.m_nModID; + } + + uint32 AppID() const + { + return m_gameID.m_nAppID; + } + + bool operator == ( const CGameID &rhs ) const + { + return m_ulGameID == rhs.m_ulGameID; + } + + bool operator != ( const CGameID &rhs ) const + { + return !(*this == rhs); + } + + bool operator < ( const CGameID &rhs ) const + { + return ( m_ulGameID < rhs.m_ulGameID ); + } + + bool IsValid() const + { + // each type has it's own invalid fixed point: + switch( m_gameID.m_nType ) + { + case k_EGameIDTypeApp: + return m_gameID.m_nAppID != k_uAppIdInvalid; + + case k_EGameIDTypeGameMod: + return m_gameID.m_nAppID != k_uAppIdInvalid && m_gameID.m_nModID & 0x80000000; + + case k_EGameIDTypeShortcut: + return (m_gameID.m_nModID & 0x80000000) != 0; + + case k_EGameIDTypeP2P: + return m_gameID.m_nAppID == k_uAppIdInvalid && m_gameID.m_nModID & 0x80000000; + + default: +#if defined(Assert) + Assert(false); +#endif + return false; + } + + } + + void Reset() + { + m_ulGameID = 0; + } + + + +private: + + enum EGameIDType + { + k_EGameIDTypeApp = 0, + k_EGameIDTypeGameMod = 1, + k_EGameIDTypeShortcut = 2, + k_EGameIDTypeP2P = 3, + }; + + struct GameID_t + { +#ifdef VALVE_BIG_ENDIAN + unsigned int m_nModID : 32; + unsigned int m_nType : 8; + unsigned int m_nAppID : 24; +#else + unsigned int m_nAppID : 24; + unsigned int m_nType : 8; + unsigned int m_nModID : 32; +#endif + }; + + union + { + uint64 m_ulGameID; + GameID_t m_gameID; + }; +}; + +#pragma pack( pop ) + +const int k_cchGameExtraInfoMax = 64; + + +//----------------------------------------------------------------------------- +// Constants used for query ports. +//----------------------------------------------------------------------------- + +#define QUERY_PORT_NOT_INITIALIZED 0xFFFF // We haven't asked the GS for this query port's actual value yet. +#define QUERY_PORT_ERROR 0xFFFE // We were unable to get the query port for this server. + + +//----------------------------------------------------------------------------- +// Purpose: Passed as argument to SteamAPI_UseBreakpadCrashHandler to enable optional callback +// just before minidump file is captured after a crash has occurred. (Allows app to append additional comment data to the dump, etc.) +//----------------------------------------------------------------------------- +typedef void (*PFNPreMinidumpCallback)(void *context); + +//----------------------------------------------------------------------------- +// Purpose: Used by ICrashHandler interfaces to reference particular installed crash handlers +//----------------------------------------------------------------------------- +typedef void *BREAKPAD_HANDLE; +#define BREAKPAD_INVALID_HANDLE (BREAKPAD_HANDLE)0 + +#endif // STEAMCLIENTPUBLIC_H diff --git a/rehlds/public/steam/steamhttpenums.h b/rehlds/public/steam/steamhttpenums.h new file mode 100644 index 0000000..d43d33d --- /dev/null +++ b/rehlds/public/steam/steamhttpenums.h @@ -0,0 +1,94 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: HTTP related enums, stuff that is shared by both clients and servers, and our +// UI projects goes here. +// +//============================================================================= + +#ifndef STEAMHTTPENUMS_H +#define STEAMHTTPENUMS_H +#ifdef _WIN32 +#pragma once +#endif + +// HTTP related types + +// This enum is used in client API methods, do not re-number existing values. +enum EHTTPMethod +{ + k_EHTTPMethodInvalid = 0, + k_EHTTPMethodGET, + k_EHTTPMethodHEAD, + k_EHTTPMethodPOST, + + // The remaining HTTP methods are not yet supported, per rfc2616 section 5.1.1 only GET and HEAD are required for + // a compliant general purpose server. We'll likely add more as we find uses for them. + + // k_EHTTPMethodOPTIONS, + k_EHTTPMethodPUT, + k_EHTTPMethodDELETE, + // k_EHTTPMethodTRACE, + // k_EHTTPMethodCONNECT +}; + + +// HTTP Status codes that the server can send in response to a request, see rfc2616 section 10.3 for descriptions +// of each of these. +enum EHTTPStatusCode +{ + // Invalid status code (this isn't defined in HTTP, used to indicate unset in our code) + k_EHTTPStatusCodeInvalid = 0, + + // Informational codes + k_EHTTPStatusCode100Continue = 100, + k_EHTTPStatusCode101SwitchingProtocols = 101, + + // Success codes + k_EHTTPStatusCode200OK = 200, + k_EHTTPStatusCode201Created = 201, + k_EHTTPStatusCode202Accepted = 202, + k_EHTTPStatusCode203NonAuthoritative = 203, + k_EHTTPStatusCode204NoContent = 204, + k_EHTTPStatusCode205ResetContent = 205, + k_EHTTPStatusCode206PartialContent = 206, + + // Redirection codes + k_EHTTPStatusCode300MultipleChoices = 300, + k_EHTTPStatusCode301MovedPermanently = 301, + k_EHTTPStatusCode302Found = 302, + k_EHTTPStatusCode303SeeOther = 303, + k_EHTTPStatusCode304NotModified = 304, + k_EHTTPStatusCode305UseProxy = 305, + //k_EHTTPStatusCode306Unused = 306, (used in old HTTP spec, now unused in 1.1) + k_EHTTPStatusCode307TemporaryRedirect = 307, + + // Error codes + k_EHTTPStatusCode400BadRequest = 400, + k_EHTTPStatusCode401Unauthorized = 401, + k_EHTTPStatusCode402PaymentRequired = 402, // This is reserved for future HTTP specs, not really supported by clients + k_EHTTPStatusCode403Forbidden = 403, + k_EHTTPStatusCode404NotFound = 404, + k_EHTTPStatusCode405MethodNotAllowed = 405, + k_EHTTPStatusCode406NotAcceptable = 406, + k_EHTTPStatusCode407ProxyAuthRequired = 407, + k_EHTTPStatusCode408RequestTimeout = 408, + k_EHTTPStatusCode409Conflict = 409, + k_EHTTPStatusCode410Gone = 410, + k_EHTTPStatusCode411LengthRequired = 411, + k_EHTTPStatusCode412PreconditionFailed = 412, + k_EHTTPStatusCode413RequestEntityTooLarge = 413, + k_EHTTPStatusCode414RequestURITooLong = 414, + k_EHTTPStatusCode415UnsupportedMediaType = 415, + k_EHTTPStatusCode416RequestedRangeNotSatisfiable = 416, + k_EHTTPStatusCode417ExpectationFailed = 417, + + // Server error codes + k_EHTTPStatusCode500InternalServerError = 500, + k_EHTTPStatusCode501NotImplemented = 501, + k_EHTTPStatusCode502BadGateway = 502, + k_EHTTPStatusCode503ServiceUnavailable = 503, + k_EHTTPStatusCode504GatewayTimeout = 504, + k_EHTTPStatusCode505HTTPVersionNotSupported = 505, +}; + +#endif // STEAMHTTPENUMS_H \ No newline at end of file diff --git a/rehlds/public/steam/steamtypes.h b/rehlds/public/steam/steamtypes.h new file mode 100644 index 0000000..6b6bc26 --- /dev/null +++ b/rehlds/public/steam/steamtypes.h @@ -0,0 +1,136 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#ifndef STEAMTYPES_H +#define STEAMTYPES_H +#ifdef _WIN32 +#pragma once +#endif + +// Steam-specific types. Defined here so this header file can be included in other code bases. +#ifndef WCHARTYPES_H +typedef unsigned char uint8; +#endif + +#if defined( __GNUC__ ) && !defined(POSIX) + #if __GNUC__ < 4 + #error "Steamworks requires GCC 4.X (4.2 or 4.4 have been tested)" + #endif + #define POSIX 1 +#endif + +#if defined(__x86_64__) || defined(_WIN64) +#define X64BITS +#endif + +// Make sure VALVE_BIG_ENDIAN gets set on PS3, may already be set previously in Valve internal code. +#if !defined(VALVE_BIG_ENDIAN) && defined(_PS3) +#define VALVE_BIG_ENDIAN +#endif + +typedef unsigned char uint8; +typedef signed char int8; + +#if defined( _WIN32 ) + +typedef __int16 int16; +typedef unsigned __int16 uint16; +typedef __int32 int32; +typedef unsigned __int32 uint32; +typedef __int64 int64; +typedef unsigned __int64 uint64; + +#ifdef X64BITS +typedef __int64 intp; // intp is an integer that can accomodate a pointer +typedef unsigned __int64 uintp; // (ie, sizeof(intp) >= sizeof(int) && sizeof(intp) >= sizeof(void *) +#else +typedef __int32 intp; +typedef unsigned __int32 uintp; +#endif + +#else // _WIN32 + +typedef short int16; +typedef unsigned short uint16; +typedef int int32; +typedef unsigned int uint32; +typedef long long int64; +typedef unsigned long long uint64; +#ifdef X64BITS +typedef long long intp; +typedef unsigned long long uintp; +#else +typedef int intp; +typedef unsigned int uintp; +#endif + +#endif // else _WIN32 + +const int k_cubSaltSize = 8; +typedef uint8 Salt_t[ k_cubSaltSize ]; + +//----------------------------------------------------------------------------- +// GID (GlobalID) stuff +// This is a globally unique identifier. It's guaranteed to be unique across all +// racks and servers for as long as a given universe persists. +//----------------------------------------------------------------------------- +// NOTE: for GID parsing/rendering and other utils, see gid.h +typedef uint64 GID_t; + +const GID_t k_GIDNil = 0xffffffffffffffffull; + +// For convenience, we define a number of types that are just new names for GIDs +typedef GID_t JobID_t; // Each Job has a unique ID +typedef GID_t TxnID_t; // Each financial transaction has a unique ID + +const GID_t k_TxnIDNil = k_GIDNil; +const GID_t k_TxnIDUnknown = 0; + + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. +typedef uint32 PackageId_t; +const PackageId_t k_uPackageIdFreeSub = 0x0; +const PackageId_t k_uPackageIdInvalid = 0xFFFFFFFF; + + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. +typedef uint32 AppId_t; +const AppId_t k_uAppIdInvalid = 0x0; + +typedef uint64 AssetClassId_t; +const AssetClassId_t k_ulAssetClassIdInvalid = 0x0; + +typedef uint32 PhysicalItemId_t; +const PhysicalItemId_t k_uPhysicalItemIdInvalid = 0x0; + + +// this is baked into client messages and interfaces as an int, +// make sure we never break this. AppIds and DepotIDs also presently +// share the same namespace, but since we'd like to change that in the future +// I've defined it seperately here. +typedef uint32 DepotId_t; +const DepotId_t k_uDepotIdInvalid = 0x0; + +// RTime32 +// We use this 32 bit time representing real world time. +// It offers 1 second resolution beginning on January 1, 1970 (Unix time) +typedef uint32 RTime32; + +typedef uint32 CellID_t; +const CellID_t k_uCellIDInvalid = 0xFFFFFFFF; + +// handle to a Steam API call +typedef uint64 SteamAPICall_t; +const SteamAPICall_t k_uAPICallInvalid = 0x0; + +typedef uint32 AccountID_t; + +typedef uint32 PartnerId_t; +const PartnerId_t k_uPartnerIdInvalid = 0; + +#endif // STEAMTYPES_H diff --git a/rehlds/public/steamid.cpp b/rehlds/public/steamid.cpp new file mode 100644 index 0000000..0b0be2a --- /dev/null +++ b/rehlds/public/steamid.cpp @@ -0,0 +1,32 @@ +#include "precompiled.h" + +bool CSteamID::SetFromSteam2String(const char *pchSteam2ID, EUniverse eUniverse) +{ + Assert(pchSteam2ID); + + // Convert the Steam2 ID string to a Steam2 ID structure + TSteamGlobalUserID steam2ID; + steam2ID.m_SteamInstanceID = 0; + steam2ID.m_SteamLocalUserID.Split.High32bits = 0; + steam2ID.m_SteamLocalUserID.Split.Low32bits = 0; + + const char *pchTSteam2ID = pchSteam2ID; + + // Customer support is fond of entering steam IDs in the following form: STEAM_n:x:y + char *pchOptionalLeadString = "STEAM_"; + if (Q_strnicmp(pchSteam2ID, pchOptionalLeadString, Q_strlen(pchOptionalLeadString)) == 0) + pchTSteam2ID = pchSteam2ID + Q_strlen(pchOptionalLeadString); + + char cExtraCharCheck = 0; + + int cFieldConverted = sscanf(pchTSteam2ID, "%hu:%u:%u%c", &steam2ID.m_SteamInstanceID, + &steam2ID.m_SteamLocalUserID.Split.High32bits, &steam2ID.m_SteamLocalUserID.Split.Low32bits, &cExtraCharCheck); + + // Validate the conversion ... a special case is steam2 instance ID 1 which is reserved for special DoD handling + if (cExtraCharCheck != 0 || cFieldConverted == EOF || cFieldConverted < 2 || (cFieldConverted < 3 && steam2ID.m_SteamInstanceID != 1)) + return false; + + // Now convert to steam ID from the Steam2 ID structure + SetFromSteam2(&steam2ID, eUniverse); + return true; +} diff --git a/rehlds/public/string_t.h b/rehlds/public/string_t.h new file mode 100644 index 0000000..385dc19 --- /dev/null +++ b/rehlds/public/string_t.h @@ -0,0 +1,106 @@ +//========= Copyright (c) 1996-2002, Valve LLC, All rights reserved. ========== +// +// Purpose: Defines the more complete set of operations on the string_t defined +// These should be used instead of direct manipulation to allow more +// flexibility in future ports or optimization. +// +// $NoKeywords: $ +//============================================================================= + +#ifndef STRING_T_H +#define STRING_T_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "osconfig.h" +#include + +#ifndef NO_STRING_T + +#ifdef WEAK_STRING_T + +typedef int valve_string_t; + +//----------------------------------------------------------------------------- +// Purpose: The correct way to specify the NULL string as a constant. +//----------------------------------------------------------------------------- + +#define NULL_STRING 0 + +//----------------------------------------------------------------------------- +// Purpose: Given a string_t, make a C string. By convention the result string +// pointer should be considered transient and should not be stored. +//----------------------------------------------------------------------------- + +#define STRING( offset ) ( ( offset ) ? reinterpret_cast( offset ) : "" ) + +//----------------------------------------------------------------------------- +// Purpose: Given a C string, obtain a string_t +//----------------------------------------------------------------------------- + +#define MAKE_STRING( str ) ( ( *str != 0 ) ? reinterpret_cast( str ) : 0 ) + +//----------------------------------------------------------------------------- + +#else // Strong string_t + +//----------------------------------------------------------------------------- + +struct valve_string_t +{ +public: + bool operator!() const { return (pszValue == NULL); } + bool operator==(const valve_string_t &rhs) const { return (pszValue == rhs.pszValue); } + bool operator!=(const valve_string_t &rhs) const { return (pszValue != rhs.pszValue); } + + const char *ToCStr() const { return (pszValue) ? pszValue : ""; } + +protected: + const char *pszValue; +}; + +//----------------------------------------------------------------------------- + +struct castable_string_t : public valve_string_t // string_t is used in unions, hence, no constructor allowed +{ + castable_string_t() { pszValue = NULL; } + castable_string_t(const char *pszFrom) { pszValue = (*pszFrom != 0) ? pszFrom : 0; } +}; + +//----------------------------------------------------------------------------- +// Purpose: The correct way to specify the NULL string as a constant. +//----------------------------------------------------------------------------- + +#define NULL_STRING castable_string_t() + +//----------------------------------------------------------------------------- +// Purpose: Given a string_t, make a C string. By convention the result string +// pointer should be considered transient and should not be stored. +//----------------------------------------------------------------------------- + +#define STRING( string_t_obj ) (string_t_obj).ToCStr() + +//----------------------------------------------------------------------------- +// Purpose: Given a C string, obtain a string_t +//----------------------------------------------------------------------------- + +#define MAKE_STRING( c_str ) castable_string_t( c_str ) + +//----------------------------------------------------------------------------- + +#endif + +#else // NO_STRING_T + +typedef const char *string_t; +#define NULL_STRING 0 +#define STRING( c_str ) ( c_str ) +#define MAKE_STRING( c_str ) ( c_str ) + +#endif // NO_STRING_T + +//============================================================================= + +#endif // STRING_T_H diff --git a/rehlds/public/tier0/dbg.cpp b/rehlds/public/tier0/dbg.cpp new file mode 100644 index 0000000..3dfc222 --- /dev/null +++ b/rehlds/public/tier0/dbg.cpp @@ -0,0 +1,435 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// The main debug library implementation +//============================================================================= + +#include "precompiled.h" + +//----------------------------------------------------------------------------- +// internal structures +//----------------------------------------------------------------------------- + +enum +{ + MAX_GROUP_NAME_LENGTH = 48 +}; + +struct SpewGroup_t +{ + char m_GroupName[MAX_GROUP_NAME_LENGTH]; + int m_Level; +}; + + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +void _AssertValidReadPtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!IsBadReadPtr(ptr, count)); +#else + Assert(ptr); +#endif + +} + +void _AssertValidWritePtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!IsBadWritePtr(ptr, count)); +#else + Assert(ptr); +#endif +} + +void _AssertValidReadWritePtr(void* ptr, int count/* = 1*/) +{ +#ifdef _WIN32 + Assert(!(IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr, count))); +#else + Assert(ptr); +#endif +} + +void AssertValidStringPtr(const char* ptr, int maxchar/* = 0xFFFFFF */) +{ +#ifdef _WIN32 + Assert(!IsBadStringPtr(ptr, maxchar)); +#else + Assert(ptr); +#endif +} + + +//----------------------------------------------------------------------------- +// globals +//----------------------------------------------------------------------------- + +SpewRetval_t DefaultSpewFunc(SpewType_t type, char const *pMsg) +{ + printf("%s", pMsg); + if (type == SPEW_ASSERT) + return SPEW_DEBUGGER; + else if (type == SPEW_ERROR) + return SPEW_ABORT; + else + return SPEW_CONTINUE; +} + +static SpewOutputFunc_t s_SpewOutputFunc = DefaultSpewFunc; + +static char const* s_pFileName; +static int s_Line; +static SpewType_t s_SpewType; + +static SpewGroup_t* s_pSpewGroups = 0; +static int s_GroupCount = 0; +static int s_DefaultLevel = 0; + + + +//----------------------------------------------------------------------------- +// Spew output management. +//----------------------------------------------------------------------------- + +void SpewOutputFunc(SpewOutputFunc_t func) +{ + s_SpewOutputFunc = func ? func : DefaultSpewFunc; +} + +SpewOutputFunc_t GetSpewOutputFunc(void) +{ + if (s_SpewOutputFunc) + { + return s_SpewOutputFunc; + } + else + { + return DefaultSpewFunc; + } +} + +//----------------------------------------------------------------------------- +// Spew functions +//----------------------------------------------------------------------------- + +void _SpewInfo(SpewType_t type, char const* pFile, int line) +{ + // Only grab the file name. Ignore the path. + char const* pSlash = strrchr(pFile, '\\'); + char const* pSlash2 = strrchr(pFile, '/'); + if (pSlash < pSlash2) pSlash = pSlash2; + + s_pFileName = pSlash ? pSlash + 1 : pFile; + s_Line = line; + s_SpewType = type; +} + +SpewRetval_t _SpewMessage(SpewType_t spewType, char const* pMsgFormat, va_list args) +{ + char pTempBuffer[1024]; + + /* Printf the file and line for warning + assert only... */ + int len = 0; + if ((spewType == SPEW_ASSERT)) + { + len = sprintf(pTempBuffer, "%s (%d) : ", s_pFileName, s_Line); + } + + /* Create the message.... */ + len += vsprintf(&pTempBuffer[len], pMsgFormat, args); + + // Add \n for warning and assert + if ((spewType == SPEW_ASSERT)) + { + len += sprintf(&pTempBuffer[len], "\n"); + } + + assert(len < 1024); /* use normal assert here; to avoid recursion. */ + assert(s_SpewOutputFunc); + + /* direct it to the appropriate target(s) */ + SpewRetval_t ret = s_SpewOutputFunc(spewType, pTempBuffer); + switch (ret) + { + // Put the break into the macro so it would occur in the right place + // case SPEW_DEBUGGER: + // DebuggerBreak(); + // break; + + case SPEW_ABORT: + // MessageBox(NULL,"Error in _SpewMessage","Error",MB_OK); + exit(0); + default: + break; + } + + return ret; +} + +SpewRetval_t _SpewMessage(char const* pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); + va_end(args); + return ret; +} + +SpewRetval_t _DSpewMessage(char const *pGroupName, int level, char const* pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return SPEW_CONTINUE; + + va_list args; + va_start(args, pMsgFormat); + SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); + va_end(args); + return ret; +} + +void Msg(char const* pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DMsg(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void Warning(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DWarning(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void Log(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void DLog(char const *pGroupName, int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive(pGroupName, level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void Error(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_ERROR, pMsgFormat, args); + va_end(args); +} + + +//----------------------------------------------------------------------------- +// A couple of super-common dynamic spew messages, here for convenience +// These looked at the "developer" group, print if it's level 1 or higher +//----------------------------------------------------------------------------- + +void DevMsg(int level, char const* pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DevWarning(int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DevLog(int level, char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", level)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +void DevMsg(char const *pMsgFormat, ...) +{ + if (!IsSpewActive("developer", 1)) + return; + + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); + va_end(args); +} + +void DevWarning(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_WARNING, pMsgFormat, args); + va_end(args); +} + +void DevLog(char const *pMsgFormat, ...) +{ + va_list args; + va_start(args, pMsgFormat); + _SpewMessage(SPEW_LOG, pMsgFormat, args); + va_end(args); +} + +//----------------------------------------------------------------------------- +// Find a group, return true if found, false if not. Return in ind the +// index of the found group, or the index of the group right before where the +// group should be inserted into the list to maintain sorted order. +//----------------------------------------------------------------------------- + +bool FindSpewGroup(char const* pGroupName, int* pInd) +{ + int s = 0; + if (s_GroupCount) + { + int e = (int)(s_GroupCount - 1); + while (s <= e) + { + int m = (s + e) >> 1; + int cmp = Q_stricmp(pGroupName, s_pSpewGroups[m].m_GroupName); + if (!cmp) + { + *pInd = m; + return true; + } + if (cmp < 0) + e = m - 1; + else + s = m + 1; + } + } + *pInd = s; + return false; +} + + +//----------------------------------------------------------------------------- +// Sets the priority level for a spew group +//----------------------------------------------------------------------------- + +void SpewActivate(char const* pGroupName, int level) +{ + Assert(pGroupName); + + // check for the default group first... + if ((pGroupName[0] == '*') && (pGroupName[1] == '\0')) + { + s_DefaultLevel = level; + return; + } + + // Normal case, search in group list using binary search. + // If not found, grow the list of groups and insert it into the + // right place to maintain sorted order. Then set the level. + int ind; + if (!FindSpewGroup(pGroupName, &ind)) + { + // not defined yet, insert an entry. + ++s_GroupCount; + if (s_pSpewGroups) + { + s_pSpewGroups = (SpewGroup_t*)realloc(s_pSpewGroups, + s_GroupCount * sizeof(SpewGroup_t)); + + // shift elements down to preserve order + int numToMove = s_GroupCount - ind - 1; + memmove(&s_pSpewGroups[ind + 1], &s_pSpewGroups[ind], + numToMove * sizeof(SpewGroup_t)); + } + else + s_pSpewGroups = (SpewGroup_t*)malloc(s_GroupCount * sizeof(SpewGroup_t)); + + Assert(strlen(pGroupName) < MAX_GROUP_NAME_LENGTH); + strcpy(s_pSpewGroups[ind].m_GroupName, pGroupName); + } + s_pSpewGroups[ind].m_Level = level; +} + + +//----------------------------------------------------------------------------- +// Tests to see if a particular spew is active +//----------------------------------------------------------------------------- + +bool IsSpewActive(char const* pGroupName, int level) +{ + // If we don't find the spew group, use the default level. + int ind; + if (FindSpewGroup(pGroupName, &ind)) + return s_pSpewGroups[ind].m_Level >= level; + else + return s_DefaultLevel >= level; +} + + +// If we don't have a function from math.h, then it doesn't link certain floating-point +// functions in and printfs with %f cause runtime errors in the C libraries. +float CrackSmokingCompiler(float a) +{ + return fabs(a); +} + +void* Plat_SimpleLog(const char* file, int line) +{ + FILE* f = fopen("simple.log", "at+"); + fprintf(f, "%s:%i\n", file, line); + fclose(f); + + return NULL; +} \ No newline at end of file diff --git a/rehlds/public/tier0/dbg.h b/rehlds/public/tier0/dbg.h new file mode 100644 index 0000000..3a7cd99 --- /dev/null +++ b/rehlds/public/tier0/dbg.h @@ -0,0 +1,453 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// The main debug library interfaces +//============================================================================= + + +#ifndef DBG_H +#define DBG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "basetypes.h" +#include "tier0/platform.h" +#include +#include +#include + + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- + +#ifdef TIER0_DLL_EXPORT +#define DBG_INTERFACE DLL_EXPORT +#define DBG_OVERLOAD DLL_GLOBAL_EXPORT +#define DBG_CLASS DLL_CLASS_EXPORT +#else +#define DBG_INTERFACE DLL_IMPORT +#define DBG_OVERLOAD DLL_GLOBAL_IMPORT +#define DBG_CLASS DLL_CLASS_IMPORT +#endif + + +//----------------------------------------------------------------------------- +// Usage model for the Dbg library +// +// 1. Spew. +// +// Spew can be used in a static and a dynamic mode. The static +// mode allows us to display assertions and other messages either only +// in debug builds, or in non-release builds. The dynamic mode allows us to +// turn on and off certain spew messages while the application is running. +// +// Static Spew messages: +// +// Assertions are used to detect and warn about invalid states +// Spews are used to display a particular status/warning message. +// +// To use an assertion, use +// +// Assert( (f == 5) ); +// AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) ); +// AssertFunc( (f == 5), BadFunc() ); +// AssertEquals( f, 5 ); +// AssertFloatEquals( f, 5.0f, 1e-3 ); +// +// The first will simply report that an assertion failed on a particular +// code file and line. The second version will display a print-f formatted message +// along with the file and line, the third will display a generic message and +// will also cause the function BadFunc to be executed, and the last two +// will report an error if f is not equal to 5 (the last one asserts within +// a particular tolerance). +// +// To use a warning, use +// +// Warning("Oh I feel so %s all over\n", "yummy"); +// +// Warning will do its magic in only Debug builds. To perform spew in *all* +// builds, use RelWarning. +// +// Three other spew types, Msg, Log, and Error, are compiled into all builds. +// These error types do *not* need two sets of parenthesis. +// +// Msg( "Isn't this exciting %d?", 5 ); +// Error( "I'm just thrilled" ); +// +// Dynamic Spew messages +// +// It is possible to dynamically turn spew on and off. Dynamic spew is +// identified by a spew group and priority level. To turn spew on for a +// particular spew group, use SpewActivate( "group", level ). This will +// cause all spew in that particular group with priority levels <= the +// level specified in the SpewActivate function to be printed. Use DSpew +// to perform the spew: +// +// DWarning( "group", level, "Oh I feel even yummier!\n" ); +// +// Priority level 0 means that the spew will *always* be printed, and group +// '*' is the default spew group. If a DWarning is encountered using a group +// whose priority has not been set, it will use the priority of the default +// group. The priority of the default group is initially set to 0. +// +// Spew output +// +// The output of the spew system can be redirected to an externally-supplied +// function which is responsible for outputting the spew. By default, the +// spew is simply printed using printf. +// +// To redirect spew output, call SpewOutput. +// +// SpewOutputFunc( OutputFunc ); +// +// This will cause OutputFunc to be called every time a spew message is +// generated. OutputFunc will be passed a spew type and a message to print. +// It must return a value indicating whether the debugger should be invoked, +// whether the program should continue running, or whether the program +// should abort. +// +// 2. Code activation +// +// To cause code to be run only in debug builds, use DBG_CODE: +// An example is below. +// +// DBG_CODE( +// { +// int x = 5; +// ++x; +// } +// ); +// +// Code can be activated based on the dynamic spew groups also. Use +// +// DBG_DCODE( "group", level, +// { int x = 5; ++x; } +// ); +// +// 3. Breaking into the debugger. +// +// To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK +// +// DBG_BREAK(); +// +// You can force a break in any build (release or debug) using +// +// DebuggerBreak(); +//----------------------------------------------------------------------------- + +/* Various types of spew messages */ +// I'm sure you're asking yourself why SPEW_ instead of DBG_ ? +// It's because DBG_ is used all over the place in windows.h +// For example, DBG_CONTINUE is defined. Feh. +enum SpewType_t +{ + SPEW_MESSAGE = 0, + SPEW_WARNING, + SPEW_ASSERT, + SPEW_ERROR, + SPEW_LOG, + + SPEW_TYPE_COUNT +}; + +enum SpewRetval_t +{ + SPEW_DEBUGGER = 0, + SPEW_CONTINUE, + SPEW_ABORT +}; + +/* type of externally defined function used to display debug spew */ +typedef SpewRetval_t(*SpewOutputFunc_t)(SpewType_t spewType, char const *pMsg); + +/* Used to redirect spew output */ +void SpewOutputFunc(SpewOutputFunc_t func); + +/* Used ot get the current spew output function */ +SpewOutputFunc_t GetSpewOutputFunc(void); + +/* Used to manage spew groups and subgroups */ +void SpewActivate(char const* pGroupName, int level); +bool IsSpewActive(char const* pGroupName, int level); + +/* Used to display messages, should never be called directly. */ +void _SpewInfo(SpewType_t type, char const* pFile, int line); +SpewRetval_t _SpewMessage(char const* pMsg, ...); +SpewRetval_t _DSpewMessage(char const *pGroupName, int level, char const* pMsg, ...); + +/* Used to define macros, never use these directly. */ +#define _Assert( _exp ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + if (_SpewMessage("Assertion Failed: " #_exp) == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertMsg( _exp, _msg ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + if (_SpewMessage(_msg) == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertFunc( _exp, _f ) do { \ + if (!(_exp)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Assertion Failed!" #_exp); \ + _f; \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertEquals( _exp, _expectedValue ) \ + do { \ + if ((_exp) != (_expectedValue)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Expected %d but got %d!", (_expectedValue), (_exp)); \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +#define _AssertFloatEquals( _exp, _expectedValue, _tol ) \ + do { \ + if (fabs((_exp) - (_expectedValue)) > (_tol)) \ + { \ + _SpewInfo( SPEW_ASSERT, __FILE__, __LINE__ ); \ + SpewRetval_t ret = _SpewMessage("Expected %f but got %f!", (_expectedValue), (_exp)); \ + if (ret == SPEW_DEBUGGER) \ + { \ + DebuggerBreak(); \ + } \ + } \ + } while (0) + +/* Spew macros... */ + +#ifdef _DEBUG + +#define Assert( _exp ) _Assert( _exp ) +#define AssertMsg( _exp, _msg ) _AssertMsg( _exp, _msg ) +#define AssertFunc( _exp, _f ) _AssertFunc( _exp, _f ) +#define AssertEquals( _exp, _expectedValue ) _AssertEquals( _exp, _expectedValue ) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) _AssertFloatEquals( _exp, _expectedValue, _tol ) +#define Verify( _exp ) _Assert( _exp ) + +#define AssertMsg1( _exp, _msg, a1 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1 ) ) +#define AssertMsg2( _exp, _msg, a1, a2 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2 ) ) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3 ) ) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4 ) ) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5 ) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ) ) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7 ) ) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) _AssertMsg( _exp, CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ) + + +#else /* Not _DEBUG */ + +#define Assert( _exp ) ((void)0) +#define AssertMsg( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif /* _DEBUG */ + + + +/* These are always compiled in */ +void Msg(char const* pMsg, ...); +void DMsg(char const *pGroupName, int level, char const *pMsg, ...); + +void Warning(char const *pMsg, ...); +void DWarning(char const *pGroupName, int level, char const *pMsg, ...); + +void Log(char const *pMsg, ...); +void DLog(char const *pGroupName, int level, char const *pMsg, ...); + +void Error(char const *pMsg, ...); + +// You can use this macro like a runtime assert macro. +// If the condition fails, then Error is called with the message. This macro is called +// like AssertMsg, where msg must be enclosed in parenthesis: +// +// ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) ); +#define ErrorIfNot( condition, msg ) \ + if ( (condition) ) \ + ; \ + else \ + { \ + Error msg; \ + } + +/* A couple of super-common dynamic spew messages, here for convenience */ +/* These looked at the "developer" group */ +void DevMsg(int level, char const* pMsg, ...); +void DevWarning(int level, char const *pMsg, ...); +void DevLog(int level, char const *pMsg, ...); + +/* default level versions (level 1) */ +void DevMsg(char const* pMsg, ...); +void DevWarning(char const *pMsg, ...); +void DevLog(char const *pMsg, ...); + +/* Code macros, debugger interface */ + +#ifdef _DEBUG + +#define DBG_CODE( _code ) if (0) ; else { _code } +#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {} +#define DBG_BREAK() DebuggerBreak() /* defined in platform.h */ + +#else /* not _DEBUG */ + +#define DBG_CODE( _code ) ((void)0) +#define DBG_DCODE( _g, _l, _code ) ((void)0) +#define DBG_BREAK() ((void)0) + +#endif /* _DEBUG */ + +//----------------------------------------------------------------------------- +// Macro to assist in asserting constant invariants during compilation + +#define UID_PREFIX generated_id_ +#define UID_CAT1(a,c) a ## c +#define UID_CAT2(a,c) UID_CAT1(a,c) +#define UNIQUE_ID UID_CAT2(UID_PREFIX,__LINE__) + + +#ifdef _DEBUG +#define COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;} +#define ASSERT_INVARIANT( pred ) static void UNIQUE_ID() { COMPILE_TIME_ASSERT( pred ) } +#else +#define COMPILE_TIME_ASSERT( pred ) +#define ASSERT_INVARIANT( pred ) +#endif + + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +// Have to use these stubs so we don't have to include windows.h here. +void _AssertValidReadPtr(void* ptr, int count = 1); +void _AssertValidWritePtr(void* ptr, int count = 1); +void _AssertValidReadWritePtr(void* ptr, int count = 1); + + void AssertValidStringPtr(const char* ptr, int maxchar = 0xFFFFFF); +template inline void AssertValidReadPtr(T* ptr, int count = 1) { _AssertValidReadPtr((void*)ptr, count); } +template inline void AssertValidWritePtr(T* ptr, int count = 1) { _AssertValidWritePtr((void*)ptr, count); } +template inline void AssertValidReadWritePtr(T* ptr, int count = 1) { _AssertValidReadWritePtr((void*)ptr, count); } + +#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this)) + +//----------------------------------------------------------------------------- +// Macro to protect functions that are not reentrant + +#ifdef _DEBUG +class CReentryGuard +{ +public: + CReentryGuard(int *pSemaphore) + : m_pSemaphore(pSemaphore) + { + ++(*m_pSemaphore); + } + + ~CReentryGuard() + { + --(*m_pSemaphore); + } + +private: + int *m_pSemaphore; +}; + +#define ASSERT_NO_REENTRY() \ + static int fSemaphore##__LINE__; \ + Assert( !fSemaphore##__LINE__ ); \ + CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ ) +#else +#define ASSERT_NO_REENTRY() +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Inline string formatter +// + +class CDbgFmtMsg +{ +public: + CDbgFmtMsg(const char *pszFormat, ...) + { + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + _vsnprintf(m_szBuf, sizeof(m_szBuf) - 1, pszFormat, arg_ptr); + va_end(arg_ptr); + + m_szBuf[sizeof(m_szBuf) - 1] = 0; + } + + operator const char *() const + { + return m_szBuf; + } + +private: + char m_szBuf[256]; +}; + +//----------------------------------------------------------------------------- +// +// Purpose: Embed debug info in each file. +// + +//#ifdef _WIN32 +//#ifdef _DEBUG +//#pragma comment(compiler) +//#pragma comment(exestr,"*** DEBUG file detected, Last Compile: " __DATE__ ", " __TIME__ " ***") +//#endif +//#endif + +#endif /* DBG_H */ \ No newline at end of file diff --git a/rehlds/public/tier0/fasttimer.h b/rehlds/public/tier0/fasttimer.h new file mode 100644 index 0000000..d6ef979 --- /dev/null +++ b/rehlds/public/tier0/fasttimer.h @@ -0,0 +1,424 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef FASTTIMER_H +#define FASTTIMER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "tier0/platform.h" + + +PLATFORM_INTERFACE __int64 g_ClockSpeed; +PLATFORM_INTERFACE unsigned long g_dwClockSpeed; + +PLATFORM_INTERFACE double g_ClockSpeedMicrosecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedMillisecondsMultiplier; +PLATFORM_INTERFACE double g_ClockSpeedSecondsMultiplier; + + + +class CCycleCount +{ + friend class CFastTimer; + + +public: + CCycleCount(); + + void Sample(); // Sample the clock. This takes about 34 clocks to execute (or 26,000 calls per millisecond on a P900). + + void Init(); // Set to zero. + void Init(float initTimeMsec); + bool IsLessThan(CCycleCount const &other) const; // Compare two counts. + + // Convert to other time representations. These functions are slow, so it's preferable to call them + // during display rather than inside a timing block. + unsigned long GetCycles() const; + + unsigned long GetMicroseconds() const; + double GetMicrosecondsF() const; + + unsigned long GetMilliseconds() const; + double GetMillisecondsF() const; + + double GetSeconds() const; + + CCycleCount& operator+=(CCycleCount const &other); + + // dest = rSrc1 + rSrc2 + static void Add(CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest); // Add two samples together. + + // dest = rSrc1 - rSrc2 + static void Sub(CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest); // Add two samples together. + + + __int64 m_Int64; +}; + +class CClockSpeedInit +{ +public: + CClockSpeedInit() + { + Init(); + } + + static void Init() + { + const CPUInformation& pi = GetCPUInformation(); + + g_ClockSpeed = pi.m_Speed; + g_dwClockSpeed = (unsigned long)g_ClockSpeed; + + g_ClockSpeedMicrosecondsMultiplier = 1000000.0 / (double)g_ClockSpeed; + g_ClockSpeedMillisecondsMultiplier = 1000.0 / (double)g_ClockSpeed; + g_ClockSpeedSecondsMultiplier = 1.0f / (double)g_ClockSpeed; + } + +}; + +class CFastTimer +{ +public: + // These functions are fast to call and should be called from your sampling code. + void Start(); + void End(); + + const CCycleCount & GetDuration() const; // Get the elapsed time between Start and End calls. + CCycleCount GetDurationInProgress() const; // Call without ending. Not that cheap. + + // Return number of cycles per second on this processor. + static inline unsigned long GetClockSpeed(); + +private: + + CCycleCount m_Duration; +}; + + +// This is a helper class that times whatever block of code it's in +class CTimeScope +{ +public: + CTimeScope(CFastTimer *pTimer); + ~CTimeScope(); + +private: + CFastTimer *m_pTimer; +}; + +inline CTimeScope::CTimeScope(CFastTimer *pTotal) +{ + m_pTimer = pTotal; + m_pTimer->Start(); +} + +inline CTimeScope::~CTimeScope() +{ + m_pTimer->End(); +} + +// This is a helper class that times whatever block of code it's in and +// adds the total (int microseconds) to a global counter. +class CTimeAdder +{ +public: + CTimeAdder(CCycleCount *pTotal); + ~CTimeAdder(); + + void End(); + +private: + CCycleCount *m_pTotal; + CFastTimer m_Timer; +}; + +inline CTimeAdder::CTimeAdder(CCycleCount *pTotal) +{ + m_pTotal = pTotal; + m_Timer.Start(); +} + +inline CTimeAdder::~CTimeAdder() +{ + End(); +} + +inline void CTimeAdder::End() +{ + if (m_pTotal) + { + m_Timer.End(); + *m_pTotal += m_Timer.GetDuration(); + m_pTotal = 0; + } +} + + + +// -------------------------------------------------------------------------- // +// Simple tool to support timing a block of code, and reporting the results on +// program exit +// -------------------------------------------------------------------------- // + +#define PROFILE_SCOPE(name) \ + class C##name##ACC : public CAverageCycleCounter \ + { \ + public: \ + ~C##name##ACC() \ + { \ + Msg("%-48s: %6.3f avg (%8.1f total, %7.3f peak, %5d iters)\n", \ + #name, \ + GetAverageMilliseconds(), \ + GetTotalMilliseconds(), \ + GetPeakMilliseconds(), \ + GetIters() ); \ + } \ + }; \ + static C##name##ACC name##_ACC; \ + CAverageTimeMarker name##_ATM( &name##_ACC ) + +// -------------------------------------------------------------------------- // + +class CAverageCycleCounter +{ +public: + CAverageCycleCounter(); + + void Init(); + void MarkIter(const CCycleCount &duration); + + unsigned GetIters() const; + + double GetAverageMilliseconds() const; + double GetTotalMilliseconds() const; + double GetPeakMilliseconds() const; + +private: + unsigned m_nIters; + CCycleCount m_Total; + CCycleCount m_Peak; + bool m_fReport; + const char *m_pszName; +}; + +// -------------------------------------------------------------------------- // + +class CAverageTimeMarker +{ +public: + CAverageTimeMarker(CAverageCycleCounter *pCounter); + ~CAverageTimeMarker(); + +private: + CAverageCycleCounter *m_pCounter; + CFastTimer m_Timer; +}; +// -------------------------------------------------------------------------- // +// CCycleCount inlines. +// -------------------------------------------------------------------------- // + +inline CCycleCount::CCycleCount() +{ + m_Int64 = 0; +} + +inline void CCycleCount::Init() +{ + m_Int64 = 0; +} + +inline void CCycleCount::Init(float initTimeMsec) +{ + if (g_ClockSpeedMillisecondsMultiplier > 0) + m_Int64 = initTimeMsec / g_ClockSpeedMillisecondsMultiplier; + else + m_Int64 = 0; +} + +inline void CCycleCount::Sample() +{ + unsigned long* pSample = (unsigned long *)&m_Int64; + __asm + { + // force the cpu to synchronize the instruction queue + // NJS: CPUID can really impact performance in tight loops. + //cpuid + //cpuid + //cpuid + mov ecx, pSample + rdtsc + mov[ecx], eax + mov[ecx + 4], edx + } +} + + +inline CCycleCount& CCycleCount::operator+=(CCycleCount const &other) +{ + m_Int64 += other.m_Int64; + return *this; +} + + +inline void CCycleCount::Add(CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest) +{ + dest.m_Int64 = rSrc1.m_Int64 + rSrc2.m_Int64; +} + +inline void CCycleCount::Sub(CCycleCount const &rSrc1, CCycleCount const &rSrc2, CCycleCount &dest) +{ + dest.m_Int64 = rSrc1.m_Int64 - rSrc2.m_Int64; +} + +inline bool CCycleCount::IsLessThan(CCycleCount const &other) const +{ + return m_Int64 < other.m_Int64; +} + + +inline unsigned long CCycleCount::GetCycles() const +{ + return (unsigned long)m_Int64; +} + + +inline unsigned long CCycleCount::GetMicroseconds() const +{ + return (unsigned long)((m_Int64 * 1000000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMicrosecondsF() const +{ + return (double)(m_Int64 * g_ClockSpeedMicrosecondsMultiplier); +} + + +inline unsigned long CCycleCount::GetMilliseconds() const +{ + return (unsigned long)((m_Int64 * 1000) / g_ClockSpeed); +} + + +inline double CCycleCount::GetMillisecondsF() const +{ + return (double)(m_Int64 * g_ClockSpeedMillisecondsMultiplier); +} + + +inline double CCycleCount::GetSeconds() const +{ + return (double)(m_Int64 * g_ClockSpeedSecondsMultiplier); +} + + +// -------------------------------------------------------------------------- // +// CFastTimer inlines. +// -------------------------------------------------------------------------- // +inline void CFastTimer::Start() +{ + m_Duration.Sample(); +} + + +inline void CFastTimer::End() +{ + CCycleCount cnt; + cnt.Sample(); + m_Duration.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; +} + +inline CCycleCount CFastTimer::GetDurationInProgress() const +{ + CCycleCount cnt; + cnt.Sample(); + + CCycleCount result; + result.m_Int64 = cnt.m_Int64 - m_Duration.m_Int64; + + return result; +} + + +inline unsigned long CFastTimer::GetClockSpeed() +{ + return g_dwClockSpeed; +} + + +inline CCycleCount const& CFastTimer::GetDuration() const +{ + return m_Duration; +} + + +// -------------------------------------------------------------------------- // +// CAverageCycleCounter inlines + +inline CAverageCycleCounter::CAverageCycleCounter() + : m_nIters(0) +{ +} + +inline void CAverageCycleCounter::Init() +{ + m_Total.Init(); + m_Peak.Init(); + m_nIters = 0; +} + +inline void CAverageCycleCounter::MarkIter(const CCycleCount &duration) +{ + ++m_nIters; + m_Total += duration; + if (m_Peak.IsLessThan(duration)) + m_Peak = duration; +} + +inline unsigned CAverageCycleCounter::GetIters() const +{ + return m_nIters; +} + +inline double CAverageCycleCounter::GetAverageMilliseconds() const +{ + if (m_nIters) + return (m_Total.GetMillisecondsF() / (double)m_nIters); + else + return 0; +} + +inline double CAverageCycleCounter::GetTotalMilliseconds() const +{ + return m_Total.GetMillisecondsF(); +} + +inline double CAverageCycleCounter::GetPeakMilliseconds() const +{ + return m_Peak.GetMillisecondsF(); +} + +// -------------------------------------------------------------------------- // + +inline CAverageTimeMarker::CAverageTimeMarker(CAverageCycleCounter *pCounter) +{ + m_pCounter = pCounter; + m_Timer.Start(); +} + +inline CAverageTimeMarker::~CAverageTimeMarker() +{ + m_Timer.End(); + m_pCounter->MarkIter(m_Timer.GetDuration()); +} + + +#endif // FASTTIMER_H \ No newline at end of file diff --git a/rehlds/public/tier0/mem.h b/rehlds/public/tier0/mem.h new file mode 100644 index 0000000..5171ffe --- /dev/null +++ b/rehlds/public/tier0/mem.h @@ -0,0 +1,37 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: Memory allocation! +// +// $NoKeywords: $ +//============================================================================= + +#ifndef TIER0_MEM_H +#define TIER0_MEM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include +#include "tier0/platform.h" + +#ifdef TIER0_DLL_EXPORT +# define MEM_INTERFACE DLL_EXPORT +#else +# define MEM_INTERFACE DLL_IMPORT +#endif + + +//----------------------------------------------------------------------------- +// DLL-exported methods for particular kinds of memory +//----------------------------------------------------------------------------- +MEM_INTERFACE void *MemAllocScratch(int nMemSize); +MEM_INTERFACE void MemFreeScratch(); + +#ifdef __linux__ +MEM_INTERFACE void ZeroMemory(void *mem, size_t length); +#endif + + +#endif /* TIER0_MEM_H */ diff --git a/rehlds/public/tier0/memalloc.h b/rehlds/public/tier0/memalloc.h new file mode 100644 index 0000000..165d6d1 --- /dev/null +++ b/rehlds/public/tier0/memalloc.h @@ -0,0 +1,77 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// Purpose: This header should never be used directly from leaf code!!! +// Instead, just add the file memoverride.cpp into your project and all this +// will automagically be used +// +// $NoKeywords: $ +//============================================================================= + +#ifndef TIER0_MEMALLOC_H +#define TIER0_MEMALLOC_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include +#include "tier0/mem.h" + +struct _CrtMemState; + +//----------------------------------------------------------------------------- +// NOTE! This should never be called directly from leaf code +// Just use new,delete,malloc,free etc. They will call into this eventually +//----------------------------------------------------------------------------- +class IMemAlloc +{ +public: + // Release versions + virtual void *Alloc(size_t nSize) = 0; + virtual void *Realloc(void *pMem, size_t nSize) = 0; + virtual void Free(void *pMem) = 0; + virtual void *Expand(void *pMem, size_t nSize) = 0; + + // Debug versions + virtual void *Alloc(size_t nSize, const char *pFileName, int nLine) = 0; + virtual void *Realloc(void *pMem, size_t nSize, const char *pFileName, int nLine) = 0; + virtual void Free(void *pMem, const char *pFileName, int nLine) = 0; + virtual void *Expand(void *pMem, size_t nSize, const char *pFileName, int nLine) = 0; + + // Returns size of a particular allocation + virtual size_t GetSize(void *pMem) = 0; + + // Force file + line information for an allocation + virtual void PushAllocDbgInfo(const char *pFileName, int nLine) = 0; + virtual void PopAllocDbgInfo() = 0; + + // FIXME: Remove when we have our own allocator + // these methods of the Crt debug code is used in our codebase currently + virtual long CrtSetBreakAlloc(long lNewBreakAlloc) = 0; + virtual int CrtSetReportMode(int nReportType, int nReportMode) = 0; + virtual int CrtIsValidHeapPointer(const void *pMem) = 0; + virtual int CrtCheckMemory(void) = 0; + virtual int CrtSetDbgFlag(int nNewFlag) = 0; + virtual void CrtMemCheckpoint(_CrtMemState *pState) = 0; + + // FIXME: Make a better stats interface + virtual void DumpStats() = 0; + + // FIXME: Remove when we have our own allocator + virtual void* CrtSetReportFile(int nRptType, void* hFile) = 0; + virtual void* CrtSetReportHook(void* pfnNewHook) = 0; + virtual int CrtDbgReport(int nRptType, const char * szFile, + int nLine, const char * szModule, const char * pMsg) = 0; + + virtual int heapchk() = 0; +}; + + +//----------------------------------------------------------------------------- +// Singleton interface +//----------------------------------------------------------------------------- +IMemAlloc *g_pMemAlloc; + + +#endif /* TIER0_MEMALLOC_H */ diff --git a/rehlds/public/tier0/memdbgoff.h b/rehlds/public/tier0/memdbgoff.h new file mode 100644 index 0000000..7abf9e8 --- /dev/null +++ b/rehlds/public/tier0/memdbgoff.h @@ -0,0 +1,21 @@ +//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============ +// +// Purpose: This header, which must be the final line of a .h file, +// causes all crt methods to stop using debugging versions of the memory allocators. +// NOTE: Use memdbgon.h to re-enable memory debugging. +// +// $NoKeywords: $ +//============================================================================= + +#ifdef MEM_DEBUG_ON + +#undef malloc +#undef realloc +#undef calloc +#undef free +#undef _expand +#undef _msize +#undef new +#undef MEM_DEBUG_ON + +#endif diff --git a/rehlds/public/tier0/memdbgon.h b/rehlds/public/tier0/memdbgon.h new file mode 100644 index 0000000..3090b8f --- /dev/null +++ b/rehlds/public/tier0/memdbgon.h @@ -0,0 +1,93 @@ +//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============ +// +// Purpose: This header, which must be the final include in a .cpp (or .h) file, +// causes all crt methods to use debugging versions of the memory allocators. +// NOTE: Use memdbgoff.h to disable memory debugging. +// +// $NoKeywords: $ +//============================================================================= + +// SPECIAL NOTE! This file must *not* use include guards; we need to be able +// to include this potentially multiple times (since we can deactivate debugging +// by including memdbgoff.h) + +// SPECIAL NOTE #2: This must be the final include in a .cpp or .h file!!! +#include "osconfig.h" + +#ifdef _DEBUG + +#include +#include +#include +#include + +#include "tier0/memdbgoff.h" + +#define MEM_DEBUG_ON 1 + +#undef malloc +#undef realloc +#undef calloc +#undef _expand +#undef free +#undef _msize + +#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define calloc(c, s) _calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define realloc(p, s) _realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) +#define free(p) _free_dbg(p, _NORMAL_BLOCK) +#define _msize(p) _msize_dbg(p, _NORMAL_BLOCK) +#define _expand(p, s) _expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__) + + +#if defined(__AFX_H__) && defined(DEBUG_NEW) +#define new DEBUG_NEW +#else +#undef new +#define MEMALL_DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +#define new MEMALL_DEBUG_NEW +#endif + +#undef _strdup +#undef strdup +#undef _wcsdup +#undef wcsup + +#define _strdup(s) strdup_dbg(s, __FILE__, __LINE__) +#define strdup(s) strdup_dbg(s, __FILE__, __LINE__) +#define _wcsdup(s) wcsdup_dbg(s, __FILE__, __LINE__) +#define wcsdup(s) wcsdup_dbg(s, __FILE__, __LINE__) + +// Make sure we don't define strdup twice +#ifndef MEM_DBG_DEFINED_STRDUP +#define MEM_DBG_DEFINED_STRDUP 1 + +inline char *strdup_dbg(const char *pString, const char *pFileName, unsigned nLine) +{ + char *pMemory; + + if (!pString) + return NULL; + + if ((pMemory = (char *)_malloc_dbg(strlen(pString) + 1, _NORMAL_BLOCK, pFileName, nLine)) != NULL) + return strcpy(pMemory, pString); + + return NULL; +} + +inline wchar_t *wcsdup_dbg(const wchar_t *pString, const char *pFileName, unsigned nLine) +{ + wchar_t *pMemory; + + if (!pString) + return NULL; + + if ((pMemory = (wchar_t *)_malloc_dbg((wcslen(pString) + 1) * sizeof(wchar_t), _NORMAL_BLOCK, pFileName, nLine)) != NULL) + return wcscpy(pMemory, pString); + + return NULL; +} + +#endif // DBMEM_DEFINED_STRDUP + +#endif // _DEBUG diff --git a/rehlds/public/tier0/platform.h b/rehlds/public/tier0/platform.h new file mode 100644 index 0000000..0f1910b --- /dev/null +++ b/rehlds/public/tier0/platform.h @@ -0,0 +1,651 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Extremely low-level platform-specific stuff +//============================================================================= + + +#ifndef PLATFORM_H +#define PLATFORM_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" + +// need this for _alloca +#include + +// need this for memset +#include + +// for when we care about how many bits we use +typedef signed char int8; +typedef signed short int16; + +#ifdef _WIN32 +#ifdef _MSC_VER +typedef signed __int64 int64; +#endif +#elif defined __linux__ +typedef long long int64; +#endif + +typedef unsigned char uint8; +typedef unsigned short uint16; +#ifdef _WIN32 +#ifdef _MSC_VER +typedef unsigned __int64 uint64; +#endif +#elif defined __linux__ +typedef unsigned long long uint64; +#endif + + +typedef float float32; +typedef double float64; + +// for when we don't care about how many bits we use +typedef unsigned int uint; + +// This can be used to ensure the size of pointers to members when declaring +// a pointer type for a class that has only been forward declared +#ifdef _MSC_VER +#define SINGLE_INHERITANCE __single_inheritance +#define MULTIPLE_INHERITANCE __multiple_inheritance +#else +#define SINGLE_INHERITANCE +#define MULTIPLE_INHERITANCE +#endif + +/* +FIXME: Enable this when we no longer fear change =) + +// need these for the limits +#include +#include + +// Maximum and minimum representable values +#define INT8_MAX SCHAR_MAX +#define INT16_MAX SHRT_MAX +#define INT32_MAX LONG_MAX +#define INT64_MAX (((int64)~0) >> 1) + +#define INT8_MIN SCHAR_MIN +#define INT16_MIN SHRT_MIN +#define INT32_MIN LONG_MIN +#define INT64_MIN (((int64)1) << 63) + +#define UINT8_MAX ((uint8)~0) +#define UINT16_MAX ((uint16)~0) +#define UINT32_MAX ((uint32)~0) +#define UINT64_MAX ((uint64)~0) + +#define UINT8_MIN 0 +#define UINT16_MIN 0 +#define UINT32_MIN 0 +#define UINT64_MIN 0 + +#ifndef UINT_MIN +#define UINT_MIN UINT32_MIN +#endif + +#define FLOAT32_MAX FLT_MAX +#define FLOAT64_MAX DBL_MAX + +#define FLOAT32_MIN FLT_MIN +#define FLOAT64_MIN DBL_MIN +*/ + +// portability / compiler settings +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +#elif __linux__ +typedef void * HINSTANCE; +#define _MAX_PATH PATH_MAX +#endif // defined(_WIN32) && !defined(WINDED) + + +// Defines MAX_PATH +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +// Used to step into the debugger +#define DebuggerBreak() __asm { int 3 } + +// C functions for external declarations that call the appropriate C++ methods +#ifndef EXPORT +#ifdef _WIN32 +#define EXPORT _declspec( dllexport ) +#else +#define EXPORT /* */ +#endif +#endif + +#if defined __i386__ && !defined __linux__ +#define id386 1 +#else +#define id386 0 +#endif // __i386__ + +#ifdef _WIN32 +// Used for dll exporting and importing +#define DLL_EXPORT extern "C" __declspec( dllexport ) +#define DLL_IMPORT extern "C" __declspec( dllimport ) + +// Can't use extern "C" when DLL exporting a class +#define DLL_CLASS_EXPORT __declspec( dllexport ) +#define DLL_CLASS_IMPORT __declspec( dllimport ) + +// Can't use extern "C" when DLL exporting a global +#define DLL_GLOBAL_EXPORT extern __declspec( dllexport ) +#define DLL_GLOBAL_IMPORT extern __declspec( dllimport ) +#elif defined __linux__ + +// Used for dll exporting and importing +#define DLL_EXPORT extern "C" +#define DLL_IMPORT extern "C" + +// Can't use extern "C" when DLL exporting a class +#define DLL_CLASS_EXPORT +#define DLL_CLASS_IMPORT + +// Can't use extern "C" when DLL exporting a global +#define DLL_GLOBAL_EXPORT extern +#define DLL_GLOBAL_IMPORT extern + +#else +#error "Unsupported Platform." +#endif + +// Used for standard calling conventions +#ifdef _WIN32 +#define FASTCALL __fastcall +#define FORCEINLINE __forceinline +#else +#define FASTCALL +#define FORCEINLINE inline +#endif + +// Force a function call site -not- to inlined. (useful for profiling) +#define DONT_INLINE(a) (((int)(a)+1)?(a):(a)) + +// Pass hints to the compiler to prevent it from generating unnessecary / stupid code +// in certain situations. Several compilers other than MSVC also have an equivilent +// construct. +// +// Essentially the 'Hint' is that the condition specified is assumed to be true at +// that point in the compilation. If '0' is passed, then the compiler assumes that +// any subsequent code in the same 'basic block' is unreachable, and thus usually +// removed. +#ifdef _MSC_VER +#define HINT(THE_HINT) __assume((THE_HINT)) +#else +#define HINT(THE_HINT) 0 +#endif + +// Marks the codepath from here until the next branch entry point as unreachable, +// and asserts if any attempt is made to execute it. +#define UNREACHABLE() { Assert(0); HINT(0); } + +// In cases where no default is present or appropriate, this causes MSVC to generate +// as little code as possible, and throw an assertion in debug. +#define NO_DEFAULT default: UNREACHABLE(); + +#ifdef _WIN32 +// Alloca defined for this platform +#define stackalloc( _size ) _alloca( _size ) +#define stackfree( _p ) 0 +#elif __linux__ +// Alloca defined for this platform +#define stackalloc( _size ) alloca( _size ) +#define stackfree( _p ) 0 +#endif + +#ifdef _WIN32 +// Remove warnings from warning level 4. +#pragma warning(disable : 4514) // warning C4514: 'acosl' : unreferenced inline function has been removed +#pragma warning(disable : 4100) // warning C4100: 'hwnd' : unreferenced formal parameter +#pragma warning(disable : 4127) // warning C4127: conditional expression is constant +#pragma warning(disable : 4512) // warning C4512: 'InFileRIFF' : assignment operator could not be generated +#pragma warning(disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable +#pragma warning(disable : 4706) // warning C4706: assignment within conditional expression +#pragma warning(disable : 4710) // warning C4710: function 'x' not inlined +#pragma warning(disable : 4702) // warning C4702: unreachable code +#pragma warning(disable : 4505) // unreferenced local function has been removed +#pragma warning(disable : 4239) // nonstandard extension used : 'argument' ( conversion from class Vector to class Vector& ) +#pragma warning(disable : 4097) // typedef-name 'BaseClass' used as synonym for class-name 'CFlexCycler::CBaseFlex' +#pragma warning(disable : 4324) // Padding was added at the end of a structure +#pragma warning(disable : 4244) // type conversion warning. +#pragma warning(disable : 4305) // truncation from 'const double ' to 'float ' +#pragma warning(disable : 4786) // Disable warnings about long symbol names + +#if _MSC_VER >= 1300 +#pragma warning(disable : 4511) // Disable warnings about private copy constructors +#endif +#endif +//----------------------------------------------------------------------------- +// Purpose: Standard functions for handling endian-ness +//----------------------------------------------------------------------------- + +//------------------------------------- +// Basic swaps +//------------------------------------- + +template +inline T WordSwapC(T w) +{ + uint16 temp; + + temp = ((*((uint16 *)&w) & 0xff00) >> 8); + temp |= ((*((uint16 *)&w) & 0x00ff) << 8); + + return *((T*)&temp); +} + +template +inline T DWordSwapC(T dw) +{ + uint32 temp; + + temp = *((uint32 *)&dw) >> 24; + temp |= ((*((uint32 *)&dw) & 0x00FF0000) >> 8); + temp |= ((*((uint32 *)&dw) & 0x0000FF00) << 8); + temp |= ((*((uint32 *)&dw) & 0x000000FF) << 24); + + return *((T*)&temp); +} + +//------------------------------------- +// Fast swaps +//------------------------------------- + +#ifdef _MSC_VER + +#define WordSwap WordSwapAsm +#define DWordSwap DWordSwapAsm + +#pragma warning(push) +#pragma warning (disable:4035) // no return value + +template +inline T WordSwapAsm(T w) +{ + __asm + { + mov ax, w + xchg al, ah + } +} + +template +inline T DWordSwapAsm(T dw) +{ + __asm + { + mov eax, dw + bswap eax + } +} + +#pragma warning(pop) + +// The assembly implementation is not compatible with floats +template <> +inline float DWordSwapAsm(float f) +{ + return DWordSwapC(f); +} + +#else + +#define WordSwap WordSwapC +#define DWordSwap DWordSwapC + +#endif + +//------------------------------------- +// The typically used methods. +//------------------------------------- + +#if defined(__i386__) +#define VALVE_LITTLE_ENDIAN 1 +#endif + +#ifdef _SGI_SOURCE +#define VALVE_BIG_ENDIAN 1 +#endif + +#if defined(VALVE_LITTLE_ENDIAN) + +#define Valve_BigShort( val ) WordSwap( val ) +#define Valve_BigWord( val ) WordSwap( val ) +#define Valve_BigLong( val ) DWordSwap( val ) +#define Valve_BigDWord( val ) DWordSwap( val ) +#define Valve_BigFloat( val ) DWordSwap( val ) +#define Valve_LittleShort( val ) ( val ) +#define Valve_LittleWord( val ) ( val ) +#define Valve_LittleLong( val ) ( val ) +#define Valve_LittleDWord( val ) ( val ) +#define Valve_LittleFloat( val ) ( val ) + +#elif defined(BIG_ENDIAN) + +#define Valve_BigShort( val ) ( val ) +#define Valve_BigWord( val ) ( val ) +#define Valve_BigLong( val ) ( val ) +#define Valve_BigDWord( val ) ( val ) +#define Valve_BigFloat( val ) ( val ) +#define Valve_LittleShort( val ) WordSwap( val ) +#define Valve_LittleWord( val ) WordSwap( val ) +#define Valve_LittleLong( val ) DWordSwap( val ) +#define Valve_LittleDWord( val ) DWordSwap( val ) +#define Valve_LittleFloat( val ) DWordSwap( val ) + +#else + +// @Note (toml 05-02-02): this technique expects the compiler to +// optimize the expression and eliminate the other path. On any new +// platform/compiler this should be tested. +inline short BigShort(short val) { int test = 1; return (*(char *)&test == 1) ? WordSwap(val) : val; } +inline uint16 BigWord(uint16 val) { int test = 1; return (*(char *)&test == 1) ? WordSwap(val) : val; } +inline long BigLong(long val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline uint32 BigDWord(uint32 val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline float BigFloat(float val) { int test = 1; return (*(char *)&test == 1) ? DWordSwap(val) : val; } +inline short LittleShort(short val) { int test = 1; return (*(char *)&test == 1) ? val : WordSwap(val); } +inline uint16 LittleWord(uint16 val) { int test = 1; return (*(char *)&test == 1) ? val : WordSwap(val); } +inline long LittleLong(long val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } +inline uint32 LittleDWord(uint32 val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } +inline float LittleFloat(float val) { int test = 1; return (*(char *)&test == 1) ? val : DWordSwap(val); } + +#endif + + + +#ifdef TIER0_DLL_EXPORT +#define PLATFORM_INTERFACE DLL_EXPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_EXPORT +#else +#define PLATFORM_INTERFACE DLL_IMPORT +#define PLATFORM_OVERLOAD DLL_GLOBAL_IMPORT +#endif + +/* +PLATFORM_INTERFACE double Plat_FloatTime(); // Returns time in seconds since the module was loaded. +PLATFORM_INTERFACE unsigned long Plat_MSTime(); // Time in milliseconds. + +// b/w compatibility +#define Sys_FloatTime Plat_FloatTime +*/ + +// Processor Information: +struct CPUInformation +{ + int m_Size; // Size of this structure, for forward compatability. + + bool m_bRDTSC : 1, // Is RDTSC supported? + m_bCMOV : 1, // Is CMOV supported? + m_bFCMOV : 1, // Is FCMOV supported? + m_bSSE : 1, // Is SSE supported? + m_bSSE2 : 1, // Is SSE2 Supported? + m_b3DNow : 1, // Is 3DNow! Supported? + m_bMMX : 1, // Is MMX supported? + m_bHT : 1; // Is HyperThreading supported? + + unsigned char m_nLogicalProcessors, // Number op logical processors. + m_nPhysicalProcessors; // Number of physical processors + + int64 m_Speed; // In cycles per second. + + char* m_szProcessorID; // Processor vendor Identification. +}; + +PLATFORM_INTERFACE const CPUInformation& GetCPUInformation(); + + +//----------------------------------------------------------------------------- +// Thread related functions +//----------------------------------------------------------------------------- +// Registers the current thread with Tier0's thread management system. +// This should be called on every thread created in the game. +PLATFORM_INTERFACE unsigned long Plat_RegisterThread(const char *pName = "Source Thread"); + +// Registers the current thread as the primary thread. +PLATFORM_INTERFACE unsigned long Plat_RegisterPrimaryThread(); + +// VC-specific. Sets the thread's name so it has a friendly name in the debugger. +// This should generally only be handled by Plat_RegisterThread and Plat_RegisterPrimaryThread +PLATFORM_INTERFACE void Plat_SetThreadName(unsigned long dwThreadID, const char *pName); + +// These would be private if it were possible to export private variables from a .DLL. +// They need to be variables because they are checked by inline functions at performance +// critical places. +PLATFORM_INTERFACE unsigned long Plat_PrimaryThreadID; + +// Returns the ID of the currently executing thread. +PLATFORM_INTERFACE unsigned long Plat_GetCurrentThreadID(); + +// Returns the ID of the primary thread. +inline unsigned long Plat_GetPrimaryThreadID() +{ + return Plat_PrimaryThreadID; +} + +// Returns true if the current thread is the primary thread. +inline bool Plat_IsPrimaryThread() +{ + //return true; + return (Plat_GetPrimaryThreadID() == Plat_GetCurrentThreadID()); +} + +//----------------------------------------------------------------------------- +// Security related functions +//----------------------------------------------------------------------------- +// Ensure that the hardware key's drivers have been installed. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyDriver(); + +// Ok, so this isn't a very secure way to verify the hardware key for now. It +// is primarially depending on the fact that all the binaries have been wrapped +// with the secure wrapper provided by the hardware keys vendor. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKey(); + +// The same as above, but notifies user with a message box when the key isn't in +// and gives him an opportunity to correct the situation. +PLATFORM_INTERFACE bool Plat_VerifyHardwareKeyPrompt(); + +// Can be called in real time, doesn't perform the verify every frame. Mainly just +// here to allow the game to drop out quickly when the key is removed, rather than +// allowing the wrapper to pop up it's own blocking dialog, which the engine doesn't +// like much. +PLATFORM_INTERFACE bool Plat_FastVerifyHardwareKey(); + + + +//----------------------------------------------------------------------------- +// Include additional dependant header components. +//----------------------------------------------------------------------------- +#include "tier0/fasttimer.h" + + +//----------------------------------------------------------------------------- +// Just logs file and line to simple.log +//----------------------------------------------------------------------------- +void* Plat_SimpleLog(const char* file, int line); + +//#define Plat_dynamic_cast Plat_SimpleLog(__FILE__,__LINE__),dynamic_cast + +//----------------------------------------------------------------------------- +// Methods to invoke the constructor, copy constructor, and destructor +//----------------------------------------------------------------------------- + +template +inline void Construct(T* pMemory) +{ + new(pMemory)T; +} + +template +inline void CopyConstruct(T* pMemory, T const& src) +{ + new(pMemory)T(src); +} + +template +inline void Destruct(T* pMemory) +{ + pMemory->~T(); + +#ifdef _DEBUG + memset(pMemory, 0xDD, sizeof(T)); +#endif +} + + +// +// GET_OUTER() +// +// A platform-independent way for a contained class to get a pointer to its +// owner. If you know a class is exclusively used in the context of some +// "outer" class, this is a much more space efficient way to get at the outer +// class than having the inner class store a pointer to it. +// +// class COuter +// { +// class CInner // Note: this does not need to be a nested class to work +// { +// void PrintAddressOfOuter() +// { +// printf( "Outer is at 0x%x\n", GET_OUTER( COuter, m_Inner ) ); +// } +// }; +// +// CInner m_Inner; +// friend class CInner; +// }; + +#define GET_OUTER( OuterType, OuterMember ) \ + ( ( OuterType * ) ( (char *)this - offsetof( OuterType, OuterMember ) ) ) + + +/* TEMPLATE_FUNCTION_TABLE() + +(Note added to platform.h so platforms that correctly support templated +functions can handle portions as templated functions rather than wrapped +functions) + +Helps automate the process of creating an array of function +templates that are all specialized by a single integer. +This sort of thing is often useful in optimization work. + +For example, using TEMPLATE_FUNCTION_TABLE, this: + +TEMPLATE_FUNCTION_TABLE(int, Function, ( int blah, int blah ), 10) +{ +return argument * argument; +} + +is equivilent to the following: + +(NOTE: the function has to be wrapped in a class due to code +generation bugs involved with directly specializing a function +based on a constant.) + +template +class FunctionWrapper +{ +public: +int Function( int blah, int blah ) +{ +return argument*argument; +} +} + +typedef int (*FunctionType)( int blah, int blah ); + +class FunctionName +{ +public: +enum { count = 10 }; +FunctionType functions[10]; +}; + +FunctionType FunctionName::functions[] = +{ +FunctionWrapper<0>::Function, +FunctionWrapper<1>::Function, +FunctionWrapper<2>::Function, +FunctionWrapper<3>::Function, +FunctionWrapper<4>::Function, +FunctionWrapper<5>::Function, +FunctionWrapper<6>::Function, +FunctionWrapper<7>::Function, +FunctionWrapper<8>::Function, +FunctionWrapper<9>::Function +}; +*/ + +bool vtune(bool resume); + + +#define TEMPLATE_FUNCTION_TABLE(RETURN_TYPE, NAME, ARGS, COUNT) \ + \ +typedef RETURN_TYPE (FASTCALL *__Type_##NAME) ARGS; \ + \ +template \ +struct __Function_##NAME \ +{ \ + static RETURN_TYPE FASTCALL Run ARGS; \ +}; \ + \ +template \ +struct __MetaLooper_##NAME : __MetaLooper_##NAME \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME::Run; } \ +}; \ + \ +template<> \ +struct __MetaLooper_##NAME<0> \ +{ \ + __Type_##NAME func; \ + inline __MetaLooper_##NAME() { func = __Function_##NAME<0>::Run; } \ +}; \ + \ +class NAME \ +{ \ +private: \ + static const __MetaLooper_##NAME m; \ +public: \ + enum { count = COUNT }; \ + static const __Type_##NAME* functions; \ +}; \ +const __MetaLooper_##NAME NAME::m; \ +const __Type_##NAME* NAME::functions = (__Type_##NAME*)&m; \ +template \ +RETURN_TYPE FASTCALL __Function_##NAME::Run ARGS + + +#define LOOP_INTERCHANGE(BOOLEAN, CODE)\ + if( (BOOLEAN) )\ + {\ + CODE;\ + } else\ + {\ + CODE;\ + } + + +#endif /* PLATFORM_H */ \ No newline at end of file diff --git a/rehlds/public/tier0/platform_linux.cpp b/rehlds/public/tier0/platform_linux.cpp new file mode 100644 index 0000000..ed150dc --- /dev/null +++ b/rehlds/public/tier0/platform_linux.cpp @@ -0,0 +1,59 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "precompiled.h" + +double Plat_FloatTime() +{ + struct timeval tp; + static int secbase = 0; + + gettimeofday(&tp, NULL); + + if (!secbase) + { + secbase = tp.tv_sec; + return (tp.tv_usec / 1000000.0); + } + + return ((tp.tv_sec - secbase) + tp.tv_usec / 1000000.0); +} + +unsigned long Plat_MSTime() +{ + struct timeval tp; + static int secbase = 0; + + gettimeofday(&tp, NULL); + + if (!secbase) + { + secbase = tp.tv_sec; + return (tp.tv_usec / 1000000.0); + } + + return (unsigned long)((tp.tv_sec - secbase) + tp.tv_usec / 1000000.0); + +} + + + +bool vtune(bool resume) +{ + return true; +} + + +// -------------------------------------------------------------------------------------------------- // +// Memory stuff. +// -------------------------------------------------------------------------------------------------- // + + +void Plat_SetThreadName(unsigned long dwThreadID, const char *pName) +{ + Assert("Plat_SetThreadName not implemented"); +} diff --git a/rehlds/public/tier0/platform_win32.cpp b/rehlds/public/tier0/platform_win32.cpp new file mode 100644 index 0000000..10562ee --- /dev/null +++ b/rehlds/public/tier0/platform_win32.cpp @@ -0,0 +1,88 @@ +//========= Copyright © 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "precompiled.h" + +static LARGE_INTEGER g_PerformanceFrequency; +static LARGE_INTEGER g_MSPerformanceFrequency; +static LARGE_INTEGER g_ClockStart; + +static void InitTime() +{ + if (!g_PerformanceFrequency.QuadPart) + { + QueryPerformanceFrequency(&g_PerformanceFrequency); + g_MSPerformanceFrequency.QuadPart = g_PerformanceFrequency.QuadPart / 1000; + QueryPerformanceCounter(&g_ClockStart); + } +} + +double Plat_FloatTime() +{ + InitTime(); + + LARGE_INTEGER CurrentTime; + + QueryPerformanceCounter(&CurrentTime); + + double fRawSeconds = (double)(CurrentTime.QuadPart - g_ClockStart.QuadPart) / (double)(g_PerformanceFrequency.QuadPart); + + return fRawSeconds; +} + +unsigned long Plat_MSTime() +{ + InitTime(); + + LARGE_INTEGER CurrentTime; + + QueryPerformanceCounter(&CurrentTime); + + return (unsigned long)((CurrentTime.QuadPart - g_ClockStart.QuadPart) / g_MSPerformanceFrequency.QuadPart); +} + +bool vtune(bool resume) +{ + static bool bInitialized = false; + static void(__cdecl *VTResume)(void) = NULL; + static void(__cdecl *VTPause) (void) = NULL; + + // Grab the Pause and Resume function pointers from the VTune DLL the first time through: + if (!bInitialized) + { + bInitialized = true; + + HINSTANCE pVTuneDLL = LoadLibrary("vtuneapi.dll"); + + if (pVTuneDLL) + { + VTResume = (void(__cdecl *)())GetProcAddress(pVTuneDLL, "VTResume"); + VTPause = (void(__cdecl *)())GetProcAddress(pVTuneDLL, "VTPause"); + } + } + + // Call the appropriate function, as indicated by the argument: + if (resume && VTResume) + { + VTResume(); + return true; + + } + else if (!resume && VTPause) + { + VTPause(); + return true; + } + + return false; + +} + + +// -------------------------------------------------------------------------------------------------- // +// Memory stuff. +// -------------------------------------------------------------------------------------------------- // diff --git a/rehlds/public/utlbuffer.cpp b/rehlds/public/utlbuffer.cpp new file mode 100644 index 0000000..d0498b2 --- /dev/null +++ b/rehlds/public/utlbuffer.cpp @@ -0,0 +1,419 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Serialization buffer +//============================================================================= + +#include "precompiled.h" + +//----------------------------------------------------------------------------- +// constructors +//----------------------------------------------------------------------------- +CUtlBuffer::CUtlBuffer(int growSize, int initSize, bool text) : +m_Memory(growSize, initSize), m_Error(0) +{ + m_Get = 0; + m_Put = 0; + m_Flags = 0; + if (text) + { + m_Flags |= TEXT_BUFFER; + } +} + +CUtlBuffer::CUtlBuffer(void const* pBuffer, int size, bool text) : +m_Memory((unsigned char*)pBuffer, size), m_Error(0) +{ + m_Get = 0; + m_Put = 0; + m_Flags = 0; + if (text) + m_Flags |= TEXT_BUFFER; +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +void CUtlBuffer::SetExternalBuffer(void* pMemory, int numElements, bool text) +{ + m_Memory.SetExternalBuffer((unsigned char*)pMemory, numElements); + + // Reset all indices; we just changed memory + m_Get = 0; + m_Put = 0; + m_Flags = 0; + if (text) + m_Flags |= TEXT_BUFFER; +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +void CUtlBuffer::EnsureCapacity(int num) +{ + m_Memory.EnsureCapacity(num); +} + + +//----------------------------------------------------------------------------- +// Base get method from which all others derive +//----------------------------------------------------------------------------- +void CUtlBuffer::Get(void* pMem, int size) +{ + Assert(m_Get + size <= m_Memory.NumAllocated()); + memcpy(pMem, &m_Memory[m_Get], size); + m_Get += size; +} + + +//----------------------------------------------------------------------------- +// Eats whitespace +//----------------------------------------------------------------------------- +void CUtlBuffer::EatWhiteSpace() +{ + if (IsText() && IsValid()) + { + int lastpos = Size(); + while (m_Get < lastpos) + { + if (!isspace(*(char*)&m_Memory[m_Get])) + break; + m_Get += sizeof(char); + } + } +} + + +//----------------------------------------------------------------------------- +// Reads a null-terminated string +//----------------------------------------------------------------------------- +void CUtlBuffer::GetString(char* pString, int nMaxLen) +{ + if (!IsValid()) + { + *pString = 0; + return; + } + + if (nMaxLen == 0) + { + nMaxLen = INT_MAX; + } + + if (!IsText()) + { + int len = strlen((char*)&m_Memory[m_Get]) + 1; + if (len <= nMaxLen) + { + Get(pString, len); + } + else + { + Get(pString, nMaxLen); + pString[nMaxLen - 1] = 0; + SeekGet(SEEK_CURRENT, len - nMaxLen); + } + } + else + { + // eat all whitespace + EatWhiteSpace(); + + // Eat characters + int nCount = 0; + int nLastPos = Size(); + while (m_Get < nLastPos) + { + char c = *(char*)&m_Memory[m_Get]; + if (isspace(c) || (!c)) + break; + + if (nCount < nMaxLen - 1) + { + *pString++ = c; + } + ++nCount; + ++m_Get; + } + + // Terminate + *pString = 0; + } +} + + +//----------------------------------------------------------------------------- +// Checks if a get is ok +//----------------------------------------------------------------------------- +bool CUtlBuffer::CheckGet(int size) +{ + if (m_Error) + return false; + + if (m_Memory.NumAllocated() >= m_Get + size) + return true; + + m_Error |= GET_OVERFLOW; + return false; +} + + +//----------------------------------------------------------------------------- +// Change where I'm reading +//----------------------------------------------------------------------------- +void CUtlBuffer::SeekGet(SeekType_t type, int offset) +{ + switch (type) + { + case SEEK_HEAD: + m_Get = offset; + break; + + case SEEK_CURRENT: + m_Get += offset; + break; + + case SEEK_TAIL: + m_Get = m_Memory.NumAllocated() - offset; + break; + } +} + + +//----------------------------------------------------------------------------- +// Parse... +//----------------------------------------------------------------------------- + +#pragma warning ( disable : 4706 ) + +int CUtlBuffer::VaScanf(char const* pFmt, va_list list) +{ + Assert(pFmt); + if (m_Error || !IsText()) + return 0; + + int numScanned = 0; + + char c; + char* pEnd; + while (c = *pFmt++) + { + // Stop if we hit the end of the buffer + if (m_Get >= Size()) + { + m_Error |= GET_OVERFLOW; + break; + } + + switch (c) + { + case ' ': + // eat all whitespace + EatWhiteSpace(); + break; + + case '%': + { + // Conversion character... try to convert baby! + char type = *pFmt++; + if (type == 0) + return numScanned; + + switch (type) + { + case 'c': + { + char* ch = va_arg(list, char *); + *ch = (char)m_Memory[m_Get]; + ++m_Get; + } + break; + + case 'i': + case 'd': + { + int* i = va_arg(list, int *); + *i = strtol((char*)PeekGet(), &pEnd, 10); + if (pEnd == PeekGet()) + return numScanned; + m_Get = (int)pEnd - (int)Base(); + } + break; + + case 'x': + { + int* i = va_arg(list, int *); + *i = strtol((char*)PeekGet(), &pEnd, 16); + if (pEnd == PeekGet()) + return numScanned; + m_Get = (int)pEnd - (int)Base(); + } + break; + + case 'u': + { + unsigned int* u = va_arg(list, unsigned int *); + *u = strtoul((char*)PeekGet(), &pEnd, 10); + if (pEnd == PeekGet()) + return numScanned; + m_Get = (int)pEnd - (int)Base(); + } + break; + + case 'f': + { + float* f = va_arg(list, float *); + *f = (float)strtod((char*)PeekGet(), &pEnd); + if (pEnd == PeekGet()) + return numScanned; + m_Get = (int)pEnd - (int)Base(); + } + break; + + case 's': + { + char* s = va_arg(list, char *); + GetString(s); + } + break; + + default: + { + // unimplemented scanf type + Assert(0); + return numScanned; + } + break; + } + + ++numScanned; + } + break; + + default: + { + // Here we have to match the format string character + // against what's in the buffer or we're done. + if (c != m_Memory[m_Get]) + return numScanned; + ++m_Get; + } + } + } + return numScanned; +} + +#pragma warning ( default : 4706 ) + +int CUtlBuffer::Scanf(char const* pFmt, ...) +{ + va_list args; + + va_start(args, pFmt); + int count = VaScanf(pFmt, args); + va_end(args); + + return count; +} + + +//----------------------------------------------------------------------------- +// Serialization +//----------------------------------------------------------------------------- + +void CUtlBuffer::Put(void const* pMem, int size) +{ + if (CheckPut(size)) + { + memcpy(&m_Memory[m_Put], pMem, size); + m_Put += size; + } +} + + +//----------------------------------------------------------------------------- +// Writes a null-terminated string +//----------------------------------------------------------------------------- + +void CUtlBuffer::PutString(char const* pString) +{ + int len = strlen(pString); + + // Not text? append a null at the end. + if (!IsText()) + ++len; + + Put(pString, len); +} + +void CUtlBuffer::VaPrintf(char const* pFmt, va_list list) +{ + char temp[2048]; + int len = vsprintf(temp, pFmt, list); + Assert(len < 2048); + + // Not text? append a null at the end. + if (!IsText()) + ++len; + + Put(temp, len); +} + +void CUtlBuffer::Printf(char const* pFmt, ...) +{ + va_list args; + + va_start(args, pFmt); + VaPrintf(pFmt, args); + va_end(args); +} + + +//----------------------------------------------------------------------------- +// Checks if a put is ok +//----------------------------------------------------------------------------- + +bool CUtlBuffer::CheckPut(int size) +{ + if (m_Error) + return false; + + while (m_Memory.NumAllocated() < m_Put + size) + { + if (m_Memory.IsExternallyAllocated()) + { + m_Error |= PUT_OVERFLOW; + return false; + } + + m_Memory.Grow(); + } + return true; +} + +void CUtlBuffer::SeekPut(SeekType_t type, int offset) +{ + switch (type) + { + case SEEK_HEAD: + m_Put = offset; + break; + + case SEEK_CURRENT: + m_Put += offset; + break; + + case SEEK_TAIL: + m_Put = m_Memory.NumAllocated() - offset; + break; + } +} \ No newline at end of file diff --git a/rehlds/public/utlbuffer.h b/rehlds/public/utlbuffer.h new file mode 100644 index 0000000..9ac532d --- /dev/null +++ b/rehlds/public/utlbuffer.h @@ -0,0 +1,341 @@ +//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============ +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// Serialization/unserialization buffer +//============================================================================= + +#ifndef UTLBUFFER_H +#define UTLBUFFER_H + +#include "osconfig.h" +#include "utlmemory.h" +#include + +//----------------------------------------------------------------------------- +// Command parsing.. +//----------------------------------------------------------------------------- + +class CUtlBuffer +{ +public: + enum SeekType_t + { + SEEK_HEAD = 0, + SEEK_CURRENT, + SEEK_TAIL + }; + + CUtlBuffer(int growSize = 0, int initSize = 0, bool text = false); + CUtlBuffer(void const* pBuffer, int size, bool text = false); + + // Makes sure we've got at least this much memory + void EnsureCapacity(int num); + + // Attaches the buffer to external memory.... + void SetExternalBuffer(void* pMemory, int numElements, bool text = false); + + // Read stuff out. + // Binary mode: it'll just read the bits directly in, and characters will be + // read for strings until a null character is reached. + // Text mode: it'll parse the file, turning text #s into real numbers. + // GetString will read a string until a space is reaced + char GetChar(); + unsigned char GetUnsignedChar(); + short GetShort(); + unsigned short GetUnsignedShort(); + int GetInt(); + int GetIntHex(); + unsigned int GetUnsignedInt(); + float GetFloat(); + double GetDouble(); + void GetString(char* pString, int nMaxLen = 0); + void Get(void* pMem, int size); + + // Just like scanf, but doesn't work in binary mode + int Scanf(char const* pFmt, ...); + int VaScanf(char const* pFmt, va_list list); + + // Eats white space, advances Get index + void EatWhiteSpace(); + + // Write stuff in + // Binary mode: it'll just write the bits directly in, and strings will be + // written with a null terminating character + // Text mode: it'll convert the numbers to text versions + // PutString will not write a terminating character + void PutChar(char c); + void PutUnsignedChar(unsigned char uc); + void PutShort(short s); + void PutUnsignedShort(unsigned short us); + void PutInt(int i); + void PutUnsignedInt(unsigned int u); + void PutFloat(float f); + void PutDouble(double d); + void PutString(char const* pString); + void Put(void const* pMem, int size); + + // Just like printf, writes a terminating zero in binary mode + void Printf(char const* pFmt, ...); + void VaPrintf(char const* pFmt, va_list list); + + // What am I writing (put)/reading (get)? + void* PeekPut(int offset = 0); + void const* PeekGet(int offset = 0) const; + + // Where am I writing (put)/reading (get)? + int TellPut() const; + int TellGet() const; + + // Change where I'm writing (put)/reading (get) + void SeekPut(SeekType_t type, int offset); + void SeekGet(SeekType_t type, int offset); + + // Buffer base + void const* Base() const; + void* Base(); + + // memory allocation size, does *not* reflect size written or read, + // use TellPut or TellGet for that + int Size() const; + + // Am I a text buffer? + inline bool IsText() const { return (m_Flags & TEXT_BUFFER) != 0; } + + // Am I valid? (overflow or underflow error), Once invalid it stays invalid + inline bool IsValid() const { return m_Error == 0; } + +private: + // error flags + enum + { + PUT_OVERFLOW = 0x1, + GET_OVERFLOW = 0x2, + }; + + // flags + enum + { + TEXT_BUFFER = 0x1, + }; + + // Checks if a get/put is ok + bool CheckPut(int size); + bool CheckGet(int size); + + CUtlMemory m_Memory; + int m_Get; + int m_Put; + unsigned char m_Error; + unsigned char m_Flags; +}; + + +//----------------------------------------------------------------------------- +// Where am I reading? +//----------------------------------------------------------------------------- + +inline int CUtlBuffer::TellGet() const +{ + return m_Get; +} + + +//----------------------------------------------------------------------------- +// What am I reading? +//----------------------------------------------------------------------------- +inline void const* CUtlBuffer::PeekGet(int offset) const +{ + return &m_Memory[m_Get + offset]; +} + + +//----------------------------------------------------------------------------- +// Unserialization +//----------------------------------------------------------------------------- +#define GET_TYPE( _type, _val, _fmt ) \ + if (!IsText()) \ + { \ + if (CheckGet( sizeof(_type) )) \ + { \ + _val = *(_type *)PeekGet(); \ + m_Get += sizeof(_type); \ + } \ + else \ + { \ + _val = 0; \ + } \ + } \ + else \ + { \ + _val = 0; \ + Scanf( _fmt, &_val ); \ + } + +inline char CUtlBuffer::GetChar() +{ + char c; + GET_TYPE(char, c, "%c"); + return c; +} + +inline unsigned char CUtlBuffer::GetUnsignedChar() +{ + unsigned char c; + GET_TYPE(unsigned char, c, "%u"); + return c; +} + +inline short CUtlBuffer::GetShort() +{ + short s; + GET_TYPE(short, s, "%d"); + return s; +} + +inline unsigned short CUtlBuffer::GetUnsignedShort() +{ + unsigned short s; + GET_TYPE(unsigned short, s, "%u"); + return s; +} + +inline int CUtlBuffer::GetInt() +{ + int i; + GET_TYPE(int, i, "%d"); + return i; +} + +inline int CUtlBuffer::GetIntHex() +{ + int i; + GET_TYPE(int, i, "%x"); + return i; +} + +inline unsigned int CUtlBuffer::GetUnsignedInt() +{ + unsigned int u; + GET_TYPE(unsigned int, u, "%u"); + return u; +} + +inline float CUtlBuffer::GetFloat() +{ + float f; + GET_TYPE(float, f, "%f"); + return f; +} + +inline double CUtlBuffer::GetDouble() +{ + double d; + GET_TYPE(double, d, "%f"); + return d; +} + + +//----------------------------------------------------------------------------- +// Where am I writing? +//----------------------------------------------------------------------------- +inline int CUtlBuffer::TellPut() const +{ + return m_Put; +} + + +//----------------------------------------------------------------------------- +// What am I reading? +//----------------------------------------------------------------------------- +inline void* CUtlBuffer::PeekPut(int offset) +{ + return &m_Memory[m_Put + offset]; +} + + +//----------------------------------------------------------------------------- +// Various put methods +//----------------------------------------------------------------------------- +#define PUT_TYPE( _type, _val, _fmt ) \ + if (!IsText()) \ + { \ + if (CheckPut( sizeof(_type) )) \ + { \ + *(_type *)PeekPut() = _val; \ + m_Put += sizeof(_type); \ + } \ + } \ + else \ + { \ + Printf( _fmt, _val ); \ + } + + +inline void CUtlBuffer::PutChar(char c) +{ + PUT_TYPE(char, c, "%c"); +} + +inline void CUtlBuffer::PutUnsignedChar(unsigned char c) +{ + PUT_TYPE(unsigned char, c, "%u"); +} + +inline void CUtlBuffer::PutShort(short s) +{ + PUT_TYPE(short, s, "%d"); +} + +inline void CUtlBuffer::PutUnsignedShort(unsigned short s) +{ + PUT_TYPE(unsigned short, s, "%u"); +} + +inline void CUtlBuffer::PutInt(int i) +{ + PUT_TYPE(int, i, "%d"); +} + +inline void CUtlBuffer::PutUnsignedInt(unsigned int u) +{ + PUT_TYPE(unsigned int, u, "%u"); +} + +inline void CUtlBuffer::PutFloat(float f) +{ + PUT_TYPE(float, f, "%f"); +} + +inline void CUtlBuffer::PutDouble(double d) +{ + PUT_TYPE(double, d, "%f"); +} + +//----------------------------------------------------------------------------- +// Buffer base and size +//----------------------------------------------------------------------------- + +inline void const* CUtlBuffer::Base() const +{ + return m_Memory.Base(); +} + +inline void* CUtlBuffer::Base() +{ + return m_Memory.Base(); +} + +inline int CUtlBuffer::Size() const +{ + return m_Memory.NumAllocated(); +} + + +#endif // UTLBUFFER_H diff --git a/rehlds/public/utllinkedlist.h b/rehlds/public/utllinkedlist.h new file mode 100644 index 0000000..05f8799 --- /dev/null +++ b/rehlds/public/utllinkedlist.h @@ -0,0 +1,693 @@ +//======== (C) Copyright 1999, 2000 Valve, L.L.C. All rights reserved. ======== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Linked list container class +// +// $Revision: $ +// $NoKeywords: $ +//============================================================================= + +#ifndef UTLLINKEDLIST_H +#define UTLLINKEDLIST_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "basetypes.h" +#include "utlmemory.h" +#include "tier0/dbg.h" + + +// This is a useful macro to iterate from head to tail in a linked list. +#define FOR_EACH_LL( listName, iteratorName ) \ + for( int iteratorName=listName.Head(); iteratorName != listName.InvalidIndex(); iteratorName = listName.Next( iteratorName ) ) + +#define INVALID_LLIST_IDX ((I)~0) + +//----------------------------------------------------------------------------- +// class CUtlLinkedList: +// description: +// A lovely index-based linked list! T is the class type, I is the index +// type, which usually should be an unsigned short or smaller. +//----------------------------------------------------------------------------- + +template +class CUtlLinkedList +{ +public: + typedef T ElemType_t; + typedef I IndexType_t; + + // constructor, destructor + CUtlLinkedList(int growSize = 0, int initSize = 0); + CUtlLinkedList(void *pMemory, int memsize); + ~CUtlLinkedList(); + + // gets particular elements + T& Element(I i); + T const& Element(I i) const; + T& operator[](I i); + T const& operator[](I i) const; + + // Make sure we have a particular amount of memory + void EnsureCapacity(int num); + + // Memory deallocation + void Purge(); + + // Delete all the elements then call Purge. + void PurgeAndDeleteElements(); + + // Insertion methods.... + I InsertBefore(I before); + I InsertAfter(I after); + I AddToHead(); + I AddToTail(); + + I InsertBefore(I before, T const& src); + I InsertAfter(I after, T const& src); + I AddToHead(T const& src); + I AddToTail(T const& src); + + // Find an element and return its index or InvalidIndex() if it couldn't be found. + I Find(const T &src) const; + + // Look for the element. If it exists, remove it and return true. Otherwise, return false. + bool FindAndRemove(const T &src); + + // Removal methods + void Remove(I elem); + void RemoveAll(); + + // Allocation/deallocation methods + // If multilist == true, then list list may contain many + // non-connected lists, and IsInList and Head + Tail are meaningless... + I Alloc(bool multilist = false); + void Free(I elem); + + // list modification + void LinkBefore(I before, I elem); + void LinkAfter(I after, I elem); + void Unlink(I elem); + void LinkToHead(I elem); + void LinkToTail(I elem); + + // invalid index + inline static I InvalidIndex() { return INVALID_LLIST_IDX; } + inline static size_t ElementSize() { return sizeof(ListElem_t); } + + // list statistics + int Count() const; + I MaxElementIndex() const; + + // Traversing the list + I Head() const; + I Tail() const; + I Previous(I i) const; + I Next(I i) const; + + // Are nodes in the list or valid? + bool IsValidIndex(I i) const; + bool IsInList(I i) const; + +protected: + // What the linked list element looks like + struct ListElem_t + { + T m_Element; + I m_Previous; + I m_Next; + + private: + // No copy constructor for these... + ListElem_t(const ListElem_t&); + }; + + // constructs the class + I AllocInternal(bool multilist = false); + void ConstructList(); + + // Gets at the list element.... + ListElem_t& InternalElement(I i) { return m_Memory[i]; } + ListElem_t const& InternalElement(I i) const { return m_Memory[i]; } + + void ResetDbgInfo() + { + m_pElements = m_Memory.Base(); + } + + // copy constructors not allowed + CUtlLinkedList(CUtlLinkedList const& list) { Assert(0); } + + CUtlMemory m_Memory; + I m_Head; + I m_Tail; + I m_FirstFree; + I m_ElementCount; // The number actually in the list + I m_TotalElements; // The number allocated + + // For debugging purposes; + // it's in release builds so this can be used in libraries correctly + ListElem_t *m_pElements; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template +CUtlLinkedList::CUtlLinkedList(int growSize, int initSize) : +m_Memory(growSize, initSize) +{ + ConstructList(); + ResetDbgInfo(); +} + +template +CUtlLinkedList::CUtlLinkedList(void* pMemory, int memsize) : +m_Memory((ListElem_t *)pMemory, memsize / sizeof(ListElem_t)) +{ + ConstructList(); + ResetDbgInfo(); +} + +template +CUtlLinkedList::~CUtlLinkedList() +{ + RemoveAll(); +} + +template +void CUtlLinkedList::ConstructList() +{ + m_Head = InvalidIndex(); + m_Tail = InvalidIndex(); + m_FirstFree = InvalidIndex(); + m_ElementCount = m_TotalElements = 0; +} + + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- + +template +inline T& CUtlLinkedList::Element(I i) +{ + return m_Memory[i].m_Element; +} + +template +inline T const& CUtlLinkedList::Element(I i) const +{ + return m_Memory[i].m_Element; +} + +template +inline T& CUtlLinkedList::operator[](I i) +{ + return m_Memory[i].m_Element; +} + +template +inline T const& CUtlLinkedList::operator[](I i) const +{ + return m_Memory[i].m_Element; +} + +//----------------------------------------------------------------------------- +// list statistics +//----------------------------------------------------------------------------- + +template +inline int CUtlLinkedList::Count() const +{ + return m_ElementCount; +} + +template +inline I CUtlLinkedList::MaxElementIndex() const +{ + return m_Memory.NumAllocated(); +} + + +//----------------------------------------------------------------------------- +// Traversing the list +//----------------------------------------------------------------------------- + +template +inline I CUtlLinkedList::Head() const +{ + return m_Head; +} + +template +inline I CUtlLinkedList::Tail() const +{ + return m_Tail; +} + +template +inline I CUtlLinkedList::Previous(I i) const +{ + Assert(IsValidIndex(i)); + return InternalElement(i).m_Previous; +} + +template +inline I CUtlLinkedList::Next(I i) const +{ + Assert(IsValidIndex(i)); + return InternalElement(i).m_Next; +} + + +//----------------------------------------------------------------------------- +// Are nodes in the list or valid? +//----------------------------------------------------------------------------- + +template +inline bool CUtlLinkedList::IsValidIndex(I i) const +{ + return (i < m_TotalElements) && (i >= 0) && + ((m_Memory[i].m_Previous != i) || (m_Memory[i].m_Next == i)); +} + +template +inline bool CUtlLinkedList::IsInList(I i) const +{ + return (i < m_TotalElements) && (i >= 0) && (Previous(i) != i); +} + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- + +template< class T, class I > +void CUtlLinkedList::EnsureCapacity(int num) +{ + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Deallocate memory +//----------------------------------------------------------------------------- + +template +void CUtlLinkedList::Purge() +{ + RemoveAll(); + m_Memory.Purge(); + m_FirstFree = InvalidIndex(); + m_TotalElements = 0; + ResetDbgInfo(); + +} + + +template +void CUtlLinkedList::PurgeAndDeleteElements() +{ + int iNext; + for (int i = Head(); i != InvalidIndex(); i = iNext) + { + iNext = Next(i); + delete Element(i); + } + + Purge(); +} + + +//----------------------------------------------------------------------------- +// Node allocation/deallocation +//----------------------------------------------------------------------------- +template +I CUtlLinkedList::AllocInternal(bool multilist) +{ + I elem; + if (m_FirstFree == InvalidIndex()) + { + // Nothing in the free list; add. + // Since nothing is in the free list, m_TotalElements == total # of elements + // the list knows about. + if (m_TotalElements == m_Memory.NumAllocated()) + m_Memory.Grow(); + + Assert(m_TotalElements != InvalidIndex()); + + elem = (I)m_TotalElements; + ++m_TotalElements; + + if (elem == InvalidIndex()) + { + Error("CUtlLinkedList overflow!\n"); + } + } + else + { + elem = m_FirstFree; + m_FirstFree = InternalElement(m_FirstFree).m_Next; + } + + if (!multilist) + InternalElement(elem).m_Next = InternalElement(elem).m_Previous = elem; + else + InternalElement(elem).m_Next = InternalElement(elem).m_Previous = InvalidIndex(); + + ResetDbgInfo(); + + return elem; +} + +template +I CUtlLinkedList::Alloc(bool multilist) +{ + I elem = AllocInternal(multilist); + Construct(&Element(elem)); + + return elem; +} + +template +void CUtlLinkedList::Free(I elem) +{ + Assert(IsValidIndex(elem)); + Unlink(elem); + + ListElem_t &internalElem = InternalElement(elem); + Destruct(&internalElem.m_Element); + internalElem.m_Next = m_FirstFree; + m_FirstFree = elem; +} + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses default constructor) +//----------------------------------------------------------------------------- + +template +I CUtlLinkedList::InsertBefore(I before) +{ + // Make a new node + I newNode = AllocInternal(); + + // Link it in + LinkBefore(before, newNode); + + // Construct the data + Construct(&Element(newNode)); + + return newNode; +} + +template +I CUtlLinkedList::InsertAfter(I after) +{ + // Make a new node + I newNode = AllocInternal(); + + // Link it in + LinkAfter(after, newNode); + + // Construct the data + Construct(&Element(newNode)); + + return newNode; +} + +template +inline I CUtlLinkedList::AddToHead() +{ + return InsertAfter(InvalidIndex()); +} + +template +inline I CUtlLinkedList::AddToTail() +{ + return InsertBefore(InvalidIndex()); +} + + +//----------------------------------------------------------------------------- +// Insertion methods; allocates and links (uses copy constructor) +//----------------------------------------------------------------------------- + +template +I CUtlLinkedList::InsertBefore(I before, T const& src) +{ + // Make a new node + I newNode = AllocInternal(); + + // Link it in + LinkBefore(before, newNode); + + // Construct the data + CopyConstruct(&Element(newNode), src); + + return newNode; +} + +template +I CUtlLinkedList::InsertAfter(I after, T const& src) +{ + // Make a new node + I newNode = AllocInternal(); + + // Link it in + LinkAfter(after, newNode); + + // Construct the data + CopyConstruct(&Element(newNode), src); + + return newNode; +} + +template +inline I CUtlLinkedList::AddToHead(T const& src) +{ + return InsertAfter(InvalidIndex(), src); +} + +template +inline I CUtlLinkedList::AddToTail(T const& src) +{ + return InsertBefore(InvalidIndex(), src); +} + + +//----------------------------------------------------------------------------- +// Removal methods +//----------------------------------------------------------------------------- + +template +I CUtlLinkedList::Find(const T &src) const +{ + for (I i = Head(); i != InvalidIndex(); i = Next(i)) + { + if (Element(i) == src) + return i; + } + return InvalidIndex(); +} + + +template +bool CUtlLinkedList::FindAndRemove(const T &src) +{ + I i = Find(src); + if (i == InvalidIndex()) + { + return false; + } + else + { + Remove(i); + return true; + } +} + + +template +void CUtlLinkedList::Remove(I elem) +{ + Free(elem); +} + +template +void CUtlLinkedList::RemoveAll() +{ + if (m_TotalElements == 0) + return; + + // Put everything into the free list + I prev = InvalidIndex(); + for (int i = (int)m_TotalElements; --i >= 0;) + { + // Invoke the destructor + if (IsValidIndex((I)i)) + Destruct(&Element((I)i)); + + // next points to the next free list item + InternalElement((I)i).m_Next = prev; + + // Indicates it's in the free list + InternalElement((I)i).m_Previous = (I)i; + prev = (I)i; + } + + // First free points to the first element + m_FirstFree = 0; + + // Clear everything else out + m_Head = InvalidIndex(); + m_Tail = InvalidIndex(); + m_ElementCount = 0; +} + + +//----------------------------------------------------------------------------- +// list modification +//----------------------------------------------------------------------------- + +template +void CUtlLinkedList::LinkBefore(I before, I elem) +{ + Assert(IsValidIndex(elem)); + + // Unlink it if it's in the list at the moment + Unlink(elem); + + ListElem_t& newElem = InternalElement(elem); + + // The element *after* our newly linked one is the one we linked before. + newElem.m_Next = before; + + if (before == InvalidIndex()) + { + // In this case, we're linking to the end of the list, so reset the tail + newElem.m_Previous = m_Tail; + m_Tail = elem; + } + else + { + // Here, we're not linking to the end. Set the prev pointer to point to + // the element we're linking. + Assert(IsInList(before)); + ListElem_t& beforeElem = InternalElement(before); + newElem.m_Previous = beforeElem.m_Previous; + beforeElem.m_Previous = elem; + } + + // Reset the head if we linked to the head of the list + if (newElem.m_Previous == InvalidIndex()) + m_Head = elem; + else + InternalElement(newElem.m_Previous).m_Next = elem; + + // one more element baby + ++m_ElementCount; +} + +template +void CUtlLinkedList::LinkAfter(I after, I elem) +{ + Assert(IsValidIndex(elem)); + + // Unlink it if it's in the list at the moment + if (IsInList(elem)) + Unlink(elem); + + ListElem_t& newElem = InternalElement(elem); + + // The element *before* our newly linked one is the one we linked after + newElem.m_Previous = after; + if (after == InvalidIndex()) + { + // In this case, we're linking to the head of the list, reset the head + newElem.m_Next = m_Head; + m_Head = elem; + } + else + { + // Here, we're not linking to the end. Set the next pointer to point to + // the element we're linking. + Assert(IsInList(after)); + ListElem_t& afterElem = InternalElement(after); + newElem.m_Next = afterElem.m_Next; + afterElem.m_Next = elem; + } + + // Reset the tail if we linked to the tail of the list + if (newElem.m_Next == InvalidIndex()) + m_Tail = elem; + else + InternalElement(newElem.m_Next).m_Previous = elem; + + // one more element baby + ++m_ElementCount; +} + +template +void CUtlLinkedList::Unlink(I elem) +{ + Assert(IsValidIndex(elem)); + if (IsInList(elem)) + { + ListElem_t *pBase = m_Memory.Base(); + ListElem_t *pOldElem = &pBase[elem]; + + // If we're the first guy, reset the head + // otherwise, make our previous node's next pointer = our next + if (pOldElem->m_Previous != INVALID_LLIST_IDX) + { + pBase[pOldElem->m_Previous].m_Next = pOldElem->m_Next; + } + else + { + m_Head = pOldElem->m_Next; + } + + // If we're the last guy, reset the tail + // otherwise, make our next node's prev pointer = our prev + if (pOldElem->m_Next != INVALID_LLIST_IDX) + { + pBase[pOldElem->m_Next].m_Previous = pOldElem->m_Previous; + } + else + { + m_Tail = pOldElem->m_Previous; + } + + // This marks this node as not in the list, + // but not in the free list either + pOldElem->m_Previous = pOldElem->m_Next = elem; + + // One less puppy + --m_ElementCount; + } +} + +template +inline void CUtlLinkedList::LinkToHead(I elem) +{ + LinkAfter(InvalidIndex(), elem); +} + +template +inline void CUtlLinkedList::LinkToTail(I elem) +{ + LinkBefore(InvalidIndex(), elem); +} + + +#endif // UTLLINKEDLIST_H diff --git a/rehlds/public/utlmemory.h b/rehlds/public/utlmemory.h new file mode 100644 index 0000000..68353f3 --- /dev/null +++ b/rehlds/public/utlmemory.h @@ -0,0 +1,323 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// A growable memory class. +//============================================================================= + +#ifndef UTLMEMORY_H +#define UTLMEMORY_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "osconfig.h" +#include "tier0/dbg.h" +#include +#include "tier0/platform.h" + +#pragma warning (disable:4100) +#pragma warning (disable:4514) + +//----------------------------------------------------------------------------- +// The CUtlMemory class: +// A growable memory class which doubles in size by default. +//----------------------------------------------------------------------------- +template< class T > +class CUtlMemory +{ +public: + // constructor, destructor + CUtlMemory(int nGrowSize = 0, int nInitSize = 0); + CUtlMemory(T* pMemory, int numElements); + ~CUtlMemory(); + + // element access + T& operator[](int i); + T const& operator[](int i) const; + T& Element(int i); + T const& Element(int i) const; + + // Can we use this index? + bool IsIdxValid(int i) const; + + // Gets the base address (can change when adding elements!) + T* Base(); + T const* Base() const; + + // Attaches the buffer to external memory.... + void SetExternalBuffer(T* pMemory, int numElements); + + // Size + int NumAllocated() const; + int Count() const; + + // Grows the memory, so that at least allocated + num elements are allocated + void Grow(int num = 1); + + // Makes sure we've got at least this much memory + void EnsureCapacity(int num); + + // Memory deallocation + void Purge(); + + // is the memory externally allocated? + bool IsExternallyAllocated() const; + + // Set the size by which the memory grows + void SetGrowSize(int size); + +private: + enum + { + EXTERNAL_BUFFER_MARKER = -1, + }; + + T* m_pMemory; + int m_nAllocationCount; + int m_nGrowSize; +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +template< class T > +CUtlMemory::CUtlMemory(int nGrowSize, int nInitAllocationCount) : m_pMemory(0), +m_nAllocationCount(nInitAllocationCount), m_nGrowSize(nGrowSize) +{ + Assert((nGrowSize >= 0) && (nGrowSize != EXTERNAL_BUFFER_MARKER)); + if (m_nAllocationCount) + { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + +template< class T > +CUtlMemory::CUtlMemory(T* pMemory, int numElements) : m_pMemory(pMemory), +m_nAllocationCount(numElements) +{ + // Special marker indicating externally supplied memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + +template< class T > +CUtlMemory::~CUtlMemory() +{ + Purge(); +} + + +//----------------------------------------------------------------------------- +// Attaches the buffer to external memory.... +//----------------------------------------------------------------------------- +template< class T > +void CUtlMemory::SetExternalBuffer(T* pMemory, int numElements) +{ + // Blow away any existing allocated memory + Purge(); + + m_pMemory = pMemory; + m_nAllocationCount = numElements; + + // Indicate that we don't own the memory + m_nGrowSize = EXTERNAL_BUFFER_MARKER; +} + + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- +template< class T > +inline T& CUtlMemory::operator[](int i) +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T const& CUtlMemory::operator[](int i) const +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T& CUtlMemory::Element(int i) +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + +template< class T > +inline T const& CUtlMemory::Element(int i) const +{ + Assert(IsIdxValid(i)); + return m_pMemory[i]; +} + + +//----------------------------------------------------------------------------- +// is the memory externally allocated? +//----------------------------------------------------------------------------- +template< class T > +bool CUtlMemory::IsExternallyAllocated() const +{ + return m_nGrowSize == EXTERNAL_BUFFER_MARKER; +} + + +template< class T > +void CUtlMemory::SetGrowSize(int nSize) +{ + Assert((nSize >= 0) && (nSize != EXTERNAL_BUFFER_MARKER)); + m_nGrowSize = nSize; +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- +template< class T > +inline T* CUtlMemory::Base() +{ + return m_pMemory; +} + +template< class T > +inline T const* CUtlMemory::Base() const +{ + return m_pMemory; +} + + +//----------------------------------------------------------------------------- +// Size +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlMemory::NumAllocated() const +{ + return m_nAllocationCount; +} + +template< class T > +inline int CUtlMemory::Count() const +{ + return m_nAllocationCount; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- +template< class T > +inline bool CUtlMemory::IsIdxValid(int i) const +{ + return (i >= 0) && (i < m_nAllocationCount); +} + + +//----------------------------------------------------------------------------- +// Grows the memory +//----------------------------------------------------------------------------- +template< class T > +void CUtlMemory::Grow(int num) +{ + Assert(num > 0); + + if (IsExternallyAllocated()) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + // Make sure we have at least numallocated + num allocations. + // Use the grow rules specified for this memory (in m_nGrowSize) + int nAllocationRequested = m_nAllocationCount + num; + while (m_nAllocationCount < nAllocationRequested) + { + if (m_nAllocationCount != 0) + { + if (m_nGrowSize) + { + m_nAllocationCount += m_nGrowSize; + } + else + { + m_nAllocationCount += m_nAllocationCount; + } + } + else + { + // Compute an allocation which is at least as big as a cache line... + m_nAllocationCount = (31 + sizeof(T)) / sizeof(T); + Assert(m_nAllocationCount != 0); + } + } + + if (m_pMemory) + { + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + } + else + { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + + +//----------------------------------------------------------------------------- +// Makes sure we've got at least this much memory +//----------------------------------------------------------------------------- +template< class T > +inline void CUtlMemory::EnsureCapacity(int num) +{ + if (m_nAllocationCount >= num) + return; + + if (IsExternallyAllocated()) + { + // Can't grow a buffer whose memory was externally allocated + Assert(0); + return; + } + + m_nAllocationCount = num; + if (m_pMemory) + { + m_pMemory = (T*)realloc(m_pMemory, m_nAllocationCount * sizeof(T)); + } + else + { + m_pMemory = (T*)malloc(m_nAllocationCount * sizeof(T)); + } +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- +template< class T > +void CUtlMemory::Purge() +{ + if (!IsExternallyAllocated()) + { + if (m_pMemory) + { + free((void*)m_pMemory); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } +} + + +#endif // UTLSTORAGE_H \ No newline at end of file diff --git a/rehlds/public/utlrbtree.h b/rehlds/public/utlrbtree.h new file mode 100644 index 0000000..4fc0673 --- /dev/null +++ b/rehlds/public/utlrbtree.h @@ -0,0 +1,1295 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Header: $ +// $NoKeywords: $ +//============================================================================= + +#ifndef UTLRBTREE_H +#define UTLRBTREE_H + +//#include +#include "utlmemory.h" + +//----------------------------------------------------------------------------- +// Tool to generate a default compare function for any type that implements +// operator<, including all simple types +//----------------------------------------------------------------------------- + +template +class CDefOps +{ +public: + static bool LessFunc( const T &lhs, const T &rhs ) { return ( lhs < rhs ); } +}; + +#define DefLessFunc( type ) CDefOps::LessFunc + +//------------------------------------- + +inline bool StringLessThan( const char * const &lhs, const char * const &rhs) { return ( strcmp( lhs, rhs) < 0 ); } +inline bool CaselessStringLessThan( const char * const &lhs, const char * const &rhs ) { return ( _stricmp( lhs, rhs) < 0 ); } + +//------------------------------------- +// inline these two templates to stop multiple definitions of the same code +template <> inline bool CDefOps::LessFunc( const char * const &lhs, const char * const &rhs ) { return StringLessThan( lhs, rhs ); } +template <> inline bool CDefOps::LessFunc( char * const &lhs, char * const &rhs ) { return StringLessThan( lhs, rhs ); } + +//------------------------------------- + +template +void SetDefLessFunc( RBTREE_T &RBTree ) +{ +#ifdef _WIN32 + RBTree.SetLessFunc( DefLessFunc( RBTREE_T::KeyType_t ) ); +#elif _LINUX + RBTree.SetLessFunc( DefLessFunc( typename RBTREE_T::KeyType_t ) ); +#endif +} + +//----------------------------------------------------------------------------- +// A red-black binary search tree +//----------------------------------------------------------------------------- + +template +class CUtlRBTree +{ +public: + // Less func typedef + // Returns true if the first parameter is "less" than the second + typedef bool (*LessFunc_t)( T const &, T const & ); + + typedef T KeyType_t; + typedef T ElemType_t; + typedef I IndexType_t; + + // constructor, destructor + // Left at growSize = 0, the memory will first allocate 1 element and double in size + // at each increment. + // LessFunc_t is required, but may be set after the constructor using SetLessFunc() below + CUtlRBTree( int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0 ); + ~CUtlRBTree( ); + + // gets particular elements + T& Element( I i ); + T const &Element( I i ) const; + T& operator[]( I i ); + T const &operator[]( I i ) const; + + // Gets the root + I Root() const; + + // Num elements + unsigned int Count() const; + + // Max "size" of the vector + I MaxElement() const; + + // Gets the children + I Parent( I i ) const; + I LeftChild( I i ) const; + I RightChild( I i ) const; + + // Tests if a node is a left or right child + bool IsLeftChild( I i ) const; + bool IsRightChild( I i ) const; + + // Tests if root or leaf + bool IsRoot( I i ) const; + bool IsLeaf( I i ) const; + + // Checks if a node is valid and in the tree + bool IsValidIndex( I i ) const; + + // Checks if the tree as a whole is valid + bool IsValid() const; + + // Invalid index + static I InvalidIndex(); + + // returns the tree depth (not a very fast operation) + int Depth( I node ) const; + int Depth() const; + + // Sets the less func + void SetLessFunc( LessFunc_t func ); + + // Allocation method + I NewNode(); + + // Insert method (inserts in order) + I Insert( T const &insert ); + void Insert( const T *pArray, int nItems ); + + // Find method + I Find( T const &search ) const; + + // Remove methods + void RemoveAt( I i ); + bool Remove( T const &remove ); + void RemoveAll( ); + + // Allocation, deletion + void FreeNode( I i ); + + // Iteration + I FirstInorder() const; + I NextInorder( I i ) const; + I PrevInorder( I i ) const; + I LastInorder() const; + + I FirstPreorder() const; + I NextPreorder( I i ) const; + I PrevPreorder( I i ) const; + I LastPreorder( ) const; + + I FirstPostorder() const; + I NextPostorder( I i ) const; + + // If you change the search key, this can be used to reinsert the + // element into the tree. + void Reinsert( I elem ); + + +protected: + enum NodeColor_t + { + RED = 0, + BLACK + }; + + struct Links_t + { + I m_Left; + I m_Right; + I m_Parent; + I m_Tag; + }; + + struct Node_t : public Links_t + { + T m_Data; + }; + + // Sets the children + void SetParent( I i, I parent ); + void SetLeftChild( I i, I child ); + void SetRightChild( I i, I child ); + void LinkToParent( I i, I parent, bool isLeft ); + + // Gets at the links + Links_t const &Links( I i ) const; + Links_t &Links( I i ); + + // Checks if a link is red or black + bool IsRed( I i ) const; + bool IsBlack( I i ) const; + + // Sets/gets node color + NodeColor_t Color( I i ) const; + void SetColor( I i, NodeColor_t c ); + + // operations required to preserve tree balance + void RotateLeft(I i); + void RotateRight(I i); + void InsertRebalance(I i); + void RemoveRebalance(I i); + + // Insertion, removal + I InsertAt( I parent, bool leftchild ); + + // copy constructors not allowed + CUtlRBTree( CUtlRBTree const &tree ); + + // Inserts a node into the tree, doesn't copy the data in. + void FindInsertionPosition( T const &insert, I &parent, bool &leftchild ); + + // Remove and add back an element in the tree. + void Unlink( I elem ); + void Link( I elem ); + + // Used for sorting. + LessFunc_t m_LessFunc; + + CUtlMemory m_Elements; + I m_Root; + I m_NumElements; + I m_FirstFree; + I m_TotalElements; + + Node_t* m_pElements; + + void ResetDbgInfo() + { + m_pElements = (Node_t*)m_Elements.Base(); + } +}; + + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template +CUtlRBTree::CUtlRBTree( int growSize, int initSize, LessFunc_t lessfunc ) : + m_Elements( growSize, initSize ), + m_LessFunc( lessfunc ), + m_Root( InvalidIndex() ), + m_NumElements( 0 ), m_TotalElements( 0 ), + m_FirstFree( InvalidIndex() ) +{ + ResetDbgInfo(); +} + +template +CUtlRBTree::~CUtlRBTree() +{ +} + +//----------------------------------------------------------------------------- +// gets particular elements +//----------------------------------------------------------------------------- + +template +inline T &CUtlRBTree::Element( I i ) +{ + return m_Elements[i].m_Data; +} + +template +inline T const &CUtlRBTree::Element( I i ) const +{ + return m_Elements[i].m_Data; +} + +template +inline T &CUtlRBTree::operator[]( I i ) +{ + return Element(i); +} + +template +inline T const &CUtlRBTree::operator[]( I i ) const +{ + return Element(i); +} + +//----------------------------------------------------------------------------- +// +// various accessors +// +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Gets the root +//----------------------------------------------------------------------------- + +template +inline I CUtlRBTree::Root() const +{ + return m_Root; +} + +//----------------------------------------------------------------------------- +// Num elements +//----------------------------------------------------------------------------- + +template +inline unsigned int CUtlRBTree::Count() const +{ + return (unsigned int)m_NumElements; +} + +//----------------------------------------------------------------------------- +// Max "size" of the vector +//----------------------------------------------------------------------------- + +template +inline I CUtlRBTree::MaxElement() const +{ + return (I)m_TotalElements; +} + + +//----------------------------------------------------------------------------- +// Gets the children +//----------------------------------------------------------------------------- + +template +inline I CUtlRBTree::Parent( I i ) const +{ + return Links(i).m_Parent; +} + +template +inline I CUtlRBTree::LeftChild( I i ) const +{ + return Links(i).m_Left; +} + +template +inline I CUtlRBTree::RightChild( I i ) const +{ + return Links(i).m_Right; +} + +//----------------------------------------------------------------------------- +// Tests if a node is a left or right child +//----------------------------------------------------------------------------- + +template +inline bool CUtlRBTree::IsLeftChild( I i ) const +{ + return LeftChild(Parent(i)) == i; +} + +template +inline bool CUtlRBTree::IsRightChild( I i ) const +{ + return RightChild(Parent(i)) == i; +} + + +//----------------------------------------------------------------------------- +// Tests if root or leaf +//----------------------------------------------------------------------------- + +template +inline bool CUtlRBTree::IsRoot( I i ) const +{ + return i == m_Root; +} + +template +inline bool CUtlRBTree::IsLeaf( I i ) const +{ + return (LeftChild(i) == InvalidIndex()) && (RightChild(i) == InvalidIndex()); +} + + +//----------------------------------------------------------------------------- +// Checks if a node is valid and in the tree +//----------------------------------------------------------------------------- + +template +inline bool CUtlRBTree::IsValidIndex( I i ) const +{ + return LeftChild(i) != i; +} + + +//----------------------------------------------------------------------------- +// Invalid index +//----------------------------------------------------------------------------- + +template +I CUtlRBTree::InvalidIndex() +{ + return (I)~0; +} + + +//----------------------------------------------------------------------------- +// returns the tree depth (not a very fast operation) +//----------------------------------------------------------------------------- + +template +inline int CUtlRBTree::Depth() const +{ + return Depth(Root()); +} + +//----------------------------------------------------------------------------- +// Sets the children +//----------------------------------------------------------------------------- + +template +inline void CUtlRBTree::SetParent( I i, I parent ) +{ + Links(i).m_Parent = parent; +} + +template +inline void CUtlRBTree::SetLeftChild( I i, I child ) +{ + Links(i).m_Left = child; +} + +template +inline void CUtlRBTree::SetRightChild( I i, I child ) +{ + Links(i).m_Right = child; +} + +//----------------------------------------------------------------------------- +// Gets at the links +//----------------------------------------------------------------------------- + +template +inline typename CUtlRBTree::Links_t const &CUtlRBTree::Links( I i ) const +{ + // Sentinel node, makes life easier + static Links_t s_Sentinel = + { + InvalidIndex(), InvalidIndex(), InvalidIndex(), CUtlRBTree::BLACK + }; + + return (i != InvalidIndex()) ? *(Links_t*)&m_Elements[i] : + *(Links_t*)&s_Sentinel; +} + +template +inline typename CUtlRBTree::Links_t &CUtlRBTree::Links( I i ) +{ + Assert(i != InvalidIndex()); + return *(Links_t *)&m_Elements[i]; +} + +//----------------------------------------------------------------------------- +// Checks if a link is red or black +//----------------------------------------------------------------------------- + +template +inline bool CUtlRBTree::IsRed( I i ) const +{ + return (Links(i).m_Tag == RED); +} + +template +inline bool CUtlRBTree::IsBlack( I i ) const +{ + return (Links(i).m_Tag == BLACK); +} + + +//----------------------------------------------------------------------------- +// Sets/gets node color +//----------------------------------------------------------------------------- + +template +inline typename CUtlRBTree::NodeColor_t CUtlRBTree::Color( I i ) const +{ + return (NodeColor_t)Links(i).m_Tag; +} + +template +inline void CUtlRBTree::SetColor( I i, typename CUtlRBTree::NodeColor_t c ) +{ + Links(i).m_Tag = (I)c; +} + +//----------------------------------------------------------------------------- +// Allocates/ deallocates nodes +//----------------------------------------------------------------------------- + +template +I CUtlRBTree::NewNode() +{ + I newElem; + + // Nothing in the free list; add. + if (m_FirstFree == InvalidIndex()) + { + if (m_Elements.NumAllocated() == m_TotalElements) + m_Elements.Grow(); + newElem = m_TotalElements++; + } + else + { + newElem = m_FirstFree; + m_FirstFree = RightChild(m_FirstFree); + } + +#ifdef _DEBUG + // reset links to invalid.... + Links_t &node = Links(newElem); + node.m_Left = node.m_Right = node.m_Parent = InvalidIndex(); +#endif + + Construct( &Element(newElem) ); + ResetDbgInfo(); + + return newElem; +} + +template +void CUtlRBTree::FreeNode( I i ) +{ + Assert( IsValidIndex(i) && (i != InvalidIndex()) ); + Destruct( &Element(i) ); + SetLeftChild( i, i ); // indicates it's in not in the tree + SetRightChild( i, m_FirstFree ); + m_FirstFree = i; +} + + +//----------------------------------------------------------------------------- +// Rotates node i to the left +//----------------------------------------------------------------------------- + +template +void CUtlRBTree::RotateLeft(I elem) +{ + I rightchild = RightChild(elem); + SetRightChild( elem, LeftChild(rightchild) ); + if (LeftChild(rightchild) != InvalidIndex()) + SetParent( LeftChild(rightchild), elem ); + + if (rightchild != InvalidIndex()) + SetParent( rightchild, Parent(elem) ); + if (!IsRoot(elem)) + { + if (IsLeftChild(elem)) + SetLeftChild( Parent(elem), rightchild ); + else + SetRightChild( Parent(elem), rightchild ); + } + else + m_Root = rightchild; + + SetLeftChild( rightchild, elem ); + if (elem != InvalidIndex()) + SetParent( elem, rightchild ); +} + + +//----------------------------------------------------------------------------- +// Rotates node i to the right +//----------------------------------------------------------------------------- + +template +void CUtlRBTree::RotateRight(I elem) +{ + I leftchild = LeftChild(elem); + SetLeftChild( elem, RightChild(leftchild) ); + if (RightChild(leftchild) != InvalidIndex()) + SetParent( RightChild(leftchild), elem ); + + if (leftchild != InvalidIndex()) + SetParent( leftchild, Parent(elem) ); + if (!IsRoot(elem)) + { + if (IsRightChild(elem)) + SetRightChild( Parent(elem), leftchild ); + else + SetLeftChild( Parent(elem), leftchild ); + } + else + m_Root = leftchild; + + SetRightChild( leftchild, elem ); + if (elem != InvalidIndex()) + SetParent( elem, leftchild ); +} + + +//----------------------------------------------------------------------------- +// Rebalances the tree after an insertion +//----------------------------------------------------------------------------- + +template +void CUtlRBTree::InsertRebalance(I elem) +{ + while ( !IsRoot(elem) && (Color(Parent(elem)) == RED) ) + { + I parent = Parent(elem); + I grandparent = Parent(parent); + + /* we have a violation */ + if (IsLeftChild(parent)) + { + I uncle = RightChild(grandparent); + if (IsRed(uncle)) + { + /* uncle is RED */ + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + /* uncle is BLACK */ + if (IsRightChild(elem)) + { + /* make x a left child, will change parent and grandparent */ + elem = parent; + RotateLeft(elem); + parent = Parent(elem); + grandparent = Parent(parent); + } + /* recolor and rotate */ + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateRight(grandparent); + } + } + else + { + /* mirror image of above code */ + I uncle = LeftChild(grandparent); + if (IsRed(uncle)) + { + /* uncle is RED */ + SetColor(parent, BLACK); + SetColor(uncle, BLACK); + SetColor(grandparent, RED); + elem = grandparent; + } + else + { + /* uncle is BLACK */ + if (IsLeftChild(elem)) + { + /* make x a right child, will change parent and grandparent */ + elem = parent; + RotateRight(parent); + parent = Parent(elem); + grandparent = Parent(parent); + } + /* recolor and rotate */ + SetColor(parent, BLACK); + SetColor(grandparent, RED); + RotateLeft(grandparent); + } + } + } + SetColor( m_Root, BLACK ); +} + + +//----------------------------------------------------------------------------- +// Insert a node into the tree +//----------------------------------------------------------------------------- + +template +I CUtlRBTree::InsertAt( I parent, bool leftchild ) +{ + I i = NewNode(); + LinkToParent( i, parent, leftchild ); + ++m_NumElements; + return i; +} + +template +void CUtlRBTree::LinkToParent( I i, I parent, bool isLeft ) +{ + Links_t &elem = Links(i); + elem.m_Parent = parent; + elem.m_Left = elem.m_Right = InvalidIndex(); + elem.m_Tag = RED; + + /* insert node in tree */ + if (parent != InvalidIndex()) + { + if (isLeft) + Links(parent).m_Left = i; + else + Links(parent).m_Right = i; + } + else + { + m_Root = i; + } + + InsertRebalance(i); + + Assert(IsValid()); +} + +//----------------------------------------------------------------------------- +// Rebalance the tree after a deletion +//----------------------------------------------------------------------------- + +template +void CUtlRBTree::RemoveRebalance(I elem) +{ + while (elem != m_Root && IsBlack(elem)) + { + I parent = Parent(elem); + + // If elem is the left child of the parent + if (elem == LeftChild(parent)) + { + // Get our sibling + I sibling = RightChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateLeft(parent); + + // We may have a new parent now + parent = Parent(elem); + sibling = RightChild(parent); + } + if ( (IsBlack(LeftChild(sibling))) && (IsBlack(RightChild(sibling))) ) + { + if (sibling != InvalidIndex()) + SetColor(sibling, RED); + elem = parent; + } + else + { + if (IsBlack(RightChild(sibling))) + { + SetColor(LeftChild(sibling), BLACK); + SetColor(sibling, RED); + RotateRight(sibling); + + // rotation may have changed this + parent = Parent(elem); + sibling = RightChild(parent); + } + SetColor( sibling, Color(parent) ); + SetColor( parent, BLACK ); + SetColor( RightChild(sibling), BLACK ); + RotateLeft( parent ); + elem = m_Root; + } + } + else + { + // Elem is the right child of the parent + I sibling = LeftChild(parent); + if (IsRed(sibling)) + { + SetColor(sibling, BLACK); + SetColor(parent, RED); + RotateRight(parent); + + // We may have a new parent now + parent = Parent(elem); + sibling = LeftChild(parent); + } + if ( (IsBlack(RightChild(sibling))) && (IsBlack(LeftChild(sibling))) ) + { + if (sibling != InvalidIndex()) + SetColor( sibling, RED ); + elem = parent; + } + else + { + if (IsBlack(LeftChild(sibling))) + { + SetColor( RightChild(sibling), BLACK ); + SetColor( sibling, RED ); + RotateLeft( sibling ); + + // rotation may have changed this + parent = Parent(elem); + sibling = LeftChild(parent); + } + SetColor( sibling, Color(parent) ); + SetColor( parent, BLACK ); + SetColor( LeftChild(sibling), BLACK ); + RotateRight( parent ); + elem = m_Root; + } + } + } + SetColor( elem, BLACK ); +} + +template +void CUtlRBTree::Unlink( I elem ) +{ + if ( elem != InvalidIndex() ) + { + I x, y; + + if ((LeftChild(elem) == InvalidIndex()) || + (RightChild(elem) == InvalidIndex())) + { + /* y has a NIL node as a child */ + y = elem; + } + else + { + /* find tree successor with a NIL node as a child */ + y = RightChild(elem); + while (LeftChild(y) != InvalidIndex()) + y = LeftChild(y); + } + + /* x is y's only child */ + if (LeftChild(y) != InvalidIndex()) + x = LeftChild(y); + else + x = RightChild(y); + + /* remove y from the parent chain */ + if (x != InvalidIndex()) + SetParent( x, Parent(y) ); + if (!IsRoot(y)) + { + if (IsLeftChild(y)) + SetLeftChild( Parent(y), x ); + else + SetRightChild( Parent(y), x ); + } + else + m_Root = x; + + // need to store this off now, we'll be resetting y's color + NodeColor_t ycolor = Color(y); + if (y != elem) + { + // Standard implementations copy the data around, we cannot here. + // Hook in y to link to the same stuff elem used to. + SetParent( y, Parent(elem) ); + SetRightChild( y, RightChild(elem) ); + SetLeftChild( y, LeftChild(elem) ); + + if (!IsRoot(elem)) + if (IsLeftChild(elem)) + SetLeftChild( Parent(elem), y ); + else + SetRightChild( Parent(elem), y ); + else + m_Root = y; + + if (LeftChild(y) != InvalidIndex()) + SetParent( LeftChild(y), y ); + if (RightChild(y) != InvalidIndex()) + SetParent( RightChild(y), y ); + + SetColor( y, Color(elem) ); + } + + if ((x != InvalidIndex()) && (ycolor == BLACK)) + RemoveRebalance(x); + } +} + +template +void CUtlRBTree::Link( I elem ) +{ + if ( elem != InvalidIndex() ) + { + I parent; + bool leftchild; + + FindInsertionPosition( Element( elem ), parent, leftchild ); + + LinkToParent( elem, parent, leftchild ); + } +} + +//----------------------------------------------------------------------------- +// Delete a node from the tree +//----------------------------------------------------------------------------- + +template +void CUtlRBTree::RemoveAt(I elem) +{ + if ( elem != InvalidIndex() ) + { + Unlink( elem ); + + FreeNode(elem); + --m_NumElements; + } +} + + +//----------------------------------------------------------------------------- +// remove a node in the tree +//----------------------------------------------------------------------------- + +template bool CUtlRBTree::Remove( T const &search ) +{ + I node = Find( search ); + if (node != InvalidIndex()) + { + RemoveAt(node); + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Removes all nodes from the tree +//----------------------------------------------------------------------------- + +template +void CUtlRBTree::RemoveAll() +{ + // Just iterate through the whole list and add to free list + // much faster than doing all of the rebalancing + // also, do it so the free list is pointing to stuff in order + // to get better cache coherence when re-adding stuff to this tree. + I prev = InvalidIndex(); + for (int i = (int)m_TotalElements; --i >= 0; ) + { + I idx = (I)i; + if (IsValidIndex(idx)) + Destruct( &Element(idx) ); + SetRightChild( idx, prev ); + SetLeftChild( idx, idx ); + prev = idx; + } + m_FirstFree = m_TotalElements ? (I)0 : InvalidIndex(); + m_Root = InvalidIndex(); + m_NumElements = 0; +} + + +//----------------------------------------------------------------------------- +// iteration +//----------------------------------------------------------------------------- + +template +I CUtlRBTree::FirstInorder() const +{ + I i = m_Root; + while (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + return i; +} + +template +I CUtlRBTree::NextInorder( I i ) const +{ + Assert(IsValidIndex(i)); + + if (RightChild(i) != InvalidIndex()) + { + i = RightChild(i); + while (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + return i; + } + + I parent = Parent(i); + while (IsRightChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template +I CUtlRBTree::PrevInorder( I i ) const +{ + Assert(IsValidIndex(i)); + + if (LeftChild(i) != InvalidIndex()) + { + i = LeftChild(i); + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + return i; + } + + I parent = Parent(i); + while (IsLeftChild(i)) + { + i = parent; + if (i == InvalidIndex()) break; + parent = Parent(i); + } + return parent; +} + +template +I CUtlRBTree::LastInorder() const +{ + I i = m_Root; + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + return i; +} + +template +I CUtlRBTree::FirstPreorder() const +{ + return m_Root; +} + +template +I CUtlRBTree::NextPreorder( I i ) const +{ + if (LeftChild(i) != InvalidIndex()) + return LeftChild(i); + + if (RightChild(i) != InvalidIndex()) + return RightChild(i); + + I parent = Parent(i); + while( parent != InvalidIndex()) + { + if (IsLeftChild(i) && (RightChild(parent) != InvalidIndex())) + return RightChild(parent); + i = parent; + parent = Parent(parent); + } + return InvalidIndex(); +} + +template +I CUtlRBTree::PrevPreorder( I i ) const +{ + Assert(0); // not implemented yet + return InvalidIndex(); +} + +template +I CUtlRBTree::LastPreorder() const +{ + I i = m_Root; + while (1) + { + while (RightChild(i) != InvalidIndex()) + i = RightChild(i); + + if (LeftChild(i) != InvalidIndex()) + i = LeftChild(i); + else + break; + } + return i; +} + +template +I CUtlRBTree::FirstPostorder() const +{ + I i = m_Root; + while (!IsLeaf(i)) + { + if (LeftChild(i)) + i = LeftChild(i); + else + i = RightChild(i); + } + return i; +} + +template +I CUtlRBTree::NextPostorder( I i ) const +{ + I parent = Parent(i); + if (parent == InvalidIndex()) + return InvalidIndex(); + + if (IsRightChild(i)) + return parent; + + if (RightChild(parent) == InvalidIndex()) + return parent; + + i = RightChild(parent); + while (!IsLeaf(i)) + { + if (LeftChild(i)) + i = LeftChild(i); + else + i = RightChild(i); + } + return i; +} + + +template +void CUtlRBTree::Reinsert( I elem ) +{ + Unlink( elem ); + Link( elem ); +} + + +//----------------------------------------------------------------------------- +// returns the tree depth (not a very fast operation) +//----------------------------------------------------------------------------- + +template +int CUtlRBTree::Depth( I node ) const +{ + if (node == InvalidIndex()) + return 0; + + int depthright = Depth( RightChild(node) ); + int depthleft = Depth( LeftChild(node) ); + return max(depthright, depthleft) + 1; +} + + +//----------------------------------------------------------------------------- +// Makes sure the tree is valid after every operation +//----------------------------------------------------------------------------- + +template +bool CUtlRBTree::IsValid() const +{ + if ( !Count() ) + return true; + + if (( Root() >= MaxElement()) || ( Parent( Root() ) != InvalidIndex() )) + goto InvalidTree; + +#ifdef UTLTREE_PARANOID + + // First check to see that mNumEntries matches reality. + // count items on the free list + int numFree = 0; + int curr = m_FirstFree; + while (curr != InvalidIndex()) + { + ++numFree; + curr = RightChild(curr); + if ( (curr > MaxElement()) && (curr != InvalidIndex()) ) + goto InvalidTree; + } + if (MaxElement() - numFree != Count()) + goto InvalidTree; + + // iterate over all elements, looking for validity + // based on the self pointers + int numFree2 = 0; + for (curr = 0; curr < MaxElement(); ++curr) + { + if (!IsValidIndex(curr)) + ++numFree2; + else + { + int right = RightChild(curr); + int left = LeftChild(curr); + if ((right == left) && (right != InvalidIndex()) ) + goto InvalidTree; + + if (right != InvalidIndex()) + { + if (!IsValidIndex(right)) + goto InvalidTree; + if (Parent(right) != curr) + goto InvalidTree; + if (IsRed(curr) && IsRed(right)) + goto InvalidTree; + } + + if (left != InvalidIndex()) + { + if (!IsValidIndex(left)) + goto InvalidTree; + if (Parent(left) != curr) + goto InvalidTree; + if (IsRed(curr) && IsRed(left)) + goto InvalidTree; + } + } + } + if (numFree2 != numFree) + goto InvalidTree; + +#endif // UTLTREE_PARANOID + + return true; + +InvalidTree: + return false; +} + + +//----------------------------------------------------------------------------- +// Sets the less func +//----------------------------------------------------------------------------- + +template +void CUtlRBTree::SetLessFunc( typename CUtlRBTree::LessFunc_t func ) +{ + if (!m_LessFunc) + m_LessFunc = func; + else + { + // need to re-sort the tree here.... + Assert(0); + } +} + + +//----------------------------------------------------------------------------- +// inserts a node into the tree +//----------------------------------------------------------------------------- + +// Inserts a node into the tree, doesn't copy the data in. +template +void CUtlRBTree::FindInsertionPosition( T const &insert, I &parent, bool &leftchild ) +{ + Assert( m_LessFunc ); + + /* find where node belongs */ + I current = m_Root; + parent = InvalidIndex(); + leftchild = false; + while (current != InvalidIndex()) + { + parent = current; + if (m_LessFunc( insert, Element(current) )) + { + leftchild = true; current = LeftChild(current); + } + else + { + leftchild = false; current = RightChild(current); + } + } +} + +template +I CUtlRBTree::Insert( T const &insert ) +{ + // use copy constructor to copy it in + I parent; + bool leftchild; + FindInsertionPosition( insert, parent, leftchild ); + I newNode = InsertAt( parent, leftchild ); + CopyConstruct( &Element( newNode ), insert ); + return newNode; +} + + +template +void CUtlRBTree::Insert( const T *pArray, int nItems ) +{ + while ( nItems-- ) + { + Insert( *pArray++ ); + } +} + +//----------------------------------------------------------------------------- +// finds a node in the tree +//----------------------------------------------------------------------------- + +template +I CUtlRBTree::Find( T const &search ) const +{ + Assert( m_LessFunc ); + + I current = m_Root; + while (current != InvalidIndex()) + { + if (m_LessFunc( search, Element(current) )) + current = LeftChild(current); + else if (m_LessFunc( Element(current), search )) + current = RightChild(current); + else + break; + } + return current; +} + + + + + +#endif // UTLRBTREE_H diff --git a/rehlds/public/utlvector.h b/rehlds/public/utlvector.h new file mode 100644 index 0000000..afa7277 --- /dev/null +++ b/rehlds/public/utlvector.h @@ -0,0 +1,594 @@ +//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// $Header: $ +// $NoKeywords: $ +// +// A growable memory class. +//============================================================================= + +#ifndef UTLVECTOR_H +#define UTLVECTOR_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utlmemory.h" +#include "tier0/platform.h" + +/* <27e3b> ../public/UtlVector.h:37 */ +template +class CUtlVector +{ +public: + typedef T ElemType_t; + + // constructor, destructor + CUtlVector( int growSize = 0, int initSize = 0 ); + CUtlVector( T* pMemory, int numElements ); + ~CUtlVector(); + + // Copy the array. + CUtlVector& operator=( const CUtlVector &other ); + + // element access + T& operator[]( int i ); + T const& operator[]( int i ) const; + T& Element( int i ); + T const& Element( int i ) const; + + // Gets the base address (can change when adding elements!) + T* Base(); + T const* Base() const; + + // Returns the number of elements in the vector + // SIZE IS DEPRECATED! + int Count() const; + int Size() const; // don't use me! + + // Is element index valid? + bool IsValidIndex( int i ) const; + static int InvalidIndex( void ); + + // Adds an element, uses default constructor + int AddToHead(); + int AddToTail(); + int InsertBefore( int elem ); + int InsertAfter( int elem ); + + // Adds an element, uses copy constructor + int AddToHead( T const& src ); + int AddToTail( T const& src ); + int InsertBefore( int elem, T const& src ); + int InsertAfter( int elem, T const& src ); + + // Adds multiple elements, uses default constructor + int AddMultipleToHead( int num ); + int AddMultipleToTail( int num, const T *pToCopy=NULL ); + int InsertMultipleBefore( int elem, int num, const T *pToCopy=NULL ); // If pToCopy is set, then it's an array of length 'num' and + int InsertMultipleAfter( int elem, int num ); + + // Calls RemoveAll() then AddMultipleToTail. + void SetSize( int size ); + void SetCount( int count ); + + // Calls SetSize and copies each element. + void CopyArray( T const *pArray, int size ); + + // Add the specified array to the tail. + int AddVectorToTail( CUtlVector const &src ); + + // Finds an element (element needs operator== defined) + int Find( T const& src ) const; + + bool HasElement( T const& src ); + + // Makes sure we have enough memory allocated to store a requested # of elements + void EnsureCapacity( int num ); + + // Makes sure we have at least this many elements + void EnsureCount( int num ); + + // Element removal + void FastRemove( int elem ); // doesn't preserve order + void Remove( int elem ); // preserves order, shifts elements + void FindAndRemove( T const& src ); // removes first occurrence of src, preserves order, shifts elements + void RemoveMultiple( int elem, int num ); // preserves order, shifts elements + void RemoveAll(); // doesn't deallocate memory + + // Memory deallocation + void Purge(); + + // Purges the list and calls delete on each element in it. + void PurgeAndDeleteElements(); + + // Set the size by which it grows when it needs to allocate more memory. + void SetGrowSize( int size ); + +protected: + // Can't copy this unless we explicitly do it! + CUtlVector( CUtlVector const& vec ) { assert(0); + } + + // Grows the vector + void GrowVector( int num = 1 ); + + // Shifts elements.... + void ShiftElementsRight( int elem, int num = 1 ); + void ShiftElementsLeft( int elem, int num = 1 ); + + // For easier access to the elements through the debugger + void ResetDbgInfo(); + + CUtlMemory m_Memory; + int m_Size; + + // For easier access to the elements through the debugger + // it's in release builds so this can be used in libraries correctly + T *m_pElements; +}; + + +//----------------------------------------------------------------------------- +// For easier access to the elements through the debugger +//----------------------------------------------------------------------------- + +template< class T > +inline void CUtlVector::ResetDbgInfo() +{ + m_pElements = m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- + +template< class T > +inline CUtlVector::CUtlVector( int growSize, int initSize ) : + m_Memory(growSize, initSize), m_Size(0) +{ + ResetDbgInfo(); +} + +template< class T > +inline CUtlVector::CUtlVector( T* pMemory, int numElements ) : + m_Memory(pMemory, numElements), m_Size(0) +{ + ResetDbgInfo(); +} + +template< class T > +inline CUtlVector::~CUtlVector() +{ + Purge(); +} + +template +inline CUtlVector& CUtlVector::operator=( const CUtlVector &other ) +{ + CopyArray( other.Base(), other.Count() ); + return *this; +} + +//----------------------------------------------------------------------------- +// element access +//----------------------------------------------------------------------------- + +template< class T > +inline T& CUtlVector::operator[]( int i ) +{ + assert( IsValidIndex(i) ); + return m_Memory[i]; +} + +template< class T > +inline T const& CUtlVector::operator[]( int i ) const +{ + assert( IsValidIndex(i) ); + return m_Memory[i]; +} + +template< class T > +inline T& CUtlVector::Element( int i ) +{ + assert( IsValidIndex(i) ); + return m_Memory[i]; +} + +template< class T > +inline T const& CUtlVector::Element( int i ) const +{ + assert( IsValidIndex(i) ); + return m_Memory[i]; +} + + +//----------------------------------------------------------------------------- +// Gets the base address (can change when adding elements!) +//----------------------------------------------------------------------------- + +template< class T > +inline T* CUtlVector::Base() +{ + return m_Memory.Base(); +} + +template< class T > +inline T const* CUtlVector::Base() const +{ + return m_Memory.Base(); +} + +//----------------------------------------------------------------------------- +// Count +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::Size() const +{ + return m_Size; +} + +template< class T > +inline int CUtlVector::Count() const +{ + return m_Size; +} + + +//----------------------------------------------------------------------------- +// Is element index valid? +//----------------------------------------------------------------------------- + +template< class T > +inline bool CUtlVector::IsValidIndex( int i ) const +{ + return (i >= 0) && (i < m_Size); +} + + +//----------------------------------------------------------------------------- +// Returns in invalid index +//----------------------------------------------------------------------------- +template< class T > +inline int CUtlVector::InvalidIndex( void ) +{ + return -1; +} + + +//----------------------------------------------------------------------------- +// Grows the vector +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::GrowVector( int num ) +{ + if (m_Size + num - 1 >= m_Memory.NumAllocated()) + { + m_Memory.Grow( m_Size + num - m_Memory.NumAllocated() ); + } + + m_Size += num; + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have enough memory allocated to store a requested # of elements +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::EnsureCapacity( int num ) +{ + m_Memory.EnsureCapacity(num); + ResetDbgInfo(); +} + + +//----------------------------------------------------------------------------- +// Makes sure we have at least this many elements +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::EnsureCount( int num ) +{ + if (Count() < num) + AddMultipleToTail( num - Count() ); +} + + +//----------------------------------------------------------------------------- +// Shifts elements +//----------------------------------------------------------------------------- +template< class T > +void CUtlVector::ShiftElementsRight( int elem, int num ) +{ + assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 )); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + memmove( &Element(elem+num), &Element(elem), numToMove * sizeof(T) ); +} + +template< class T > +void CUtlVector::ShiftElementsLeft( int elem, int num ) +{ + assert( IsValidIndex(elem) || ( m_Size == 0 ) || ( num == 0 )); + int numToMove = m_Size - elem - num; + if ((numToMove > 0) && (num > 0)) + { + memmove( &Element(elem), &Element(elem+num), numToMove * sizeof(T) ); + +#ifdef _DEBUG + memset( &Element(m_Size-num), 0xDD, num * sizeof(T) ); +#endif + } +} + +//----------------------------------------------------------------------------- +// Adds an element, uses default constructor +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::AddToHead() +{ + return InsertBefore(0); +} + +template< class T > +inline int CUtlVector::AddToTail() +{ + return InsertBefore( m_Size ); +} + +template< class T > +inline int CUtlVector::InsertAfter( int elem ) +{ + return InsertBefore( elem + 1 ); +} + +template< class T > +int CUtlVector::InsertBefore( int elem ) +{ + // Can insert at the end + assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(); + ShiftElementsRight(elem); + Construct( &Element(elem) ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds an element, uses copy constructor +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::AddToHead( T const& src ) +{ + return InsertBefore( 0, src ); +} + +template< class T > +inline int CUtlVector::AddToTail( T const& src ) +{ + return InsertBefore( m_Size, src ); +} + +template< class T > +inline int CUtlVector::InsertAfter( int elem, T const& src ) +{ + return InsertBefore( elem + 1, src ); +} + +template< class T > +int CUtlVector::InsertBefore( int elem, T const& src ) +{ + // Can insert at the end + assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(); + ShiftElementsRight(elem); + CopyConstruct( &Element(elem), src ); + return elem; +} + + +//----------------------------------------------------------------------------- +// Adds multiple elements, uses default constructor +//----------------------------------------------------------------------------- + +template< class T > +inline int CUtlVector::AddMultipleToHead( int num ) +{ + return InsertMultipleBefore( 0, num ); +} + +template< class T > +inline int CUtlVector::AddMultipleToTail( int num, const T *pToCopy ) +{ + return InsertMultipleBefore( m_Size, num, pToCopy ); +} + +template< class T > +int CUtlVector::InsertMultipleAfter( int elem, int num ) +{ + return InsertMultipleBefore( elem + 1, num ); +} + + +template< class T > +void CUtlVector::SetCount( int count ) +{ + RemoveAll(); + AddMultipleToTail( count ); +} + +template< class T > +inline void CUtlVector::SetSize( int size ) +{ + SetCount( size ); +} + +template< class T > +void CUtlVector::CopyArray( T const *pArray, int size ) +{ + SetSize( size ); + for( int i=0; i < size; i++ ) + (*this)[i] = pArray[i]; +} + +template< class T > +int CUtlVector::AddVectorToTail( CUtlVector const &src ) +{ + int base = Count(); + + // Make space. + AddMultipleToTail( src.Count() ); + + // Copy the elements. + for ( int i=0; i < src.Count(); i++ ) + (*this)[base + i] = src[i]; + + return base; +} + +template< class T > +inline int CUtlVector::InsertMultipleBefore( int elem, int num, const T *pToInsert ) +{ + if( num == 0 ) + return elem; + + // Can insert at the end + assert( (elem == Count()) || IsValidIndex(elem) ); + + GrowVector(num); + ShiftElementsRight(elem, num); + + // Invoke default constructors + for (int i = 0; i < num; ++i) + Construct( &Element(elem+i) ); + + // Copy stuff in? + if ( pToInsert ) + { + for ( int i=0; i < num; i++ ) + { + Element( elem+i ) = pToInsert[i]; + } + } + + return elem; +} + +//----------------------------------------------------------------------------- +// Finds an element (element needs operator== defined) +//----------------------------------------------------------------------------- +template< class T > +int CUtlVector::Find( T const& src ) const +{ + for ( int i = 0; i < Count(); ++i ) + { + if (Element(i) == src) + return i; + } + return -1; +} + +template< class T > +bool CUtlVector::HasElement( T const& src ) +{ + return ( Find(src) >= 0 ); +} + +//----------------------------------------------------------------------------- +// Element removal +//----------------------------------------------------------------------------- + +template< class T > +void CUtlVector::FastRemove( int elem ) +{ + assert( IsValidIndex(elem) ); + + Destruct( &Element(elem) ); + if (m_Size > 0) + { + memcpy( &Element(elem), &Element(m_Size-1), sizeof(T) ); + --m_Size; + } +} + +template< class T > +void CUtlVector::Remove( int elem ) +{ + Destruct( &Element(elem) ); + ShiftElementsLeft(elem); + --m_Size; +} + +template< class T > +void CUtlVector::FindAndRemove( T const& src ) +{ + int elem = Find( src ); + if ( elem != -1 ) + { + Remove( elem ); + } +} + +template< class T > +void CUtlVector::RemoveMultiple( int elem, int num ) +{ + assert( IsValidIndex(elem) ); + assert( elem + num <= Count() ); + + for (int i = elem + num; --i >= elem; ) + Destruct(&Element(i)); + + ShiftElementsLeft(elem, num); + m_Size -= num; +} + +template< class T > +void CUtlVector::RemoveAll() +{ + for (int i = m_Size; --i >= 0; ) + Destruct(&Element(i)); + + m_Size = 0; +} + + +//----------------------------------------------------------------------------- +// Memory deallocation +//----------------------------------------------------------------------------- + +template< class T > +void CUtlVector::Purge() +{ + RemoveAll(); + m_Memory.Purge( ); + ResetDbgInfo(); +} + + +template +inline void CUtlVector::PurgeAndDeleteElements() +{ + for( int i=0; i < m_Size; i++ ) + delete Element(i); + + Purge(); +} + + +template< class T > +void CUtlVector::SetGrowSize( int size ) +{ + m_Memory.SetGrowSize( size ); +} + + +#endif // CCVECTOR_H diff --git a/rehlds/rehlds/FlightRecorderImpl.cpp b/rehlds/rehlds/FlightRecorderImpl.cpp new file mode 100644 index 0000000..e1af095 --- /dev/null +++ b/rehlds/rehlds/FlightRecorderImpl.cpp @@ -0,0 +1,224 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ +#include "precompiled.h" + +CRehldsFlightRecorder::CRehldsFlightRecorder() { + m_MetaRegionPtr = (uint8_t*) sys_allocmem(META_REGION_SIZE); + m_DataRegionPtr = (uint8_t*) sys_allocmem(DATA_REGION_SIZE); + + if (!m_MetaRegionPtr || !m_DataRegionPtr) { + rehlds_syserror("%s: direct allocation failed", __FUNCTION__); + } + + //initialize meta region header + char* metaPos = (char*)m_MetaRegionPtr; + const char* metaSignature = "REHLDS_FLIGHTREC_META"; + metaPos += sprintf(metaPos, "%s%s%s:", metaSignature, metaSignature, metaSignature); + + m_pMetaHeader = (meta_header*)metaPos; + metaPos += sizeof(meta_header); + m_pRecorderState = (recorder_state*)metaPos; + metaPos += sizeof(recorder_state); + + if ((metaPos - (char*)m_MetaRegionPtr) > META_REGION_HEADER) { + rehlds_syserror("%s: Meta header overflow", __FUNCTION__); + } + + //initialize data region header + char* dataPos = (char*)m_DataRegionPtr; + const char* dataSignature = "REHLDS_FLIGHTREC_DATA"; + dataPos += sprintf(dataPos, "%s%s%s:", dataSignature, dataSignature, dataSignature); + + m_pDataHeader = (data_header*)dataPos; + dataPos += sizeof(data_header); + + if ((dataPos - (char*)m_pDataHeader) > DATA_REGION_HEADER) { + rehlds_syserror("%s: Data header overflow", __FUNCTION__); + } + + InitHeadersContent(); + + m_MetaRegionPtr += META_REGION_HEADER; + m_DataRegionPtr += DATA_REGION_HEADER; +} + +void CRehldsFlightRecorder::InitHeadersContent() { + m_pMetaHeader->version = FLIGHT_RECORDER_VERSION; + m_pMetaHeader->metaRegionPos = 0; + m_pMetaHeader->numMessages = 0; + + m_pRecorderState->wpos = 0; + m_pRecorderState->lastMsgBeginPos = 0xFFFFFFFF; + m_pRecorderState->curMessage = 0; + + m_pDataHeader->version = FLIGHT_RECORDER_VERSION; + m_pDataHeader->prevItrLastPos = 0xFFFFFFFF; +} + +void CRehldsFlightRecorder::MoveToStart() { + if (m_pRecorderState->curMessage == 0) { + m_pDataHeader->prevItrLastPos = m_pRecorderState->wpos; + m_pRecorderState->wpos = 0; + } else { + memcpy(m_DataRegionPtr, m_DataRegionPtr + m_pRecorderState->lastMsgBeginPos, m_pRecorderState->wpos - m_pRecorderState->lastMsgBeginPos); + m_pRecorderState->wpos -= m_pRecorderState->lastMsgBeginPos; + m_pDataHeader->prevItrLastPos = m_pRecorderState->lastMsgBeginPos; + m_pRecorderState->lastMsgBeginPos = 0; + } +} + +void CRehldsFlightRecorder::StartMessage(uint16_t msg, bool entrance) { + if (msg == 0 || msg > m_pMetaHeader->numMessages) { + rehlds_syserror("%s: Invalid message id %u", __FUNCTION__, msg); + } + + if (entrance) { + msg = msg | 0x8000; + } + + if (m_pRecorderState->curMessage != 0) { + rehlds_syserror("%s: overlapping messages", __FUNCTION__); + } + + unsigned int sz = DATA_REGION_MAIN_SIZE - m_pRecorderState->wpos; + if (sz < 6) { + MoveToStart(); + } + + + + m_pRecorderState->curMessage = msg; + m_pRecorderState->lastMsgBeginPos = m_pRecorderState->wpos; + *(uint16_t*)(m_DataRegionPtr + m_pRecorderState->wpos) = msg; + m_pRecorderState->wpos += 2; +} + +void CRehldsFlightRecorder::EndMessage(uint16_t msg, bool entrance) { + if (entrance) { + msg = msg | 0x8000; + } + + if (m_pRecorderState->curMessage != msg) { + rehlds_syserror("%s: invalid message %u", __FUNCTION__, msg); + } + + unsigned int freeSz = DATA_REGION_MAIN_SIZE - m_pRecorderState->wpos; + if (freeSz < 2) { + MoveToStart(); + } + + unsigned int msgSize = m_pRecorderState->wpos - m_pRecorderState->lastMsgBeginPos; + if (msgSize > MSG_MAX_SIZE) { + rehlds_syserror("%s: too big message %u; size%u", __FUNCTION__, msg, msgSize); + } + *(uint16_t*)(m_DataRegionPtr + m_pRecorderState->wpos) = msgSize; + m_pRecorderState->wpos += 2; + + m_pRecorderState->curMessage = 0; +} + +void CRehldsFlightRecorder::CheckSize(unsigned int wantToWriteLen) { + unsigned int msgSize = m_pRecorderState->wpos - m_pRecorderState->lastMsgBeginPos; + if (msgSize + wantToWriteLen > MSG_MAX_SIZE) { + rehlds_syserror("%s: too big message %u; size%u", __FUNCTION__, m_pRecorderState->curMessage, msgSize); + } +} + +void CRehldsFlightRecorder::WriteBuffer(const void* data, unsigned int len) { + if (m_pRecorderState->curMessage == 0) { + rehlds_syserror("%s: Could not write, invalid state", __FUNCTION__); + } + + CheckSize(len); + unsigned int freeSz = DATA_REGION_MAIN_SIZE - m_pRecorderState->wpos; + if (freeSz < len) { + MoveToStart(); + } + + memcpy(m_DataRegionPtr + m_pRecorderState->wpos, data, len); + m_pRecorderState->wpos += len; +} + +void CRehldsFlightRecorder::WriteString(const char* s) { + WriteBuffer(s, strlen(s) + 1); +} + +void CRehldsFlightRecorder::WriteInt8(int8_t v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteUInt8(uint8_t v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteInt16(int16_t v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteUInt16(uint16_t v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteInt32(int32_t v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteUInt32(uint32_t v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteInt64(int64_t v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteUInt64(uint64_t v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteFloat(float v) { + WritePrimitive(v); +} + +void CRehldsFlightRecorder::WriteDouble(double v) { + WritePrimitive(v); +} + +uint16_t CRehldsFlightRecorder::RegisterMessage(const char* module, const char *message, unsigned int version, bool inOut) { + if (m_pMetaHeader->numMessages >= MSG_MAX_ID) { + rehlds_syserror("%s: can't register message; limit exceeded", __FUNCTION__); + } + + uint16_t msgId = ++m_pMetaHeader->numMessages; + + sizebuf_t sb; + sb.buffername = "FlightRecorded Meta"; + sb.cursize = m_pMetaHeader->metaRegionPos; + sb.maxsize = META_REGION_MAIN_SIZE; + sb.flags = 0; + sb.data = m_MetaRegionPtr; + + MSG_WriteShort(&sb, msgId); + MSG_WriteString(&sb, module); + MSG_WriteString(&sb, message); + MSG_WriteLong(&sb, version); + MSG_WriteChar(&sb, inOut ? 1 : 0); + + m_pMetaHeader->metaRegionPos = sb.cursize; + + return msgId; +} diff --git a/rehlds/rehlds/FlightRecorderImpl.h b/rehlds/rehlds/FlightRecorderImpl.h new file mode 100644 index 0000000..514d7c3 --- /dev/null +++ b/rehlds/rehlds/FlightRecorderImpl.h @@ -0,0 +1,110 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ +#pragma once +#include "osconfig.h" +#include "FlightRecorder.h" + +class CRehldsFlightRecorder : public IRehldsFlightRecorder { +public: + static const unsigned int FLIGHT_RECORDER_VERSION = 1; + + static const unsigned int META_REGION_SIZE = 128 * 1024; + static const unsigned int META_REGION_HEADER = 128; + static const unsigned int META_REGION_MAIN_SIZE = META_REGION_SIZE - META_REGION_HEADER; + + static const unsigned int DATA_REGION_SIZE = 768 * 1024; + static const unsigned int DATA_REGION_HEADER = 128; + static const unsigned int DATA_REGION_MAIN_SIZE = DATA_REGION_SIZE - DATA_REGION_HEADER; + + static const unsigned int MSG_MAX_SIZE = 0x7FF0; + static const unsigned int MSG_MAX_ID = 0x7FF0; + +private: + +#pragma pack(push, 1) + struct recorder_state { + unsigned int wpos; + unsigned int lastMsgBeginPos; + uint16_t curMessage; + }; + + struct meta_header { + unsigned int version; + unsigned int numMessages; + unsigned int metaRegionPos; + }; + + struct data_header { + unsigned int version; + unsigned int prevItrLastPos; + }; +#pragma pack(pop) + + uint8_t* m_MetaRegionPtr; + uint8_t* m_DataRegionPtr; + meta_header* m_pMetaHeader; + recorder_state* m_pRecorderState; + data_header* m_pDataHeader; + + void InitHeadersContent(); + void MoveToStart(); + + template + void WritePrimitive(T v) { + if (m_pRecorderState->curMessage == 0) { + rehlds_syserror("%s: Could not write, invalid state", __FUNCTION__); + } + + CheckSize(sizeof(T)); + unsigned int freeSz = DATA_REGION_MAIN_SIZE - m_pRecorderState->wpos; + if (freeSz < sizeof(T)) { + MoveToStart(); + } + + *(T*)(m_DataRegionPtr + m_pRecorderState->wpos) = v; + m_pRecorderState->wpos += sizeof(T); + } + + void CheckSize(unsigned int wantToWriteLen); + +public: + CRehldsFlightRecorder(); + + virtual void StartMessage(uint16_t msg, bool entrance); + virtual void EndMessage(uint16_t msg, bool entrance); + + virtual void WriteInt8(int8_t v); + virtual void WriteUInt8(uint8_t v); + + virtual void WriteInt16(int16_t v); + virtual void WriteUInt16(uint16_t v); + + virtual void WriteInt32(int32_t v); + virtual void WriteUInt32(uint32_t v); + + virtual void WriteInt64(int64_t v); + virtual void WriteUInt64(uint64_t v); + + virtual void WriteFloat(float v); + virtual void WriteDouble(double v); + + virtual void WriteBuffer(const void* data, unsigned int len); + virtual void WriteString(const char* s); + + virtual uint16_t RegisterMessage(const char* module, const char *message, unsigned int version, bool inOut); +}; diff --git a/rehlds/rehlds/RehldsRuntimeConfig.cpp b/rehlds/rehlds/RehldsRuntimeConfig.cpp new file mode 100644 index 0000000..5eb9ddc --- /dev/null +++ b/rehlds/rehlds/RehldsRuntimeConfig.cpp @@ -0,0 +1,113 @@ +#include "precompiled.h" + +CRehldsRuntimeConfig g_RehldsRuntimeConfig; + +CRehldsRuntimeConfig::CRehldsRuntimeConfig() +{ + disableAllHooks = false; + testRecordingFileName[0] = 0; + testPlayerMode = TPM_DISABLE; +} + +void CRehldsRuntimeConfig::parseFromCommandLine(const char* cmdLine) { + char localBuf[2048]; + if (strlen(cmdLine) >= sizeof(localBuf)) rehlds_syserror("%s: too long cmdline", __FUNCTION__); + + strcpy(localBuf, cmdLine); + char* cpos = localBuf; + + getNextToken(&cpos); //skip executable path + + const char* token = getNextToken(&cpos); + while (token != NULL) { + if (!strcmp(token, "--rehlds-test-record")) + { + const char* fname = getNextToken(&cpos); + if (fname == NULL) rehlds_syserror("%s: usage: --rehlds-test-record ", __FUNCTION__); + strncpy(testRecordingFileName, fname, sizeof(testRecordingFileName)); + testRecordingFileName[sizeof(testRecordingFileName) - 1] = 0; + testPlayerMode = TPM_RECORD; + } + else if (!strcmp(token, "--rehlds-test-play")) + { + const char* fname = getNextToken(&cpos); + if (fname == NULL) rehlds_syserror("%s: usage: --rehlds-test-play ", __FUNCTION__); + strncpy(testRecordingFileName, fname, sizeof(testRecordingFileName)); + testRecordingFileName[sizeof(testRecordingFileName) - 1] = 0; + testPlayerMode = TPM_PLAY; + } + else if (!strcmp(token, "--rehlds-test-anon")) + { + const char* fname = getNextToken(&cpos); + if (fname == NULL) rehlds_syserror("%s: usage: --rehlds-test-anon ", __FUNCTION__); + strncpy(testRecordingFileName, fname, sizeof(testRecordingFileName)); + testRecordingFileName[sizeof(testRecordingFileName) - 1] = 0; + testPlayerMode = TPM_ANONYMIZE; + } + else if (!strcmp(token, "--rehlds-disable-all-hooks")) + { + disableAllHooks = true; + } + + token = getNextToken(&cpos); + } +} + +const char* CRehldsRuntimeConfig::getNextToken(char** pBuf) { + char* rpos = *pBuf; + if (*rpos == 0) return NULL; + + //skip spaces at the beginning + while (*rpos != 0 && isspace(*rpos)) + rpos++; + + if (*rpos == 0) { + *pBuf = rpos; + return NULL; + } + + const char* res = rpos; + char* wpos = rpos; + char inQuote = 0; + while (*rpos != 0) { + char cc = *rpos; + if (inQuote) { + if (inQuote == cc) + { + inQuote = 0; + rpos++; + } + else + { + if (rpos != wpos) *wpos = cc; + rpos++; wpos++; + } + } + else + { + if (isspace(cc)) + { + break; + } + else if (cc == '\'' || cc == '"') + { + inQuote = cc; + rpos++; + } + else + { + if (rpos != wpos) *wpos = cc; + rpos++; wpos++; + } + } + } + + if (*rpos != 0) { + rpos++; + } + *pBuf = rpos; + + *wpos = 0; + + return res; +} diff --git a/rehlds/rehlds/RehldsRuntimeConfig.h b/rehlds/rehlds/RehldsRuntimeConfig.h new file mode 100644 index 0000000..b77564b --- /dev/null +++ b/rehlds/rehlds/RehldsRuntimeConfig.h @@ -0,0 +1,24 @@ +#pragma once + +enum TestPlayerMode { + TPM_DISABLE, + TPM_RECORD, + TPM_PLAY, + TPM_ANONYMIZE, +}; + +class CRehldsRuntimeConfig { +private: + static const char* getNextToken(char** pBuf); + +public: + CRehldsRuntimeConfig(); + + bool disableAllHooks; + char testRecordingFileName[260]; + TestPlayerMode testPlayerMode; + + void parseFromCommandLine(const char* cmdLine); +}; + +extern CRehldsRuntimeConfig g_RehldsRuntimeConfig; diff --git a/rehlds/rehlds/flight_recorder.cpp b/rehlds/rehlds/flight_recorder.cpp new file mode 100644 index 0000000..d86ffbe --- /dev/null +++ b/rehlds/rehlds/flight_recorder.cpp @@ -0,0 +1,56 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ +#include "precompiled.h" + +CRehldsFlightRecorder* g_FlightRecorder; + +uint16_t g_FRMsg_Frame; +uint16_t g_FRMsg_FreeEntPrivateData; +uint16_t g_FRMsg_AllocEntPrivateData; + + +void FR_Init() { + g_FlightRecorder = new CRehldsFlightRecorder(); + + g_FRMsg_Frame = g_FlightRecorder->RegisterMessage("rehlds", "Frame", 1, true); + g_FRMsg_FreeEntPrivateData = g_FlightRecorder->RegisterMessage("rehlds", "FreeEntPrivateData", 1, false); + g_FRMsg_AllocEntPrivateData = g_FlightRecorder->RegisterMessage("rehlds", "AllocEntPrivateData", 1, false); +} + +void FR_StartFrame() { + g_FlightRecorder->StartMessage(g_FRMsg_Frame, true); + g_FlightRecorder->WriteDouble(realtime); + g_FlightRecorder->EndMessage(g_FRMsg_Frame, true); +} + +void FR_EndFrame() { + g_FlightRecorder->StartMessage(g_FRMsg_Frame, false); + g_FlightRecorder->EndMessage(g_FRMsg_Frame, false); +} + +void FR_AllocEntPrivateData(void* res) { + g_FlightRecorder->StartMessage(g_FRMsg_AllocEntPrivateData, true); + g_FlightRecorder->WriteUInt32((size_t)res); + g_FlightRecorder->EndMessage(g_FRMsg_AllocEntPrivateData, true); +} + +void FR_FreeEntPrivateData(void* data) { + g_FlightRecorder->StartMessage(g_FRMsg_FreeEntPrivateData, true); + g_FlightRecorder->WriteUInt32((size_t)data); + g_FlightRecorder->EndMessage(g_FRMsg_FreeEntPrivateData, true); +} diff --git a/rehlds/rehlds/flight_recorder.h b/rehlds/rehlds/flight_recorder.h new file mode 100644 index 0000000..87c9423 --- /dev/null +++ b/rehlds/rehlds/flight_recorder.h @@ -0,0 +1,33 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ +#pragma once +#include "osconfig.h" +#include "FlightRecorderImpl.h" + +extern CRehldsFlightRecorder* g_FlightRecorder; + +extern uint16_t g_FRMsg_Frame; +extern uint16_t g_FRMsg_FreeEntPrivateData; +extern uint16_t g_FRMsg_AllocEntPrivateData; + +extern void FR_Init(); + +extern void FR_StartFrame(); +extern void FR_EndFrame(); +extern void FR_FreeEntPrivateData(void* data); +extern void FR_AllocEntPrivateData(void* res); diff --git a/rehlds/rehlds/hookchains_impl.cpp b/rehlds/rehlds/hookchains_impl.cpp new file mode 100644 index 0000000..972cf8d --- /dev/null +++ b/rehlds/rehlds/hookchains_impl.cpp @@ -0,0 +1,51 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ + +#include "precompiled.h" + +AbstractHookChain::AbstractHookChain() { + m_NumHooks = 0; + m_CurHook = 0; + m_bOriginalCalled = false; + m_OriginalFunc = NULL; +} + +void* AbstractHookChain::nextHook() { + return (m_CurHook < m_NumHooks) ? m_Hooks[m_CurHook++] : NULL; +} + +void AbstractHookChain::init(void* origFunc, void* hooks, int numHooks) { + m_OriginalFunc = origFunc; + m_NumHooks = numHooks; + m_CurHook = 0; + m_bOriginalCalled = false; + memcpy(m_Hooks, hooks, numHooks * sizeof(size_t)); +} + +AbstractHookChainRegistry::AbstractHookChainRegistry() +{ + m_NumHooks = 0; +} + +void AbstractHookChainRegistry::addHook(void* hookFunc) { + if (m_NumHooks >= MAX_HOOKS_IN_CHAIN) { + rehlds_syserror("MAX_HOOKS_IN_CHAIN limit hit"); + } + + m_Hooks[m_NumHooks++] = hookFunc; +} \ No newline at end of file diff --git a/rehlds/rehlds/hookchains_impl.h b/rehlds/rehlds/hookchains_impl.h new file mode 100644 index 0000000..139cdd3 --- /dev/null +++ b/rehlds/rehlds/hookchains_impl.h @@ -0,0 +1,161 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once +#include "hookchains.h" + +#define MAX_HOOKS_IN_CHAIN 64 + +class AbstractHookChain { + +protected: + void* m_Hooks[MAX_HOOKS_IN_CHAIN]; + void* m_OriginalFunc; + int m_CurHook; + int m_NumHooks; + + bool m_bOriginalCalled; + + AbstractHookChain(); + + void* nextHook(); + +public: + void init(void* origFunc, void* hooks, int numHooks); +}; + + +template +class IHookChainImpl : public IHookChain, public AbstractHookChain { +public: + typedef t_ret(*hookfunc_t)(IHookChain*, t_args...); + typedef t_ret(*origfunc_t)(t_args...); + +private: + t_ret m_OriginalReturnResult; + +public: + virtual ~IHookChainImpl() { } + virtual t_ret callNext(t_args... args) { + void* nextvhook = nextHook(); + if (nextvhook) { + hookfunc_t nexthook = (hookfunc_t)nextvhook; + return nexthook(this, args...); + } + + origfunc_t origfunc = (origfunc_t)m_OriginalFunc; + m_OriginalReturnResult = origfunc(args...); + m_bOriginalCalled = true; + return m_OriginalReturnResult; + } + + virtual t_ret getOriginalReturnResult() { + return m_OriginalReturnResult; + } + + virtual bool isOriginalCalled() { + return m_bOriginalCalled; + } +}; + +template +class IVoidHookChainImpl : public IVoidHookChain, public AbstractHookChain { +public: + typedef void(*hookfunc_t)(IVoidHookChain*, t_args...); + typedef void(*origfunc_t)(t_args...); + + virtual ~IVoidHookChainImpl() { } + + virtual void callNext(t_args... args) { + void* nextvhook = nextHook(); + if (nextvhook) { + hookfunc_t nexthook = (hookfunc_t)nextvhook; + nexthook(this, args...); + return; + } + + origfunc_t origfunc = (origfunc_t)m_OriginalFunc; + if (origfunc) { + origfunc(args...); + } + m_bOriginalCalled = true; + } + + virtual bool isOriginalCalled() { + return m_bOriginalCalled; + } +}; + +class AbstractHookChainRegistry { +protected: + void* m_Hooks[MAX_HOOKS_IN_CHAIN]; + int m_NumHooks; + +protected: + void addHook(void* hookFunc); + +public: + AbstractHookChainRegistry(); +}; + +template +class IHookChainRegistryImpl : public IHookChainRegistry < t_ret, t_args...>, public AbstractHookChainRegistry { +public: + typedef t_ret(*hookfunc_t)(IHookChain*, t_args...); + typedef t_ret(*origfunc_t)(t_args...); + + virtual ~IHookChainRegistryImpl() { } + + t_ret callChain(origfunc_t origFunc, t_args... args) { + IHookChainImpl chain; + chain.init((void*)origFunc, m_Hooks, m_NumHooks); + return chain.callNext(args...); + } + + virtual void registerHook(hookfunc_t hook) { + addHook((void*)hook); + } +}; + +template +class IVoidHookChainRegistryImpl : public IVoidHookChainRegistry , public AbstractHookChainRegistry { +public: + typedef void(*hookfunc_t)(IVoidHookChain*, t_args...); + typedef void(*origfunc_t)(t_args...); + + virtual ~IVoidHookChainRegistryImpl() { } + + void callChain(origfunc_t origFunc, t_args... args) { + IVoidHookChainImpl chain; + chain.init((void*)origFunc, m_Hooks, m_NumHooks); + chain.callNext(args...); + } + + virtual void registerHook(hookfunc_t hook) { + addHook((void*)hook); + } +}; diff --git a/rehlds/rehlds/platform.cpp b/rehlds/rehlds/platform.cpp new file mode 100644 index 0000000..0d9d24f --- /dev/null +++ b/rehlds/rehlds/platform.cpp @@ -0,0 +1,211 @@ +#include "precompiled.h" + +IReHLDSPlatform* CRehldsPlatformHolder::m_Platform; + +IReHLDSPlatform* CRehldsPlatformHolder::get() { + if (m_Platform == NULL) { + m_Platform = new CSimplePlatform(); + } + + return m_Platform; +} + +void CRehldsPlatformHolder::set(IReHLDSPlatform* p) { + m_Platform = p; +} + +CSimplePlatform::CSimplePlatform() { +#ifdef _WIN32 + HMODULE wsock = LoadLibraryA("wsock32.dll"); + setsockopt_v11 = (setsockopt_proto)GetProcAddress(wsock, "setsockopt"); + if (setsockopt_v11 == NULL) + rehlds_syserror("%s: setsockopt_v11 not found", __FUNCTION__); +#endif +} + +uint32_t CSimplePlatform::time(uint32_t* pTime) +{ + time_t res = ::time((time_t*)NULL); + if (pTime != NULL) *pTime = (uint32_t)res; + + return (uint32_t) res; +} + +struct tm* CSimplePlatform::localtime(uint32_t time) +{ + time_t theTime = (time_t)time; + return ::localtime(&theTime); +} + +void CSimplePlatform::srand(uint32_t seed) +{ + return ::srand(seed); +} + +int CSimplePlatform::rand() +{ + return ::rand(); +} + +#ifdef _WIN32 +void CSimplePlatform::Sleep(DWORD msec) { + ::Sleep(msec); +} + +BOOL CSimplePlatform::QueryPerfCounter(LARGE_INTEGER* counter) { + return ::QueryPerformanceCounter(counter); +} + +BOOL CSimplePlatform::QueryPerfFreq(LARGE_INTEGER* freq) { + return ::QueryPerformanceFrequency(freq); +} + +DWORD CSimplePlatform::GetTickCount() { + return ::GetTickCount(); +} + +void CSimplePlatform::GetLocalTime(LPSYSTEMTIME time) { + return ::GetLocalTime(time); +} + +void CSimplePlatform::GetSystemTime(LPSYSTEMTIME time) { + return ::GetSystemTime(time); +} + +void CSimplePlatform::GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo) { + ::GetTimeZoneInformation(zinfo); +} + +BOOL CSimplePlatform::GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) +{ + return ::GetProcessTimes(hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); +} + +void CSimplePlatform::GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) +{ + ::GetSystemTimeAsFileTime(lpSystemTimeAsFileTime); +} +#endif //WIN32 + +SOCKET CSimplePlatform::socket(int af, int type, int protocol) { + return ::socket(af, type, protocol); +} + +int CSimplePlatform::setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen) { +#ifdef _WIN32 + return setsockopt_v11(s, level, optname, optval, optlen); +#else + return setsockopt(s, level, optname, optval, optlen); +#endif +} + +int CSimplePlatform::closesocket(SOCKET s) { +#ifdef _WIN32 + return ::closesocket(s); +#else + return ::close(s); +#endif +} + +int CSimplePlatform::recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen) { + return ::recvfrom(s, buf, len, flags, from, fromlen); +} + +int CSimplePlatform::sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) { + return ::sendto(s, buf, len, flags, to, tolen); +} + +int CSimplePlatform::bind(SOCKET s, const struct sockaddr* addr, int namelen) { + return ::bind(s, addr, namelen); +} + +int CSimplePlatform::getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen) { + return ::getsockname(s, name, namelen); +} + +struct hostent* CSimplePlatform::gethostbyname(const char *name) { + return ::gethostbyname(name); +} + +int CSimplePlatform::gethostname(char *name, int namelen) { + return ::gethostname(name, namelen); +} + +#ifdef _WIN32 + +int CSimplePlatform::ioctlsocket(SOCKET s, long cmd, u_long *argp) { + return ::ioctlsocket(s, cmd, argp); +} + +int CSimplePlatform::WSAGetLastError() { + return ::WSAGetLastError(); +} + +#endif //WIN32 +void CSimplePlatform::SteamAPI_SetBreakpadAppID(uint32 unAppID) { + return ::SteamAPI_SetBreakpadAppID(unAppID); +} + +void CSimplePlatform::SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback) { + ::SteamAPI_UseBreakpadCrashHandler(pchVersion, pchDate, pchTime, bFullMemoryDumps, pvContext, m_pfnPreMinidumpCallback); +} + +void CSimplePlatform::SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback) { + ::SteamAPI_RegisterCallback(pCallback, iCallback); +} + +bool CSimplePlatform::SteamAPI_Init() { + return ::SteamAPI_Init(); +} + +void CSimplePlatform::SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall) { + return ::SteamAPI_UnregisterCallResult(pCallback, hAPICall); +} + +ISteamApps* CSimplePlatform::SteamApps() { + return ::SteamApps(); +} + +bool CSimplePlatform::SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString) { + return ::SteamGameServer_Init(unIP, usSteamPort, usGamePort, usQueryPort, eServerMode, pchVersionString); +} + +ISteamGameServer* CSimplePlatform::SteamGameServer() { + return ::SteamGameServer(); +} + +void CSimplePlatform::SteamGameServer_RunCallbacks() { + ::SteamGameServer_RunCallbacks(); +} + +void CSimplePlatform::SteamAPI_RunCallbacks() { + ::SteamAPI_RunCallbacks(); +} + +void CSimplePlatform::SteamGameServer_Shutdown() { + ::SteamGameServer_Shutdown(); +} + +void CSimplePlatform::SteamAPI_UnregisterCallback(CCallbackBase *pCallback) +{ + ::SteamAPI_UnregisterCallback(pCallback); +} + +void rehlds_syserror(const char* fmt, ...) { + va_list argptr; + static char string[8192]; + + va_start(argptr, fmt); + vsnprintf(string, sizeof(string), fmt, argptr); + va_end(argptr); + + printf("%s\n", string); + + FILE* fl = fopen("rehlds_error.txt", "w"); + fprintf(fl, "%s\n", string); + fclose(fl); + + //TerminateProcess(GetCurrentProcess(), 1); + *((int*)NULL) = 0; + while (true); +} diff --git a/rehlds/rehlds/platform.h b/rehlds/rehlds/platform.h new file mode 100644 index 0000000..fd53707 --- /dev/null +++ b/rehlds/rehlds/platform.h @@ -0,0 +1,121 @@ +#pragma once + +#include "osconfig.h" +#include "steam/steam_api.h" +#include "steam/steam_gameserver.h" + +#ifdef _WIN32 +typedef int(__stdcall *setsockopt_proto)(SOCKET s, int level, int optname, const char *optval, int optlen); +#endif + +class IReHLDSPlatform { +public: + virtual uint32_t time(uint32_t* pTime) = 0; + virtual struct tm* localtime(uint32_t time) = 0; + virtual void srand(uint32_t seed) = 0; + virtual int rand() = 0; + +#ifdef _WIN32 + virtual void Sleep(DWORD msec) = 0; + virtual BOOL QueryPerfCounter(LARGE_INTEGER* counter) = 0; + virtual BOOL QueryPerfFreq(LARGE_INTEGER* freq) = 0; + virtual DWORD GetTickCount() = 0; + virtual void GetLocalTime(LPSYSTEMTIME time) = 0; + virtual void GetSystemTime(LPSYSTEMTIME time) = 0; + virtual void GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo) = 0; + virtual BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) = 0; + virtual void GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) = 0; +#endif + + virtual SOCKET socket(int af, int type, int protocol) = 0; + virtual int setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen) = 0; + virtual int closesocket(SOCKET s) = 0; + virtual int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen) = 0; + virtual int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) = 0; + virtual int bind(SOCKET s, const struct sockaddr* addr, int namelen) = 0; + virtual int getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen) = 0; + virtual struct hostent* gethostbyname(const char *name) = 0; + virtual int gethostname(char *name, int namelen) = 0; + +#ifdef _WIN32 + virtual int ioctlsocket(SOCKET s, long cmd, u_long *argp) = 0; + virtual int WSAGetLastError() = 0; +#endif + + virtual void SteamAPI_SetBreakpadAppID(uint32 unAppID) = 0; + virtual void SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback) = 0; + virtual void SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback) = 0; + virtual bool SteamAPI_Init() = 0; + virtual void SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall) = 0; + virtual ISteamApps* SteamApps() = 0; + virtual bool SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString) = 0; + virtual ISteamGameServer* SteamGameServer() = 0; + virtual void SteamGameServer_RunCallbacks() = 0; + virtual void SteamAPI_RunCallbacks() = 0; + virtual void SteamGameServer_Shutdown() = 0; + virtual void SteamAPI_UnregisterCallback(CCallbackBase *pCallback) = 0; +}; + +class CSimplePlatform : public IReHLDSPlatform { +private: +#ifdef _WIN32 + setsockopt_proto setsockopt_v11; +#endif + +public: + CSimplePlatform(); + + virtual uint32_t time(uint32_t* pTime); + virtual struct tm* localtime(uint32_t time); + virtual void srand(uint32_t seed); + virtual int rand(); + +#ifdef _WIN32 + virtual void Sleep(DWORD msec); + virtual BOOL QueryPerfCounter(LARGE_INTEGER* counter); + virtual BOOL QueryPerfFreq(LARGE_INTEGER* freq); + virtual DWORD GetTickCount(); + virtual void GetLocalTime(LPSYSTEMTIME time); + virtual void GetSystemTime(LPSYSTEMTIME time); + virtual void GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo); + virtual BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); + virtual void GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); +#endif + + virtual SOCKET socket(int af, int type, int protocol); + virtual int setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen); + virtual int closesocket(SOCKET s); + virtual int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen); + virtual int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen); + virtual int bind(SOCKET s, const struct sockaddr* addr, int namelen); + virtual int getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen); + virtual struct hostent* gethostbyname(const char *name); + virtual int gethostname(char *name, int namelen); + +#ifdef _WIN32 + virtual int ioctlsocket(SOCKET s, long cmd, u_long *argp); + virtual int WSAGetLastError(); +#endif + + virtual void SteamAPI_SetBreakpadAppID(uint32 unAppID); + virtual void SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback); + virtual void SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback); + virtual bool SteamAPI_Init(); + virtual void SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall); + virtual ISteamApps* SteamApps(); + virtual bool SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString); + virtual ISteamGameServer* SteamGameServer(); + virtual void SteamGameServer_RunCallbacks(); + virtual void SteamAPI_RunCallbacks(); + virtual void SteamGameServer_Shutdown(); + virtual void SteamAPI_UnregisterCallback(CCallbackBase *pCallback); +}; + +class CRehldsPlatformHolder { +private: + static IReHLDSPlatform* m_Platform; + +public: + static IReHLDSPlatform* get(); + static void set(IReHLDSPlatform* p); +}; diff --git a/rehlds/rehlds/precompiled.cpp b/rehlds/rehlds/precompiled.cpp new file mode 100644 index 0000000..7ff8df5 --- /dev/null +++ b/rehlds/rehlds/precompiled.cpp @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/rehlds/rehlds/precompiled.h b/rehlds/rehlds/precompiled.h new file mode 100644 index 0000000..27e532d --- /dev/null +++ b/rehlds/rehlds/precompiled.h @@ -0,0 +1,51 @@ +#pragma once + +#include "version/appversion.h" + +#include "osconfig.h" + +#include "sys_shared.h" +#include "crc32.h" +#include "static_map.h" + +#include "ed_strpool.h" + +#include "memory.h" +#include "engine.h" +#include "platform.h" +#include "RehldsRuntimeConfig.h" +#include "rehlds_debug.h" + +#ifdef HOOK_ENGINE +#include "hooker.h" +#endif + +//valve libs stuff +#include "tier0/platform.h" +#include "tier0/dbg.h" + +#include "interface.h" +#include "iregistry.h" + +#include "utlbuffer.h" +#include "utlrbtree.h" + +//testsuite +#include "testsuite.h" +#include "funccalls.h" +#include "recorder.h" +#include "player.h" +#include "anonymizer.h" + +#include "bzip2/bzlib.h" +#include "igame.h" +#include "sys_linuxwnd.h" + +#include "iengine.h" +#include "hookchains_impl.h" +#include "rehlds_interfaces.h" +#include "rehlds_interfaces_impl.h" +#include "rehlds_api.h" +#include "rehlds_api_impl.h" +#include "FlightRecorderImpl.h" +#include "flight_recorder.h" diff --git a/rehlds/rehlds/rehlds_api_impl.cpp b/rehlds/rehlds/rehlds_api_impl.cpp new file mode 100644 index 0000000..236d9e3 --- /dev/null +++ b/rehlds/rehlds/rehlds_api_impl.cpp @@ -0,0 +1,220 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#include "precompiled.h" + +char* GetClientFallback_api() { + return com_clientfallback; +} + +int* GetAllowCheats_api() { + return &allow_cheats; +} + +bool GSBSecure_api() { + return Steam_GSBSecure() != 0; +} + +int GetBuildNumber_api() { + return build_number(); +} + +double GetRealTime_api() { + return realtime; +} + +int* GetMsgBadRead_api() { + return &msg_badread; +} + +CRehldsServerStatic g_RehldsServerStatic; +CRehldsServerData g_RehldsServerData; +CRehldsHookchains g_RehldsHookchains; +RehldsFuncs_t g_RehldsApiFuncs = +{ + &SV_DropClient_api, + &SV_RejectConnection, + &Steam_NotifyBotConnect_api, + &GetNetMessage_api, + &GetHostClient_api, + &GetMsgReadCount_api, + &SV_FilterUser, + &NET_SendPacket_api, + &Cmd_TokenizeString, + &SV_CheckChallenge_api, + &SV_SendUserReg, + &SV_WriteDeltaDescriptionsToClient, + &SV_SetMoveVars, + &SV_WriteMovevarsToClient, + &GetClientFallback_api, + &GetAllowCheats_api, + &GSBSecure_api, + &GetBuildNumber_api, + &GetRealTime_api, + &GetMsgBadRead_api +}; + +sizebuf_t* GetNetMessage_api() +{ + return &net_message; +} + +IGameClient* GetHostClient_api() +{ + if (host_client == NULL) + return NULL; + + return GetRehldsApiClient(host_client); +} + +extern int* GetMsgReadCount_api() +{ + return &msg_readcount; +} + +IRehldsHookRegistry_Steam_NotifyClientConnect* CRehldsHookchains::Steam_NotifyClientConnect() +{ + return &m_Steam_NotifyClientConnect; +} + +IRehldsHookRegistry_SV_ConnectClient* CRehldsHookchains::SV_ConnectClient() +{ + return &m_SV_ConnectClient; +} + +IRehldsHookRegistry_SV_GetIDString* CRehldsHookchains::SV_GetIDString() +{ + return &m_SV_GetIDString; +} + +IRehldsHookRegistry_SV_SendServerinfo* CRehldsHookchains::SV_SendServerinfo() +{ + return &m_SV_SendServerinfo; +} + +IRehldsHookRegistry_SV_CheckProtocol* CRehldsHookchains::SV_CheckProtocol() +{ + return &m_SV_CheckProtocol; +} + +IRehldsHookRegistry_SVC_GetChallenge_mod* CRehldsHookchains::SVC_GetChallenge_mod() +{ + return &m_SVC_GetChallenge_mod; +} + +IRehldsHookRegistry_SV_CheckKeyInfo* CRehldsHookchains::SV_CheckKeyInfo() +{ + return &m_SV_CheckKeyInfo; +} + +IRehldsHookRegistry_SV_CheckIPRestrictions* CRehldsHookchains::SV_CheckIPRestrictions() +{ + return &m_SV_CheckIPRestrictions; +} + +IRehldsHookRegistry_SV_FinishCertificateCheck* CRehldsHookchains::SV_FinishCertificateCheck() +{ + return &m_SV_FinishCertificateCheck; +} + +IRehldsHookRegistry_Steam_NotifyBotConnect* CRehldsHookchains::Steam_NotifyBotConnect() +{ + return &m_Steam_NotifyBotConnect; +} + +IRehldsHookRegistry_SerializeSteamId* CRehldsHookchains::SerializeSteamId() +{ + return &m_SerializeSteamId; +} + +IRehldsHookRegistry_SV_CompareUserID* CRehldsHookchains::SV_CompareUserID() +{ + return &m_SV_CompareUserID; +} + +IRehldsHookRegistry_Steam_NotifyClientDisconnect* CRehldsHookchains::Steam_NotifyClientDisconnect() +{ + return &m_Steam_NotifyClientDisconnect; +} + +IRehldsHookRegistry_PreprocessPacket* CRehldsHookchains::PreprocessPacket() { + return &m_PreprocessPacket; +} + +IRehldsHookRegistry_ValidateCommand* CRehldsHookchains::ValidateCommand() { + return &m_ValidateCommand; +} + +IRehldsHookRegistry_ClientConnected* CRehldsHookchains::ClientConnected() { + return &m_ClientConnected; +} + +IRehldsHookRegistry_HandleNetCommand* CRehldsHookchains::HandleNetCommand() { + return &m_HandleNetCommand; +} + +IRehldsHookRegistry_Mod_LoadBrushModel* CRehldsHookchains::Mod_LoadBrushModel() { + return &m_Mod_LoadBrushModel; +} + +IRehldsHookRegistry_Mod_LoadStudioModel* CRehldsHookchains::Mod_LoadStudioModel() { + return &m_Mod_LoadStudioModel; +} + +int CRehldsApi::GetMajorVersion() +{ + return REHLDS_API_VERSION_MAJOR; +} + +int CRehldsApi::GetMinorVersion() +{ + return REHLDS_API_VERSION_MINOR; +} + +const RehldsFuncs_t* CRehldsApi::GetFuncs() +{ + return &g_RehldsApiFuncs; +} + +IRehldsHookchains* CRehldsApi::GetHookchains() +{ + return &g_RehldsHookchains; +} + +IRehldsServerStatic* CRehldsApi::GetServerStatic() { + return &g_RehldsServerStatic; +} + +IRehldsServerData* CRehldsApi::GetServerData() { + return &g_RehldsServerData; +} + +IRehldsFlightRecorder* CRehldsApi::GetFlightRecorder() { + return g_FlightRecorder; +} + +EXPOSE_SINGLE_INTERFACE(CRehldsApi, IRehldsApi, VREHLDS_HLDS_API_VERSION); diff --git a/rehlds/rehlds/rehlds_api_impl.h b/rehlds/rehlds/rehlds_api_impl.h new file mode 100644 index 0000000..eb2fb0c --- /dev/null +++ b/rehlds/rehlds/rehlds_api_impl.h @@ -0,0 +1,173 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once + +#include "maintypes.h" +#include "rehlds_api.h" +#include "rehlds_interfaces_impl.h" + +//Steam_NotifyClientConnect +typedef IHookChainImpl CRehldsHook_Steam_NotifyClientConnect; +typedef IHookChainRegistryImpl CRehldsHookRegistry_Steam_NotifyClientConnect; + +//SV_ConnectClient hook +typedef IVoidHookChainImpl<> CRehldsHook_SV_ConnectClient; +typedef IVoidHookChainRegistryImpl<> CRehldsHookRegistry_SV_ConnectClient; + +//SV_GetIDString hook +typedef IHookChainImpl CRehldsHook_SV_GetIDString; +typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_GetIDString; + +//SV_SendServerinfo hook +typedef IVoidHookChainImpl CRehldsHook_SV_SendServerinfo; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_SV_SendServerinfo; + +//SV_CheckProtocol hook +typedef IHookChainImpl CRehldsHook_SV_CheckProtocol; +typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_CheckProtocol; + +//SVC_GetChallenge_mod hook +typedef IVoidHookChainImpl CRehldsHook_SVC_GetChallenge_mod; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_SVC_GetChallenge_mod; + +//SV_CheckKeyInfo hook +typedef IHookChainImpl CRehldsHook_SV_CheckKeyInfo; +typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_CheckKeyInfo; + +//SV_CheckIPRestrictions hook +typedef IHookChainImpl CRehldsHook_SV_CheckIPRestrictions; +typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_CheckIPRestrictions; + +//SV_FinishCertificateCheck hook +typedef IHookChainImpl CRehldsHook_SV_FinishCertificateCheck; +typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_FinishCertificateCheck; + +//Steam_NotifyBotConnect hook +typedef IHookChainImpl CRehldsHook_Steam_NotifyBotConnect; +typedef IHookChainRegistryImpl CRehldsHookRegistry_Steam_NotifyBotConnect; + +//SerializeSteamId +typedef IVoidHookChainImpl CRehldsHook_SerializeSteamId; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_SerializeSteamId; + +//SV_CompareUserID hook +typedef IHookChainImpl CRehldsHook_SV_CompareUserID; +typedef IHookChainRegistryImpl CRehldsHookRegistry_SV_CompareUserID; + +//Steam_NotifyClientDisconnect +typedef IVoidHookChainImpl CRehldsHook_Steam_NotifyClientDisconnect; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_Steam_NotifyClientDisconnect; + +//PreProcessPacket +typedef IHookChainImpl CRehldsHook_PreprocessPacket; +typedef IHookChainRegistryImpl CRehldsHookRegistry_PreprocessPacket; + +//ValidateCommand +typedef IHookChainImpl CRehldsHook_ValidateCommand; +typedef IHookChainRegistryImpl CRehldsHookRegistry_ValidateCommand; + +//ClientConnected +typedef IVoidHookChainImpl CRehldsHook_ClientConnected; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_ClientConnected; + +//HandleNetCommand +typedef IVoidHookChainImpl CRehldsHook_HandleNetCommand; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_HandleNetCommand; + +//Mod_LoadBrushModel +typedef IVoidHookChainImpl CRehldsHook_Mod_LoadBrushModel; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_Mod_LoadBrushModel; + +//Mod_LoadStudioModel +typedef IVoidHookChainImpl CRehldsHook_Mod_LoadStudioModel; +typedef IVoidHookChainRegistryImpl CRehldsHookRegistry_Mod_LoadStudioModel; + +class CRehldsHookchains : public IRehldsHookchains { +public: + CRehldsHookRegistry_Steam_NotifyClientConnect m_Steam_NotifyClientConnect; + CRehldsHookRegistry_SV_ConnectClient m_SV_ConnectClient; + CRehldsHookRegistry_SV_GetIDString m_SV_GetIDString; + CRehldsHookRegistry_SV_SendServerinfo m_SV_SendServerinfo; + CRehldsHookRegistry_SV_CheckProtocol m_SV_CheckProtocol; + CRehldsHookRegistry_SVC_GetChallenge_mod m_SVC_GetChallenge_mod; + CRehldsHookRegistry_SV_CheckKeyInfo m_SV_CheckKeyInfo; + CRehldsHookRegistry_SV_CheckIPRestrictions m_SV_CheckIPRestrictions; + CRehldsHookRegistry_SV_FinishCertificateCheck m_SV_FinishCertificateCheck; + CRehldsHookRegistry_Steam_NotifyBotConnect m_Steam_NotifyBotConnect; + CRehldsHookRegistry_SerializeSteamId m_SerializeSteamId; + CRehldsHookRegistry_SV_CompareUserID m_SV_CompareUserID; + CRehldsHookRegistry_Steam_NotifyClientDisconnect m_Steam_NotifyClientDisconnect; + CRehldsHookRegistry_PreprocessPacket m_PreprocessPacket; + CRehldsHookRegistry_ValidateCommand m_ValidateCommand; + CRehldsHookRegistry_ClientConnected m_ClientConnected; + CRehldsHookRegistry_HandleNetCommand m_HandleNetCommand; + CRehldsHookRegistry_Mod_LoadBrushModel m_Mod_LoadBrushModel; + CRehldsHookRegistry_Mod_LoadStudioModel m_Mod_LoadStudioModel; + +public: + virtual IRehldsHookRegistry_Steam_NotifyClientConnect* Steam_NotifyClientConnect(); + virtual IRehldsHookRegistry_SV_ConnectClient* SV_ConnectClient(); + virtual IRehldsHookRegistry_SV_GetIDString* SV_GetIDString(); + virtual IRehldsHookRegistry_SV_SendServerinfo* SV_SendServerinfo(); + virtual IRehldsHookRegistry_SV_CheckProtocol* SV_CheckProtocol(); + virtual IRehldsHookRegistry_SVC_GetChallenge_mod* SVC_GetChallenge_mod(); + virtual IRehldsHookRegistry_SV_CheckKeyInfo* SV_CheckKeyInfo(); + virtual IRehldsHookRegistry_SV_CheckIPRestrictions* SV_CheckIPRestrictions(); + virtual IRehldsHookRegistry_SV_FinishCertificateCheck* SV_FinishCertificateCheck(); + virtual IRehldsHookRegistry_Steam_NotifyBotConnect* Steam_NotifyBotConnect(); + virtual IRehldsHookRegistry_SerializeSteamId* SerializeSteamId(); + virtual IRehldsHookRegistry_SV_CompareUserID* SV_CompareUserID(); + virtual IRehldsHookRegistry_Steam_NotifyClientDisconnect* Steam_NotifyClientDisconnect(); + virtual IRehldsHookRegistry_PreprocessPacket* PreprocessPacket(); + virtual IRehldsHookRegistry_ValidateCommand* ValidateCommand(); + virtual IRehldsHookRegistry_ClientConnected* ClientConnected(); + virtual IRehldsHookRegistry_HandleNetCommand* HandleNetCommand(); + virtual IRehldsHookRegistry_Mod_LoadBrushModel* Mod_LoadBrushModel(); + virtual IRehldsHookRegistry_Mod_LoadStudioModel* Mod_LoadStudioModel(); +}; + +extern CRehldsHookchains g_RehldsHookchains; +extern RehldsFuncs_t g_RehldsApiFuncs; +extern CRehldsServerStatic g_RehldsServerStatic; +extern CRehldsServerData g_RehldsServerData; + + +class CRehldsApi : public IRehldsApi { +public: + virtual int GetMajorVersion(); + virtual int GetMinorVersion(); + virtual const RehldsFuncs_t* GetFuncs(); + virtual IRehldsHookchains* GetHookchains(); + virtual IRehldsServerStatic* GetServerStatic(); + virtual IRehldsServerData* GetServerData(); + virtual IRehldsFlightRecorder* GetFlightRecorder(); +}; + +extern sizebuf_t* GetNetMessage_api(); +extern IGameClient* GetHostClient_api(); +extern int* GetMsgReadCount_api(); diff --git a/rehlds/rehlds/rehlds_interfaces_impl.cpp b/rehlds/rehlds/rehlds_interfaces_impl.cpp new file mode 100644 index 0000000..5fb4c74 --- /dev/null +++ b/rehlds/rehlds/rehlds_interfaces_impl.cpp @@ -0,0 +1,191 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +CGameClient** g_GameClients; + +CGameClient::CGameClient(int id, client_t* cl) + : m_NetChan(&cl->netchan) +{ + m_Id = id; + m_pClient = cl; +} + +int CGameClient::GetId() +{ + return m_Id; +} + +bool CGameClient::IsActive() +{ + return m_pClient->active != 0; +} + +void CGameClient::SetActive(bool active) +{ + m_pClient->active = active ? 1 : 0; +} + +bool CGameClient::IsSpawned() +{ + return m_pClient->spawned != 0; +} + +void CGameClient::SetSpawned(bool spawned) +{ + m_pClient->spawned = spawned ? 1 : 0; +} + +bool CGameClient::IsConnected() { + return m_pClient->connected != 0;; +} + +void CGameClient::SetConnected(bool connected) { + m_pClient->connected = connected ? 1 : 0; +} + +INetChan* CGameClient::GetNetChan() +{ + return &m_NetChan; +} + +sizebuf_t* CGameClient::GetDatagram() +{ + return &m_pClient->datagram; +} + +edict_t* CGameClient::GetEdict() +{ + return m_pClient->edict; +} + +USERID_t* CGameClient::GetNetworkUserID() +{ + return &m_pClient->network_userid; +} + +const char* CGameClient::GetName() +{ + return m_pClient->name; +} + +client_t* CGameClient::GetClient() +{ + return m_pClient; +} + + +CNetChan::CNetChan(netchan_t* chan) +{ + m_pNetChan = chan; +} + +const netadr_t* CNetChan::GetRemoteAdr() +{ + return &m_pNetChan->remote_address; +} + +netchan_t* CNetChan::GetChan() +{ + return m_pNetChan; +} + + + +int CRehldsServerStatic::GetMaxClients() +{ + return g_psvs.maxclients; +} + +bool CRehldsServerStatic::IsLogActive() +{ + return g_psvs.log.active ? true : false; +} + +IGameClient* CRehldsServerStatic::GetClient(int id) +{ + if (id < 0 || id >= g_psvs.maxclients) + Sys_Error(__FUNCTION__": invalid id provided: %d", id); + + return g_GameClients[id]; +} + + + +const char* CRehldsServerData::GetModelName() { + return g_psv.modelname; +} + +const char* CRehldsServerData::GetName() { + return g_psv.name; +} + +uint32_t CRehldsServerData::GetWorldmapCrc() { + return g_psv.worldmapCRC; +} + +uint8_t* CRehldsServerData::GetClientDllMd5() { + return g_psv.clientdllmd5; +} + +void Rehlds_Interfaces_FreeClients() +{ + if (g_GameClients == NULL) + return; + + for (int i = 0; i < g_psvs.maxclientslimit; i++) + { + delete g_GameClients[i]; + } + + free(g_GameClients); + g_GameClients = NULL; +} + +void Rehlds_Interfaces_InitClients() +{ + Rehlds_Interfaces_FreeClients(); + + g_GameClients = (CGameClient**)malloc(sizeof(CGameClient*) * g_psvs.maxclientslimit); + for (int i = 0; i < g_psvs.maxclientslimit; i++) + { + g_GameClients[i] = new CGameClient(i, &g_psvs.clients[i]); + } +} + +IGameClient* GetRehldsApiClient(client_t* cl) +{ + int idx = cl - g_psvs.clients; + if (idx < 0 || idx >= g_psvs.maxclients) + { + rehlds_syserror(__FUNCTION__": Invalid client index %d", idx); + } + + return g_GameClients[idx]; +} diff --git a/rehlds/rehlds/rehlds_interfaces_impl.h b/rehlds/rehlds/rehlds_interfaces_impl.h new file mode 100644 index 0000000..613d7aa --- /dev/null +++ b/rehlds/rehlds/rehlds_interfaces_impl.h @@ -0,0 +1,104 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ +#pragma once +#include "maintypes.h" +#include "rehlds_interfaces.h" +#include "server.h" + +class CNetChan : public INetChan +{ +private: + netchan_t* m_pNetChan; + +public: + CNetChan(netchan_t* chan); + + virtual const netadr_t* GetRemoteAdr(); + + + + virtual netchan_t* GetChan(); +}; + + +class CGameClient : public IGameClient +{ +private: + int m_Id; + client_t* m_pClient; + CNetChan m_NetChan; + +public: + CGameClient(int id, client_t* cl); + + virtual int GetId(); + + virtual bool IsActive(); + virtual void SetActive(bool active); + + virtual bool IsSpawned(); + virtual void SetSpawned(bool spawned); + + virtual INetChan* GetNetChan(); + + virtual sizebuf_t* GetDatagram(); + + virtual edict_t* GetEdict(); + + virtual USERID_t* GetNetworkUserID(); + + virtual const char* GetName(); + + virtual bool IsConnected(); + virtual void SetConnected(bool connected); + + + virtual client_t* GetClient(); +}; + +class CRehldsServerStatic : public IRehldsServerStatic { +public: + virtual int GetMaxClients(); + virtual bool IsLogActive(); + virtual IGameClient* GetClient(int id); +}; + +class CRehldsServerData : public IRehldsServerData { +public: + virtual const char* GetModelName(); + virtual const char* GetName(); + virtual uint32_t GetWorldmapCrc(); + virtual uint8_t* GetClientDllMd5(); +}; + +extern CGameClient** g_GameClients; + +extern void Rehlds_Interfaces_InitClients(); +extern void Rehlds_Interfaces_FreeClients(); + +extern IGameClient* GetRehldsApiClient(client_t* cl); \ No newline at end of file diff --git a/rehlds/rehlds/structSizeCheck.cpp b/rehlds/rehlds/structSizeCheck.cpp new file mode 100644 index 0000000..18cb3db --- /dev/null +++ b/rehlds/rehlds/structSizeCheck.cpp @@ -0,0 +1,19 @@ +#include "precompiled.h" + +template +void check_size() { + static_assert(ExpectedSize == RealSize, "Size is off!"); +} + +#ifdef _WIN32 +#define CHECK_TYPE_SIZE(t,win_size,lin_size) check_size() +#else +#define CHECK_TYPE_SIZE(t,win_size,lin_size) check_size() +#endif + + +void checkSizesStatic() { + CHECK_TYPE_SIZE(client_t, 0x5018, 0x4EF4); + CHECK_TYPE_SIZE(userfilter_t, 0x20, 0x18); + CHECK_TYPE_SIZE(CSteam3Server, 0x90, 0xA8); +} diff --git a/rehlds/testsuite/anonymizer.cpp b/rehlds/testsuite/anonymizer.cpp new file mode 100644 index 0000000..c23f261 --- /dev/null +++ b/rehlds/testsuite/anonymizer.cpp @@ -0,0 +1,1042 @@ +#include "precompiled.h" + +uint64_t NET_AdrToLong(const netadr_t &a) { + if (a.type != NA_IP) + return -1; + + return a.ip[0] | (a.ip[1] << 8) | (a.ip[2] << 16) | (a.ip[3] << 24) | (uint64_t)a.port << 32; +} + +CSteamCallbackAnonymizingWrapper::CSteamCallbackAnonymizingWrapper(CAnonymizingEngExtInterceptor* anonymizer, CCallbackBase* cb, int id) +{ + m_Anonymizer = anonymizer; + m_Wrapped = cb; + m_Id = id; + m_Size = cb->GetCallbackSizeBytes(); + m_iCallback = cb->GetICallback(); + this->m_nCallbackFlags = cb->GetFlags(); +} + +void* CSteamCallbackAnonymizingWrapper::Anonymize(void* data) { + switch (m_iCallback) { + case GSClientApprove_t::k_iCallback: + { + static GSClientApprove_t cbdata; + cbdata = *(GSClientApprove_t*)data; + cbdata.m_SteamID = m_Anonymizer->Real2FakeSteamId(cbdata.m_SteamID, __FUNCTION__); + return &cbdata; + } + + case GSClientDeny_t::k_iCallback: + { + static GSClientDeny_t cbdata; + cbdata = *(GSClientDeny_t*)data; + cbdata.m_SteamID = m_Anonymizer->Real2FakeSteamId(cbdata.m_SteamID, __FUNCTION__); + return &cbdata; + } + + case GSClientKick_t::k_iCallback: + { + static GSClientKick_t cbdata; + cbdata = *(GSClientKick_t*)data; + cbdata.m_SteamID = m_Anonymizer->Real2FakeSteamId(cbdata.m_SteamID, __FUNCTION__); + return &cbdata; + } + + case GSPolicyResponse_t::k_iCallback: + case SteamServersConnected_t::k_iCallback: + case SteamServerConnectFailure_t::k_iCallback: + return data; + + default: + rehlds_syserror("%s: unsupported callback %u", __FUNCTION__, m_iCallback); + } + + return NULL; +} + +void* CSteamCallbackAnonymizingWrapper::Anonymize(void* data, bool bIOFailure, SteamAPICall_t hSteamAPICall) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return NULL; +} + + +void CSteamCallbackAnonymizingWrapper::Run(void *pvParam) +{ + if (m_Wrapped->GetICallback() != this->GetICallback()) rehlds_syserror("%s: iCallback desync", __FUNCTION__); + if (m_Wrapped->GetFlags() != this->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + m_Wrapped->Run(Anonymize(pvParam)); + this->SetFlags(m_Wrapped->GetFlags()); + this->SetICallback(m_Wrapped->GetICallback()); +} + +void CSteamCallbackAnonymizingWrapper::Run(void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall) +{ + if (m_Wrapped->GetICallback() != this->GetICallback()) rehlds_syserror("%s: iCallback desync", __FUNCTION__); + if (m_Wrapped->GetFlags() != this->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + m_Wrapped->Run(Anonymize(pvParam, bIOFailure, hSteamAPICall), bIOFailure, hSteamAPICall); + this->SetFlags(m_Wrapped->GetFlags()); + this->SetICallback(m_Wrapped->GetICallback()); +} + +int CSteamCallbackAnonymizingWrapper::GetCallbackSizeBytes() +{ + return m_Wrapped->GetCallbackSizeBytes(); +} + + + + + +CSteamAppsAnonymizingWrapper::CSteamAppsAnonymizingWrapper(ISteamApps* original, CAnonymizingEngExtInterceptor* anonymizer) +{ + m_Wrapped = original; + m_Anonymizer = anonymizer; +} + +bool CSteamAppsAnonymizingWrapper::BIsSubscribed() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsAnonymizingWrapper::BIsLowViolence() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsAnonymizingWrapper::BIsCybercafe() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsAnonymizingWrapper::BIsVACBanned() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +const char* CSteamAppsAnonymizingWrapper::GetCurrentGameLanguage() +{ + const char* res = m_Wrapped->GetCurrentGameLanguage(); + return res; +} + +const char* CSteamAppsAnonymizingWrapper::GetAvailableGameLanguages() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return NULL; +} + +bool CSteamAppsAnonymizingWrapper::BIsSubscribedApp(AppId_t appID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsAnonymizingWrapper::BIsDlcInstalled(AppId_t appID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +uint32 CSteamAppsAnonymizingWrapper::GetEarliestPurchaseUnixTime(AppId_t nAppID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamAppsAnonymizingWrapper::BIsSubscribedFromFreeWeekend() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +int CSteamAppsAnonymizingWrapper::GetDLCCount() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamAppsAnonymizingWrapper::BGetDLCDataByIndex(int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamAppsAnonymizingWrapper::InstallDLC(AppId_t nAppID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamAppsAnonymizingWrapper::UninstallDLC(AppId_t nAppID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamAppsAnonymizingWrapper::RequestAppProofOfPurchaseKey(AppId_t nAppID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +bool CSteamAppsAnonymizingWrapper::GetCurrentBetaName(char *pchName, int cchNameBufferSize) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsAnonymizingWrapper::MarkContentCorrupt(bool bMissingFilesOnly) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +uint32 CSteamAppsAnonymizingWrapper::GetInstalledDepots(DepotId_t *pvecDepots, uint32 cMaxDepots) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +uint32 CSteamAppsAnonymizingWrapper::GetAppInstallDir(AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + + + + + + +CSteamGameServerAnonymizingWrapper::CSteamGameServerAnonymizingWrapper(ISteamGameServer* original, CAnonymizingEngExtInterceptor* anonymizer) +{ + m_Wrapped = original; + m_Anonymizer = anonymizer; +} + +bool CSteamGameServerAnonymizingWrapper::InitGameServer(uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamGameServerAnonymizingWrapper::SetProduct(const char *pszProduct) +{ + m_Wrapped->SetProduct(pszProduct); +} + +void CSteamGameServerAnonymizingWrapper::SetGameDescription(const char *pszGameDescription) +{ + m_Wrapped->SetGameDescription(pszGameDescription); +} + +void CSteamGameServerAnonymizingWrapper::SetModDir(const char *pszModDir) +{ + m_Wrapped->SetModDir(pszModDir); +} + +void CSteamGameServerAnonymizingWrapper::SetDedicatedServer(bool bDedicated) +{ + m_Wrapped->SetDedicatedServer(bDedicated); +} + +void CSteamGameServerAnonymizingWrapper::LogOn(const char *pszAccountName, const char *pszPassword) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerAnonymizingWrapper::LogOnAnonymous() +{ + m_Wrapped->LogOnAnonymous(); +} + +void CSteamGameServerAnonymizingWrapper::LogOff() +{ + m_Wrapped->LogOff(); +} + +bool CSteamGameServerAnonymizingWrapper::BLoggedOn() +{ + bool res = m_Wrapped->BLoggedOn(); + return res; +} + +bool CSteamGameServerAnonymizingWrapper::BSecure() +{ + bool res = m_Wrapped->BSecure(); + return res; +} + +CSteamID CSteamGameServerAnonymizingWrapper::GetSteamID() +{ + CSteamID res = m_Wrapped->GetSteamID(); + return CSteamID(666, 1, k_EUniversePublic, k_EAccountTypeAnonGameServer); +} + +bool CSteamGameServerAnonymizingWrapper::WasRestartRequested() +{ + bool res = m_Wrapped->WasRestartRequested(); + return res; +} + +void CSteamGameServerAnonymizingWrapper::SetMaxPlayerCount(int cPlayersMax) +{ + m_Wrapped->SetMaxPlayerCount(cPlayersMax); +} + +void CSteamGameServerAnonymizingWrapper::SetBotPlayerCount(int cBotplayers) +{ + m_Wrapped->SetBotPlayerCount(cBotplayers); +} + +void CSteamGameServerAnonymizingWrapper::SetServerName(const char *pszServerName) +{ + m_Wrapped->SetServerName(pszServerName); +} + +void CSteamGameServerAnonymizingWrapper::SetMapName(const char *pszMapName) +{ + m_Wrapped->SetMapName(pszMapName); +} + +void CSteamGameServerAnonymizingWrapper::SetPasswordProtected(bool bPasswordProtected) +{ + m_Wrapped->SetPasswordProtected(bPasswordProtected); +} + +void CSteamGameServerAnonymizingWrapper::SetSpectatorPort(uint16 unSpectatorPort) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerAnonymizingWrapper::SetSpectatorServerName(const char *pszSpectatorServerName) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerAnonymizingWrapper::ClearAllKeyValues() +{ + m_Wrapped->ClearAllKeyValues(); +} + +void CSteamGameServerAnonymizingWrapper::SetKeyValue(const char *pKey, const char *pValue) +{ + m_Wrapped->SetKeyValue(pKey, pValue); +} + +void CSteamGameServerAnonymizingWrapper::SetGameTags(const char *pchGameTags) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerAnonymizingWrapper::SetGameData(const char *pchGameData) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerAnonymizingWrapper::SetRegion(const char *pszRegion) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +bool CSteamGameServerAnonymizingWrapper::SendUserConnectAndAuthenticate(uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser) +{ + uint32_t realIp = m_Anonymizer->Fake2RealIp(ntohl(unIPClient), __FUNCTION__); + bool res = m_Wrapped->SendUserConnectAndAuthenticate(htonl(realIp), pvAuthBlob, cubAuthBlobSize, pSteamIDUser); + if (res) { + *pSteamIDUser = m_Anonymizer->Real2FakeSteamId(*pSteamIDUser, __FUNCTION__); + } + return res; +} + +CSteamID CSteamGameServerAnonymizingWrapper::CreateUnauthenticatedUserConnection() +{ + CSteamID res = m_Wrapped->CreateUnauthenticatedUserConnection(); + return res; +} + +void CSteamGameServerAnonymizingWrapper::SendUserDisconnect(CSteamID steamIDUser) +{ + CSteamID real = m_Anonymizer->Fake2RealSteamId(steamIDUser, __FUNCTION__); + m_Wrapped->SendUserDisconnect(real); +} + +bool CSteamGameServerAnonymizingWrapper::BUpdateUserData(CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore) +{ + CSteamID real = steamIDUser.BAnonAccount() ? steamIDUser : m_Anonymizer->Fake2RealSteamId(steamIDUser, __FUNCTION__); + std::string realName = m_Anonymizer->Fake2RealName(pchPlayerName, __FUNCTION__); + + bool res = m_Wrapped->BUpdateUserData(real, realName.c_str(), uScore); + return res; +} + +HAuthTicket CSteamGameServerAnonymizingWrapper::GetAuthSessionTicket(void *pTicket, int cbMaxTicket, uint32 *pcbTicket) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_HAuthTicketInvalid; +} + +EBeginAuthSessionResult CSteamGameServerAnonymizingWrapper::BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_EBeginAuthSessionResultInvalidTicket; +} + +void CSteamGameServerAnonymizingWrapper::EndAuthSession(CSteamID steamID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerAnonymizingWrapper::CancelAuthTicket(HAuthTicket hAuthTicket) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +EUserHasLicenseForAppResult CSteamGameServerAnonymizingWrapper::UserHasLicenseForApp(CSteamID steamID, AppId_t appID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_EUserHasLicenseResultDoesNotHaveLicense; +} + +bool CSteamGameServerAnonymizingWrapper::RequestUserGroupStatus(CSteamID steamIDUser, CSteamID steamIDGroup) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamGameServerAnonymizingWrapper::GetGameplayStats() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +SteamAPICall_t CSteamGameServerAnonymizingWrapper::GetServerReputation() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + +uint32 CSteamGameServerAnonymizingWrapper::GetPublicIP() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamGameServerAnonymizingWrapper::HandleIncomingPacket(const void *pData, int cbData, uint32 srcIP, uint16 srcPort) +{ + uint32_t realIp = m_Anonymizer->Fake2RealIp(htonl(srcIP), __FUNCTION__); + + bool res; + if (m_Anonymizer->m_OriginalConnectPacketLen) { + res = m_Wrapped->HandleIncomingPacket(m_Anonymizer->m_OriginalConnectPacketData, m_Anonymizer->m_OriginalConnectPacketLen, ntohl(realIp), srcPort); + m_Anonymizer->m_OriginalConnectPacketLen = 0; + } else { + res = m_Wrapped->HandleIncomingPacket(pData, cbData, ntohl(realIp), srcPort); + } + + + return res; +} + +int CSteamGameServerAnonymizingWrapper::GetNextOutgoingPacket(void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort) +{ + int res = m_Wrapped->GetNextOutgoingPacket(pOut, cbMaxOut, pNetAdr, pPort); + if (res > 0) { + uint32_t fakeIp = m_Anonymizer->Real2FakeIp(ntohl(*pNetAdr), __FUNCTION__); + *pNetAdr = htonl(fakeIp); + + //Clear players list + if (res > 6 && *(uint32_t*)pOut == 0xFFFFFFFF && ((uint8_t*)pOut)[4] == 0x44) { + memset((uint8_t*)pOut + 6, 0, res - 6); + } + + //Clear serverinfo + if (res > 6 && *(uint32_t*)pOut == 0xFFFFFFFF && ((uint8_t*)pOut)[4] == 0x49) { + memset((uint8_t*)pOut + 6, 0, res - 6); + } + } + return res; +} + +void CSteamGameServerAnonymizingWrapper::EnableHeartbeats(bool bActive) +{ + m_Wrapped->EnableHeartbeats(bActive); +} + +void CSteamGameServerAnonymizingWrapper::SetHeartbeatInterval(int iHeartbeatInterval) +{ + m_Wrapped->SetHeartbeatInterval(iHeartbeatInterval); +} + +void CSteamGameServerAnonymizingWrapper::ForceHeartbeat() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +SteamAPICall_t CSteamGameServerAnonymizingWrapper::AssociateWithClan(CSteamID steamIDClan) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + +SteamAPICall_t CSteamGameServerAnonymizingWrapper::ComputeNewPlayerCompatibility(CSteamID steamIDNewPlayer) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + + + + + + + +CAnonymizingEngExtInterceptor::CAnonymizingEngExtInterceptor(IReHLDSPlatform* basePlatform) +{ + m_ServerSocket = INVALID_SOCKET; + m_SteamCallbacksCounter = 0; + m_SteamAppsWrapper = NULL; + m_GameServerWrapper = NULL; + m_SteamBreakpadContext = NULL; + m_BasePlatform = basePlatform; + m_OriginalConnectPacketLen = 0; +} + +uint32_t CAnonymizingEngExtInterceptor::time(uint32_t* pTime) +{ + uint32_t res = m_BasePlatform->time(pTime); + return res; +} + +struct tm* CAnonymizingEngExtInterceptor::localtime(uint32_t time) +{ + struct tm* res = m_BasePlatform->localtime(time); + return res; +} + +void CAnonymizingEngExtInterceptor::srand(uint32_t seed) +{ + m_BasePlatform->srand(seed); +} + +int CAnonymizingEngExtInterceptor::rand() +{ + int res = m_BasePlatform->rand(); + return res; +} + +void CAnonymizingEngExtInterceptor::Sleep(DWORD msec) +{ + m_BasePlatform->Sleep(msec); +} + +BOOL CAnonymizingEngExtInterceptor::QueryPerfCounter(LARGE_INTEGER* counter) +{ + BOOL res = m_BasePlatform->QueryPerfCounter(counter); + return res; +} + +BOOL CAnonymizingEngExtInterceptor::QueryPerfFreq(LARGE_INTEGER* counter) +{ + BOOL res = m_BasePlatform->QueryPerfFreq(counter); + return res; +} + +DWORD CAnonymizingEngExtInterceptor::GetTickCount() +{ + DWORD res = m_BasePlatform->GetTickCount(); + return res; +} + +void CAnonymizingEngExtInterceptor::GetLocalTime(LPSYSTEMTIME time) +{ + m_BasePlatform->GetLocalTime(time); +} + +void CAnonymizingEngExtInterceptor::GetSystemTime(LPSYSTEMTIME time) +{ + m_BasePlatform->GetSystemTime(time); +} + +void CAnonymizingEngExtInterceptor::GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo) +{ + m_BasePlatform->GetTimeZoneInfo(zinfo); +} + +BOOL CAnonymizingEngExtInterceptor::GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) +{ + BOOL res = m_BasePlatform->GetProcessTimes(hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); + return res; +} + +void CAnonymizingEngExtInterceptor::GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) +{ + m_BasePlatform->GetSystemTimeAsFileTime(lpSystemTimeAsFileTime); +} + +SOCKET CAnonymizingEngExtInterceptor::socket(int af, int type, int protocol) +{ + SOCKET s = m_BasePlatform->socket(af, type, protocol); + return s; +} + +int CAnonymizingEngExtInterceptor::ioctlsocket(SOCKET s, long cmd, u_long *argp) +{ + int res = m_BasePlatform->ioctlsocket(s, cmd, argp); + return res; +} + +int CAnonymizingEngExtInterceptor::setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen) +{ + int res = m_BasePlatform->setsockopt(s, level, optname, optval, optlen); + return res; +} + +int CAnonymizingEngExtInterceptor::closesocket(SOCKET s) +{ + int res = m_BasePlatform->closesocket(s); + return res; +} + +int CAnonymizingEngExtInterceptor::recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen) +{ + int res = m_BasePlatform->recvfrom(s, buf, len, flags, from, fromlen); + if (res > 0) { + Real2FakeSockaddr(from, __FUNCTION__); + if (res > 4 && (*(uint32_t*)buf) == 0xFFFFFFFF) { + unsigned int localLen = res; + ProcessConnectionlessPacket((uint8_t*)buf, &localLen); + res = localLen; + } + } + return res; +} + +int CAnonymizingEngExtInterceptor::sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) +{ + + sockaddr saddr; + memcpy(&saddr, to, sizeof(sockaddr_in)); + Fake2RealSockaddr(&saddr, __FUNCTION__); + + int res = m_BasePlatform->sendto(s, buf, len, flags, &saddr, tolen); + return res; +} + +int CAnonymizingEngExtInterceptor::bind(SOCKET s, const struct sockaddr* addr, int namelen) +{ + int res = m_BasePlatform->bind(s, addr, namelen); + return res; +} + +int CAnonymizingEngExtInterceptor::getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen) +{ + int res = m_BasePlatform->getsockname(s, name, namelen); + return res; +} + +int CAnonymizingEngExtInterceptor::WSAGetLastError() +{ + int res = m_BasePlatform->WSAGetLastError(); + return res; +} + +struct hostent* CAnonymizingEngExtInterceptor::gethostbyname(const char *name) +{ + auto s = Fake2RealHost(name, __FUNCTION__); + struct hostent* res = m_BasePlatform->gethostbyname(s.c_str()); + return res; +} + +int CAnonymizingEngExtInterceptor::gethostname(char *name, int namelen) +{ + int res = m_BasePlatform->gethostname(name, namelen); + if (res == 0) { + auto s = Real2FakeHost(name, __FUNCTION__); + strncpy(name, s.c_str(), namelen); + name[namelen - 1] = 0; + } + return res; +} + + +CSteamCallbackAnonymizingWrapper* CAnonymizingEngExtInterceptor::getOrCreateCallbackWrapper(CCallbackBase *pCallback) +{ + auto itr = m_SteamCallbacks.find(pCallback); + if (itr == m_SteamCallbacks.end()) + { + CSteamCallbackAnonymizingWrapper* wrappee = new CSteamCallbackAnonymizingWrapper(this, pCallback, m_SteamCallbacksCounter++); + m_SteamCallbacks[pCallback] = wrappee; + return wrappee; + } + else + { + return (*itr).second; + } +} + +void CAnonymizingEngExtInterceptor::SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback) +{ + CSteamCallbackAnonymizingWrapper* wrappee = getOrCreateCallbackWrapper(pCallback); + + if (wrappee->GetFlags() != pCallback->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + //if (wrappee->GetICallback() != pCallback->GetICallback()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + m_BasePlatform->SteamAPI_RegisterCallback(wrappee, iCallback); + + pCallback->SetFlags(wrappee->GetFlags()); + pCallback->SetICallback(wrappee->GetICallback()); + +} + +bool CAnonymizingEngExtInterceptor::SteamAPI_Init() +{ + bool res = m_BasePlatform->SteamAPI_Init(); + return res; +} + +void CAnonymizingEngExtInterceptor::SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall) +{ + CSteamCallbackAnonymizingWrapper* wrappee = getOrCreateCallbackWrapper(pCallback); + + if (wrappee->GetFlags() != pCallback->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + if (wrappee->GetICallback() != pCallback->GetICallback()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + m_BasePlatform->SteamAPI_UnregisterCallResult(wrappee, hAPICall); + + pCallback->SetFlags(wrappee->GetFlags()); + pCallback->SetICallback(wrappee->GetICallback()); +} + +ISteamApps* CAnonymizingEngExtInterceptor::SteamApps() +{ + if (m_SteamAppsWrapper == NULL) + { + ISteamApps* orig = m_BasePlatform->SteamApps(); + if (orig != NULL) + m_SteamAppsWrapper = new CSteamAppsAnonymizingWrapper(orig, this); + } else { + m_BasePlatform->SteamApps(); + } + + return m_SteamAppsWrapper; +} + +bool CAnonymizingEngExtInterceptor::SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString) +{ + bool res = m_BasePlatform->SteamGameServer_Init(unIP, usSteamPort, usGamePort, usQueryPort, eServerMode, pchVersionString); + return res; +} + +ISteamGameServer* CAnonymizingEngExtInterceptor::SteamGameServer() +{ + if (m_GameServerWrapper == NULL) + { + ISteamGameServer* orig = m_BasePlatform->SteamGameServer(); + if (orig != NULL) + m_GameServerWrapper = new CSteamGameServerAnonymizingWrapper(orig, this); + } else { + m_BasePlatform->SteamGameServer(); + } + + return m_GameServerWrapper; +} + +void CAnonymizingEngExtInterceptor::SteamAPI_SetBreakpadAppID(uint32 unAppID) +{ + m_BasePlatform->SteamAPI_SetBreakpadAppID(unAppID); +} + +void CAnonymizingEngExtInterceptor::SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback) +{ + m_BasePlatform->SteamAPI_UseBreakpadCrashHandler(pchVersion, pchDate, pchTime, bFullMemoryDumps, pvContext, m_pfnPreMinidumpCallback); +} + +void CAnonymizingEngExtInterceptor::SteamGameServer_RunCallbacks() +{ + m_BasePlatform->SteamGameServer_RunCallbacks(); +} + +void CAnonymizingEngExtInterceptor::SteamAPI_RunCallbacks() +{ + m_BasePlatform->SteamAPI_RunCallbacks(); +} + +void CAnonymizingEngExtInterceptor::SteamGameServer_Shutdown() +{ + m_BasePlatform->SteamGameServer_Shutdown(); + m_GameServerWrapper = NULL; +} + +void CAnonymizingEngExtInterceptor::SteamAPI_UnregisterCallback(CCallbackBase *pCallback) +{ + CSteamCallbackAnonymizingWrapper* wrappee = getOrCreateCallbackWrapper(pCallback); + + if (wrappee->GetFlags() != pCallback->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + if (wrappee->GetICallback() != pCallback->GetICallback()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + m_BasePlatform->SteamAPI_UnregisterCallback(wrappee); + + pCallback->SetFlags(wrappee->GetFlags()); + pCallback->SetICallback(wrappee->GetICallback()); +} + +void CAnonymizingEngExtInterceptor::AnonymizeAddr(const char* real, const char* fake) { + netadr_t realAdr; + netadr_t fakeAdr; + + if (!NET_StringToAdr(real, &realAdr)) { + rehlds_syserror("%s: Invalid address %s", __FUNCTION__, realAdr); + } + + if (!NET_StringToAdr(fake, &fakeAdr)) { + rehlds_syserror("%s: Invalid address %s", __FUNCTION__, realAdr); + } + + AnonymizeAddr(realAdr, fakeAdr); +} + +void CAnonymizingEngExtInterceptor::AnonymizeAddr(const netadr_t& real, const netadr_t& fake) { + uint32_t realIp = *(uint32_t*)(&real.ip[0]); + uint32_t fakeIp = *(uint32_t*)(&fake.ip[0]); + + m_Fake2RealIpMap[fakeIp] = realIp; + m_Real2FakeIpMap[realIp] = fakeIp; +} + +uint32_t CAnonymizingEngExtInterceptor::Fake2RealIp(uint32_t fakeIp, const char* callsite) { + auto itr = m_Fake2RealIpMap.find(fakeIp); + if (itr == m_Fake2RealIpMap.end()) { + rehlds_syserror("%s: Unmapped fake addr %s", callsite, IpToString(fakeIp)); + } + + return itr->second; +} + +uint32_t CAnonymizingEngExtInterceptor::Real2FakeIp(uint32_t realIp, const char* callsite) { + auto itr = m_Real2FakeIpMap.find(realIp); + if (itr == m_Real2FakeIpMap.end()) { + Con_Printf("%s: Unmapped real addr %s\n", callsite, IpToString(realIp)); + m_Real2FakeIpMap[realIp] = realIp; + m_Fake2RealIpMap[realIp] = realIp; + return realIp; + } + + return itr->second; +} + +void CAnonymizingEngExtInterceptor::Real2FakeSockaddr(sockaddr* saddr, const char* callsite) { + sockaddr_in* inaddr = (sockaddr_in*)saddr; + uint32_t realIp = *(uint32_t*)(&inaddr->sin_addr); + uint32_t fakeIp = Real2FakeIp(realIp, callsite); + + *(uint32_t*)(&inaddr->sin_addr) = fakeIp; +} + +void CAnonymizingEngExtInterceptor::Fake2RealSockaddr(sockaddr* saddr, const char* callsite) { + sockaddr_in* inaddr = (sockaddr_in*)saddr; + uint32_t fakeIp = *(uint32_t*)(&inaddr->sin_addr); + uint32_t realIp = Fake2RealIp(fakeIp, callsite); + + *(uint32_t*)(&inaddr->sin_addr) = realIp; +} + +char* CAnonymizingEngExtInterceptor::IpToString(uint32_t ip) { + static char buf[64]; + sprintf(buf, "%u.%u.%u.%u", ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF); + return buf; +} + +CSteamID CAnonymizingEngExtInterceptor::Real2FakeSteamId(CSteamID realId, const char* callsite) { + auto itr = m_Real2FakeSteamId.find(realId.ConvertToUint64()); + if (itr == m_Real2FakeSteamId.end()) { + rehlds_syserror("%s: Unmapped real steamid %s", callsite, SteamIdToString(realId)); + } + + return CSteamID(itr->second); +} + +CSteamID CAnonymizingEngExtInterceptor::Fake2RealSteamId(CSteamID fakeId, const char* callsite) { + auto itr = m_Fake2RealSteamId.find(fakeId.ConvertToUint64()); + if (itr == m_Fake2RealSteamId.end()) { + rehlds_syserror("%s: Unmapped fake steamid %s", callsite, SteamIdToString(fakeId)); + } + + return CSteamID(itr->second); +} + +char* CAnonymizingEngExtInterceptor::SteamIdToString(const CSteamID& steamid) { + USERID_t userid; + userid.clientip = 0; + userid.idtype = AUTH_IDTYPE_STEAM; + userid.m_SteamID = steamid.ConvertToUint64(); + return SV_GetIDString_internal(&userid); +} + +void CAnonymizingEngExtInterceptor::AnonymizeSteamId(const CSteamID& real, const CSteamID& fake) { + m_Real2FakeSteamId[real.ConvertToUint64()] = fake.ConvertToUint64(); + m_Fake2RealSteamId[fake.ConvertToUint64()] = real.ConvertToUint64(); +} + +void CAnonymizingEngExtInterceptor::AnonymizeSteamId(const char* real, const char* fake) { + CSteamID realId; + realId.SetFromSteam2String(real, k_EUniversePublic); + + CSteamID fakeId; + fakeId.SetFromSteam2String(fake, k_EUniversePublic); + + AnonymizeSteamId(realId, fakeId); +} + +void CAnonymizingEngExtInterceptor::ProcessConnectionlessPacket(uint8_t* data, unsigned int *len) { + memcpy(net_message.data, data, *len); + net_message.cursize = *len; + MSG_BeginReading(); + MSG_ReadLong(); // 0xFFFFFFFF + + char* args = MSG_ReadStringLine(); + Cmd_TokenizeString(args); + + const char* cmd = Cmd_Argv(0); + if (!strcmp(cmd, "connect")) { + ProcessConnectPacket(data, len); + } +} + +std::string CAnonymizingEngExtInterceptor::Real2FakeName(const char* realName, const char* callsite) { + std::string r(realName); + auto itr = m_Real2FakeName.find(r); + if (itr == m_Real2FakeName.end()) { + rehlds_syserror("%s: no fake mapping for real name '%s'", callsite, realName); + } + + return itr->second; +} + +std::string CAnonymizingEngExtInterceptor::Fake2RealName(const char* fakeName, const char* callsite) { + std::string r(fakeName); + auto itr = m_Fake2RealName.find(r); + if (itr == m_Fake2RealName.end()) { + rehlds_syserror("%s: no real mapping for fake name '%s'", callsite, fakeName); + } + + return itr->second; +} + +void CopyInfoKey(char* from, char* to, const char* key) { + const char *v = Info_ValueForKey(from, key); + if (v[0]) { + Info_SetValueForStarKey(to, key, v, MAX_INFO_STRING); + } +} + +void CAnonymizingEngExtInterceptor::ProcessConnectPacket(uint8_t* data, unsigned int *len) { + char origuserinfo[1024]; + char userinfo[1024]; + char protinfo[1024]; + + memcpy(m_OriginalConnectPacketData, data, *len); + m_OriginalConnectPacketLen = *len; + + int protocol = Q_atoi(Cmd_Argv(1)); + int challenge = Q_atoi(Cmd_Argv(2)); + + strncpy(protinfo, Cmd_Argv(3), ARRAYSIZE(protinfo)); + protinfo[ARRAYSIZE(protinfo) - 1] = 0; + + strncpy(origuserinfo, Cmd_Argv(4), ARRAYSIZE(origuserinfo)); + origuserinfo[ARRAYSIZE(origuserinfo) - 1] = 0; + + bool isSteam = (3 == atoi(Info_ValueForKey(protinfo, "prot"))); + + std::string newName = Real2FakeName(Info_ValueForKey(origuserinfo, "name"), __FUNCTION__); + Info_SetValueForKey(origuserinfo, "name", newName.c_str(), MAX_INFO_STRING); + + userinfo[0] = 0; + CopyInfoKey(origuserinfo, userinfo, "name"); + CopyInfoKey(origuserinfo, userinfo, "rate"); + CopyInfoKey(origuserinfo, userinfo, "hslots"); + CopyInfoKey(origuserinfo, userinfo, "hdelay"); + CopyInfoKey(origuserinfo, userinfo, "hspecs"); + CopyInfoKey(origuserinfo, userinfo, "cl_updaterate"); + CopyInfoKey(origuserinfo, userinfo, "*hltv"); + CopyInfoKey(origuserinfo, userinfo, "*hid"); + CopyInfoKey(origuserinfo, userinfo, "cl_autowepswitch"); + CopyInfoKey(origuserinfo, userinfo, "_cl_autowepswitch"); + CopyInfoKey(origuserinfo, userinfo, "_vgui_menus"); + CopyInfoKey(origuserinfo, userinfo, "_ah"); + CopyInfoKey(origuserinfo, userinfo, "cl_dlmax"); + CopyInfoKey(origuserinfo, userinfo, "model"); + CopyInfoKey(origuserinfo, userinfo, "topcolor"); + CopyInfoKey(origuserinfo, userinfo, "bottomcolor"); + CopyInfoKey(origuserinfo, userinfo, "cl_lw"); + CopyInfoKey(origuserinfo, userinfo, "cl_lc"); + CopyInfoKey(origuserinfo, userinfo, "hud_classautokill"); + + int infoLenDiff = strlen(origuserinfo) - strlen(userinfo); + if (infoLenDiff > 8) { + char localBuf[256]; + for (int i = 0; i < (infoLenDiff - 8); i++) { + localBuf[i] = 'a' + (i % 26); + localBuf[i + 1] = 0; + } + Info_SetValueForStarKey(userinfo, "_wtf", localBuf, MAX_INFO_STRING); + } + + + uint8_t ticket[1024]; + unsigned int ticketLen = *len - msg_readcount; + + if (ticketLen > 0) { + MSG_ReadBuf(ticketLen, ticket); + } + + if (isSteam) { + // clean the ticket + memset(ticket, 0, sizeof(ticket)); + } + + char agg[2048]; + sprintf(agg, "connect %u %u \"%s\" \"%s\"\n", protocol, challenge, protinfo, userinfo); + + memcpy(data + 4, agg, strlen(agg)); + + if (ticketLen > 0) { + memcpy(data + 4 + strlen(agg), ticket, ticketLen); + } + + *len = 4 + strlen(agg) + ticketLen; +} + +void CAnonymizingEngExtInterceptor::AnonymizeName(const char* real, const char* fake) { + m_Real2FakeName[std::string(real)] = std::string(fake); + m_Fake2RealName[std::string(fake)] = std::string(real); +} + +std::string CAnonymizingEngExtInterceptor::Real2FakeHost(const char* realHost, const char* callsite) { + std::string r(realHost); + auto itr = m_Real2FakeHost.find(r); + if (itr == m_Real2FakeHost.end()) { + rehlds_syserror("%s: no fake mapping for real host '%s'", callsite, realHost); + } + + return itr->second; +} + +std::string CAnonymizingEngExtInterceptor::Fake2RealHost(const char* fakeHost, const char* callsite) { + std::string f(fakeHost); + auto itr = m_Fake2RealHost.find(f); + if (itr == m_Fake2RealHost.end()) { + rehlds_syserror("%s: no fake mapping for fake host '%s'", callsite, fakeHost); + } + + return itr->second; +} + +void CAnonymizingEngExtInterceptor::AnonymizeHost(const char* real, const char* fake) { + m_Real2FakeHost[std::string(real)] = std::string(fake); + m_Fake2RealHost[std::string(fake)] = std::string(real); +} diff --git a/rehlds/testsuite/anonymizer.h b/rehlds/testsuite/anonymizer.h new file mode 100644 index 0000000..dd6f96e --- /dev/null +++ b/rehlds/testsuite/anonymizer.h @@ -0,0 +1,229 @@ +#pragma once +#ifdef _WIN32 + +#include "osconfig.h" +#include "testsuite.h" +#include "funccalls.h" + +class CAnonymizingEngExtInterceptor; + +class CSteamAppsAnonymizingWrapper : public ISteamApps +{ +private: + ISteamApps* m_Wrapped; + CAnonymizingEngExtInterceptor* m_Anonymizer; + +public: + CSteamAppsAnonymizingWrapper(ISteamApps* original, CAnonymizingEngExtInterceptor* anonymizer); + + virtual bool BIsSubscribed(); + virtual bool BIsLowViolence(); + virtual bool BIsCybercafe(); + virtual bool BIsVACBanned(); + virtual const char *GetCurrentGameLanguage(); + virtual const char *GetAvailableGameLanguages(); + + virtual bool BIsSubscribedApp(AppId_t appID); + virtual bool BIsDlcInstalled(AppId_t appID); + + virtual uint32 GetEarliestPurchaseUnixTime(AppId_t nAppID); + virtual bool BIsSubscribedFromFreeWeekend(); + + virtual int GetDLCCount(); + virtual bool BGetDLCDataByIndex(int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize); + + virtual void InstallDLC(AppId_t nAppID); + virtual void UninstallDLC(AppId_t nAppID); + + virtual void RequestAppProofOfPurchaseKey(AppId_t nAppID); + + virtual bool GetCurrentBetaName(char *pchName, int cchNameBufferSize); + virtual bool MarkContentCorrupt(bool bMissingFilesOnly); + virtual uint32 GetInstalledDepots(DepotId_t *pvecDepots, uint32 cMaxDepots); + + virtual uint32 GetAppInstallDir(AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize); +}; + +class CSteamGameServerAnonymizingWrapper : public ISteamGameServer +{ +private: + ISteamGameServer* m_Wrapped; + CAnonymizingEngExtInterceptor* m_Anonymizer; + +public: + CSteamGameServerAnonymizingWrapper(ISteamGameServer* original, CAnonymizingEngExtInterceptor* anonymizer); + + virtual bool InitGameServer(uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString); + virtual void SetProduct(const char *pszProduct); + virtual void SetGameDescription(const char *pszGameDescription); + virtual void SetModDir(const char *pszModDir); + virtual void SetDedicatedServer(bool bDedicated); + virtual void LogOn(const char *pszAccountName, const char *pszPassword); + virtual void LogOnAnonymous(); + virtual void LogOff(); + virtual bool BLoggedOn(); + virtual bool BSecure(); + virtual CSteamID GetSteamID(); + virtual bool WasRestartRequested(); + virtual void SetMaxPlayerCount(int cPlayersMax); + virtual void SetBotPlayerCount(int cBotplayers); + virtual void SetServerName(const char *pszServerName); + virtual void SetMapName(const char *pszMapName); + virtual void SetPasswordProtected(bool bPasswordProtected); + virtual void SetSpectatorPort(uint16 unSpectatorPort); + virtual void SetSpectatorServerName(const char *pszSpectatorServerName); + virtual void ClearAllKeyValues(); + virtual void SetKeyValue(const char *pKey, const char *pValue); + virtual void SetGameTags(const char *pchGameTags); + virtual void SetGameData(const char *pchGameData); + virtual void SetRegion(const char *pszRegion); + virtual bool SendUserConnectAndAuthenticate(uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser); + virtual CSteamID CreateUnauthenticatedUserConnection(); + virtual void SendUserDisconnect(CSteamID steamIDUser); + virtual bool BUpdateUserData(CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore); + virtual HAuthTicket GetAuthSessionTicket(void *pTicket, int cbMaxTicket, uint32 *pcbTicket); + virtual EBeginAuthSessionResult BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID); + virtual void EndAuthSession(CSteamID steamID); + virtual void CancelAuthTicket(HAuthTicket hAuthTicket); + virtual EUserHasLicenseForAppResult UserHasLicenseForApp(CSteamID steamID, AppId_t appID); + virtual bool RequestUserGroupStatus(CSteamID steamIDUser, CSteamID steamIDGroup); + virtual void GetGameplayStats(); + virtual SteamAPICall_t GetServerReputation(); + virtual uint32 GetPublicIP(); + virtual bool HandleIncomingPacket(const void *pData, int cbData, uint32 srcIP, uint16 srcPort); + virtual int GetNextOutgoingPacket(void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort); + virtual void EnableHeartbeats(bool bActive); + virtual void SetHeartbeatInterval(int iHeartbeatInterval); + virtual void ForceHeartbeat(); + virtual SteamAPICall_t AssociateWithClan(CSteamID steamIDClan); + virtual SteamAPICall_t ComputeNewPlayerCompatibility(CSteamID steamIDNewPlayer); +}; + +class CSteamCallbackAnonymizingWrapper : public CCallbackBase +{ +private: + void* Anonymize(void* data); + void* Anonymize(void* data, bool bIOFailure, SteamAPICall_t hSteamAPICall); +public: + CSteamCallbackAnonymizingWrapper(CAnonymizingEngExtInterceptor* anonymizer, CCallbackBase* cb, int id); + virtual void Run(void *pvParam); + virtual void Run(void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall); + virtual int GetCallbackSizeBytes(); + + int getRehldsCallbackId() { return m_Id; } + +protected: + CAnonymizingEngExtInterceptor* m_Anonymizer; + CCallbackBase* m_Wrapped; + int m_Id; + int m_Size; +}; + +class CAnonymizingEngExtInterceptor : public IReHLDSPlatform { + friend class CSteamAppsAnonymizingWrapper; + friend class CSteamGameServerAnonymizingWrapper; + friend class CSteamCallbackAnonymizingWrapper; + +private: + SOCKET m_ServerSocket; + + int m_SteamCallbacksCounter; + std::unordered_map m_SteamCallbacks; + CSteamAppsAnonymizingWrapper* m_SteamAppsWrapper; + + CSteamCallbackAnonymizingWrapper* getOrCreateCallbackWrapper(CCallbackBase *pCallback); + + CSteamGameServerAnonymizingWrapper* m_GameServerWrapper; + void* m_SteamBreakpadContext; + + IReHLDSPlatform* m_BasePlatform; + + std::unordered_map m_Fake2RealIpMap; + std::unordered_map m_Real2FakeIpMap; + + uint32_t Fake2RealIp(uint32_t fakeIp, const char* callsite); + uint32_t Real2FakeIp(uint32_t realIp, const char* callsite); + + void Real2FakeSockaddr(sockaddr* saddr, const char* callsite); + void Fake2RealSockaddr(sockaddr* saddr, const char* callsite); + char* IpToString(uint32_t ip); + + std::unordered_map m_Fake2RealSteamId; + std::unordered_map m_Real2FakeSteamId; + + CSteamID Real2FakeSteamId(CSteamID realId, const char* callsite); + CSteamID Fake2RealSteamId(CSteamID fakeId, const char* callsite); + + + char* SteamIdToString(const CSteamID& steamid); + void ProcessConnectionlessPacket(uint8_t* data, unsigned int *len); + void ProcessConnectPacket(uint8_t* data, unsigned int *len); + + std::unordered_map m_Real2FakeName; + std::unordered_map m_Fake2RealName; + + std::string Real2FakeName(const char* realName, const char* callsite); + std::string Fake2RealName(const char* fakeName, const char* callsite); + uint8_t m_OriginalConnectPacketData[4096]; + unsigned int m_OriginalConnectPacketLen; + + std::unordered_map m_Real2FakeHost; + std::unordered_map m_Fake2RealHost; + + std::string Real2FakeHost(const char* realHost, const char* callsite); + std::string Fake2RealHost(const char* fakeHost, const char* callsite); + +public: + CAnonymizingEngExtInterceptor(IReHLDSPlatform* basePlatform); + + virtual uint32_t time(uint32_t* pTime); + virtual struct tm* localtime(uint32_t time); + virtual void srand(uint32_t seed); + virtual int rand(); + + virtual void Sleep(DWORD msec); + virtual BOOL QueryPerfCounter(LARGE_INTEGER* counter); + virtual BOOL QueryPerfFreq(LARGE_INTEGER* freq); + virtual DWORD GetTickCount(); + virtual void GetLocalTime(LPSYSTEMTIME time); + virtual void GetSystemTime(LPSYSTEMTIME time); + virtual void GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo); + virtual BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); + virtual void GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); + + virtual SOCKET socket(int af, int type, int protocol); + virtual int ioctlsocket(SOCKET s, long cmd, u_long *argp); + virtual int setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen); + virtual int closesocket(SOCKET s); + virtual int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen); + virtual int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen); + virtual int bind(SOCKET s, const struct sockaddr* addr, int namelen); + virtual int getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen); + virtual int WSAGetLastError(); + virtual struct hostent* gethostbyname(const char *name); + virtual int gethostname(char *name, int namelen); + + virtual void SteamAPI_SetBreakpadAppID(uint32 unAppID); + virtual void SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback); + virtual void SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback); + virtual bool SteamAPI_Init(); + virtual void SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall); + virtual ISteamApps* SteamApps(); + virtual bool SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString); + virtual ISteamGameServer* SteamGameServer(); + virtual void SteamGameServer_RunCallbacks(); + virtual void SteamAPI_RunCallbacks(); + virtual void SteamGameServer_Shutdown(); + virtual void SteamAPI_UnregisterCallback(CCallbackBase *pCallback); + + void AnonymizeAddr(const netadr_t& real, const netadr_t& fake); + void AnonymizeAddr(const char* real, const char* fake); + void AnonymizeSteamId(const CSteamID& real, const CSteamID& fake); + void AnonymizeSteamId(const char* real, const char* fake); + void AnonymizeName(const char* real, const char* fake); + void AnonymizeHost(const char* real, const char* fake); + + +}; + +#endif //_WIN32 diff --git a/rehlds/testsuite/funccalls.cpp b/rehlds/testsuite/funccalls.cpp new file mode 100644 index 0000000..1e15bf6 --- /dev/null +++ b/rehlds/testsuite/funccalls.cpp @@ -0,0 +1,3288 @@ +#include "precompiled.h" + +void PrintSystemTime(LPSYSTEMTIME t, std::stringstream &ss) +{ + ss << "{" + << " Year: " << t->wYear + << " Month: " << t->wMonth + << " Day: " << t->wDay + << " DayOfWeek: " << t->wDayOfWeek + << " Hour: " << t->wHour + << " Month: " << t->wMonth + << " Second: " << t->wSecond + << " Millisecond: " << t->wMilliseconds + << " }"; +} + +void PrintFileTime(LPFILETIME t, std::stringstream &ss) +{ + ss << "{" + << " highDate: " << t->dwHighDateTime + << " lowDate: " << t->dwLowDateTime + << " }"; +} + +void PrintTm(struct tm* t, std::stringstream &ss) { + ss << "{" + << " tm_year: " << t->tm_year + << " tm_mon: " << t->tm_mon + << " tm_yday: " << t->tm_yday + << " tm_wday: " << t->tm_wday + << " tm_mday: " << t->tm_mday + << " tm_isdst: " << t->tm_isdst + << " tm_hour: " << t->tm_hour + << " tm_min: " << t->tm_min + << " tm_sec: " << t->tm_sec + << " }"; +} + +void PrintBinaryArray(const char* data, int dataLen, std::stringstream &ss) +{ + ss << "["; + for (int i = 0; i < dataLen; i++) + ss << " " << (unsigned int) (unsigned char)data[i]; + ss << "]"; +} + +void IEngExtCall::ensureArgsAreEqual(IEngExtCall* expect, bool strict, const char* callSource) { + if (compareInputArgs(expect, strict)) return; + + std::string expectedSignature = expect->toString(); + std::string mySignature = toString(); + rehlds_syserror("%s: call arguments mismatch; expected signature:\n%s\n\ncurrent signature:\n%s", callSource, expectedSignature.c_str(), mySignature.c_str()); +} + +bool CompareSockAddrs(void* ps1, void* ps2) { + sockaddr* sa1 = (sockaddr*)ps1; + sockaddr* sa2 = (sockaddr*)ps2; + + if (sa1->sa_family != sa2->sa_family) + return false; + + int compareSize = 0; + switch (sa1->sa_family) { + case AF_INET: + compareSize = 8; // sa_family(2) + sin_addr(4) + sin_port(2) + break; + + default: + rehlds_syserror("%s: Unknown sockaddr family %u", __FUNCTION__, sa1->sa_family); + } + + return 0 == memcmp(ps1, ps2, compareSize); +} + +/* ============================================================================ + CSleepExtCall +============================================================================ */ +CSleepExtCall::CSleepExtCall(DWORD time) +{ + m_Time = time; +} + +std::string CSleepExtCall::toString() +{ + std::stringstream ss; + ss << "Sleep(" << m_Time << ")"; + return ss.str(); +} + +bool CSleepExtCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSleepExtCall* otherSleep = dynamic_cast(other); + if (otherSleep == NULL) + return false; + + return otherSleep->m_Time == this->m_Time; +} + +void CSleepExtCall::writePrologue(std::ostream &stream) +{ + stream.write((char*)&m_Time, 4); +} + +void CSleepExtCall::readPrologue(std::istream &stream) +{ + stream.read((char*)&m_Time, 4); +} + + + +/* ============================================================================ + CQueryPerfFreqCall +============================================================================ */ +std::string CQueryPerfFreqCall::toString() +{ + LARGE_INTEGER li; + li.QuadPart = m_Freq; + + std::stringstream ss; + ss << "QueryPerformanceFrequency(freq = { LowPart: " << li.LowPart << "; HighPart: " << li.HighPart << ") => " << m_Res; + return ss.str(); +} + +bool CQueryPerfFreqCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CQueryPerfFreqCall* otherPerfFreq = dynamic_cast(other); + if (otherPerfFreq == NULL) + return false; + + return true; +} + +void CQueryPerfFreqCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Freq, 8).write((char*)&m_Res, 1); +} + +void CQueryPerfFreqCall::readEpilogue(std::istream &stream) { + m_Res = 0; + stream.read((char*)&m_Freq, 8).read((char*)&m_Res, 1); +} + + + +/* ============================================================================ + CQueryPerfCounterCall +============================================================================ */ +std::string CQueryPerfCounterCall::toString() +{ + LARGE_INTEGER li; + li.QuadPart = m_Counter; + + std::stringstream ss; + ss << "QueryPerformanceCounter(counter = { LowPart: " << li.LowPart << "; HighPart: " << li.HighPart << ") => " << m_Res; + return ss.str(); +} + +bool CQueryPerfCounterCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CQueryPerfCounterCall* otherPerfFreq = dynamic_cast(other); + if (otherPerfFreq == NULL) + return false; + + return true; +} + +void CQueryPerfCounterCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Counter, 8).write((char*)&m_Res, 1); +} + +void CQueryPerfCounterCall::readEpilogue(std::istream &stream) { + m_Res = 0; + stream.read((char*)&m_Counter, 8).read((char*)&m_Res, 1); +} + + + + +/* ============================================================================ + CGetTickCountCall +============================================================================ */ +std::string CGetTickCountCall::toString() +{ + std::stringstream ss; + ss << "GetTickCount() => " << m_Res; + return ss.str(); +} + +bool CGetTickCountCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetTickCountCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGetTickCountCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CGetTickCountCall::readEpilogue(std::istream &stream) { + m_Res = 0; + stream.read((char*)&m_Res, 4); +} + + + + +/* ============================================================================ + CGetTickCountCall +============================================================================ */ + +std::string CGetLocalTimeCall::toString() +{ + std::stringstream ss; + ss << "GetLocalTime() => "; + PrintSystemTime(&m_Res, ss); + return ss.str(); +} + +bool CGetLocalTimeCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetLocalTimeCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGetLocalTimeCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, sizeof(m_Res)); +} + +void CGetLocalTimeCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, sizeof(m_Res)); +} + + + + +/* ============================================================================ + CGetSystemTimeCall +============================================================================ */ +std::string CGetSystemTimeCall::toString() +{ + std::stringstream ss; + ss << "GetSystemTime() => "; + PrintSystemTime(&m_Res, ss); + return ss.str(); +} + +bool CGetSystemTimeCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetSystemTimeCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGetSystemTimeCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, sizeof(m_Res)); +} + +void CGetSystemTimeCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, sizeof(m_Res)); +} + + + + +/* ============================================================================ + CGetTimeZoneInfoCall +============================================================================ */ +std::string CGetTimeZoneInfoCall::toString() +{ + std::stringstream ss; + ss << "GetTimeZoneInfo() => {" + << " Bias: " << m_Res.Bias + << " StandardName: " << m_Res.StandardName + << " StandardDate: "; PrintSystemTime(&m_Res.StandardDate, ss); + + ss << " StandardBias: " << m_Res.StandardBias + << " DaylightName: " << m_Res.DaylightName + << " DaylightDate: "; PrintSystemTime(&m_Res.DaylightDate, ss); + ss << " DaylightBias: " << m_Res.DaylightBias + << " }"; + return ss.str(); +} + +bool CGetTimeZoneInfoCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetTimeZoneInfoCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGetTimeZoneInfoCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, sizeof(m_Res)); +} + +void CGetTimeZoneInfoCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, sizeof(m_Res)); +} + + + + +/* ============================================================================ + CSocketCall +============================================================================ */ +CSocketCall::CSocketCall(int af, int type, int protocol) +{ + m_Af = af; + m_Type = type; + m_Protocol = protocol; + m_Res = INVALID_SOCKET; +} + +std::string CSocketCall::toString() +{ + std::stringstream ss; + ss << "socket(af: " << m_Af << "; type: " << m_Type << "; protocol: " << m_Protocol << ") => " << m_Res; + return ss.str(); +} + +bool CSocketCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSocketCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Af != m_Af) + return false; + + if (otherCall->m_Type != m_Type) + return false; + + if (otherCall->m_Protocol != m_Protocol) + return false; + + return true; +} + +void CSocketCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_Af, 4).write((char*)&m_Type, 4).write((char*)&m_Protocol, 4); +} + +void CSocketCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CSocketCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_Af, 4).read((char*)&m_Type, 4).read((char*)&m_Protocol, 4); +} + +void CSocketCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, 4); +} + + + + +/* ============================================================================ + CIoCtlSocketCall +============================================================================ */ +CIoCtlSocketCall::CIoCtlSocketCall(SOCKET s, long cmd, u_long inValue) +{ + m_Socket = s; + m_Cmd = cmd; + m_InValue = inValue; + m_OutValue = 0; m_Res = 0; +} + +std::string CIoCtlSocketCall::toString() +{ + std::stringstream ss; + ss << "ioctlsocket(s: " << m_Socket << "; cmd: " << m_Cmd << "; val: { in: " << m_InValue << "; out: " << m_OutValue << " }) => " << m_Res; + return ss.str(); +} + +bool CIoCtlSocketCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CIoCtlSocketCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Socket != m_Socket) + return false; + + if (otherCall->m_Cmd != m_Cmd) + return false; + + if (otherCall->m_InValue != m_InValue) + return false; + + return true; +} + +void CIoCtlSocketCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_Socket, 4) + .write((char*)&m_Cmd, 4) + .write((char*)&m_InValue, 4); +} + +void CIoCtlSocketCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_OutValue, 4) + .write((char*)&m_Res, 4); +} + +void CIoCtlSocketCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_Socket, 4) + .read((char*)&m_Cmd, 4) + .read((char*)&m_InValue, 4); +} + +void CIoCtlSocketCall::readEpilogue(std::istream &stream) { + stream + .read((char*)&m_OutValue, 4) + .read((char*)&m_Res, 4); +} + + + + + +/* ============================================================================ + CSetSockOptCall +============================================================================ */ +CSetSockOptCall::CSetSockOptCall(SOCKET s, int level, int optname, const char* optval, int optlen) +{ + if (optlen > sizeof(m_OptVal)) + rehlds_syserror("CSetSockOptCall(): too large optlen (%d max %d)", optlen, sizeof(m_OptVal)); + m_Socket = s; + m_Level = level; + m_OptName = optname; + m_OptValLen = optlen; + memcpy(m_OptVal, optval, m_OptValLen); + m_Res = 0; +} + +std::string CSetSockOptCall::toString() +{ + std::stringstream ss; + ss << "setsockopt(s: " << m_Socket << "; level: " << m_Level << "; optName: " << m_OptName << "; optVal: "; + PrintBinaryArray(m_OptVal, m_OptValLen, ss); + ss << "; optLen: " << m_OptValLen << " ) => " << m_Res; + return ss.str(); +} + +bool CSetSockOptCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSetSockOptCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Socket != m_Socket) + return false; + + if (otherCall->m_Level != m_Level) + return false; + + if (otherCall->m_OptName != m_OptName) + return false; + + if (otherCall->m_OptValLen != m_OptValLen) + return false; + + if (memcmp(otherCall->m_OptVal, m_OptVal, m_OptValLen)) + return false; + + return true; +} + +void CSetSockOptCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_Socket, 4) + .write((char*)&m_Level, 4) + .write((char*)&m_OptName, 4) + .write((char*)&m_OptValLen, 4) + .write(m_OptVal, m_OptValLen); +} + +void CSetSockOptCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CSetSockOptCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_Socket, 4) + .read((char*)&m_Level, 4) + .read((char*)&m_OptName, 4) + .read((char*)&m_OptValLen, 4); + + stream.read(m_OptVal, m_OptValLen); +} + +void CSetSockOptCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, 4); +} + + + + +/* ============================================================================ + CCloseSocketCall +============================================================================ */ +CCloseSocketCall::CCloseSocketCall(SOCKET s) +{ + m_Socket = s; + m_Res = 0; +} + +std::string CCloseSocketCall::toString() +{ + std::stringstream ss; + ss << "closesocket(s: " << m_Socket << " ) => " << m_Res; + return ss.str(); +} + +bool CCloseSocketCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CCloseSocketCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Socket != m_Socket) + return false; + + return true; +} + +void CCloseSocketCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_Socket, 4); +} + +void CCloseSocketCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CCloseSocketCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_Socket, 4); +} + +void CCloseSocketCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, 4); +} + + +/* ============================================================================ + CRecvFromCall +============================================================================ */ +CRecvFromCall::CRecvFromCall(SOCKET s, int len, int flags, int fromlen) +{ + m_Socket = s; + m_Len = len; + m_Flags = flags; + m_FromLenIn = fromlen; + m_FromLenOut = 0; m_Res = -1; +} + +std::string CRecvFromCall::toString() +{ + std::stringstream ss; + ss << "recvfrom(s: " << m_Socket << "; data: "; + PrintBinaryArray(m_Data, m_Res, ss); + ss << "; len: " << m_Len << "; flags: " << m_Flags << "; from: "; + PrintBinaryArray(m_From, m_FromLenOut, ss); + ss << "; fromlen: { in: " << m_FromLenIn << "; out: " << m_FromLenOut << " } ) => " << m_Res; + return ss.str(); +} + +bool CRecvFromCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CRecvFromCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Socket != m_Socket) + return false; + + if (otherCall->m_Len != m_Len) + return false; + + if (otherCall->m_Flags != m_Flags) + return false; + + if (otherCall->m_FromLenIn != m_FromLenIn) + return false; + + return true; +} + +void CRecvFromCall::setResult(const void* data, const void* from, int fromLen, int res) +{ + if (res > 0 && res > sizeof(m_Data)) + rehlds_syserror("%s: too large datalen (%d max %d)", __FUNCTION__, res, sizeof(m_Data)); + + if (fromLen > sizeof(m_From)) + rehlds_syserror("%s: too large fromlen (%d max %d)", __FUNCTION__, res, sizeof(m_From)); + + m_FromLenOut = fromLen; + m_Res = res; + + if (res > 0) + memcpy(m_Data, data, res); + + if (fromLen > 0) + memcpy(m_From, from, fromLen); +} + +void CRecvFromCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_Socket, 4) + .write((char*)&m_Len, 4) + .write((char*)&m_Flags, 4) + .write((char*)&m_FromLenIn, 4); +} + +void CRecvFromCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_FromLenOut, 4) + .write((char*)&m_Res, 4) + .write((char*)&m_From, (m_FromLenOut > 0 && m_Res >= 0) ? m_FromLenOut : 0) + .write((char*)&m_Data, (m_Res > 0) ? m_Res : 0); +} + +void CRecvFromCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_Socket, 4) + .read((char*)&m_Len, 4) + .read((char*)&m_Flags, 4) + .read((char*)&m_FromLenIn, 4); +} + +void CRecvFromCall::readEpilogue(std::istream &stream) { + stream + .read((char*)&m_FromLenOut, 4) + .read((char*)&m_Res, 4); + + stream.read((char*)&m_From, (m_FromLenOut > 0 && m_Res >= 0) ? m_FromLenOut : 0) + .read((char*)&m_Data, (m_Res > 0) ? m_Res : 0); +} + + + + + +/* ============================================================================ + CSendToCall +============================================================================ */ +CSendToCall::CSendToCall(SOCKET s, const void* buf, int len, int flags, const void* to, int tolen) +{ + if (len > sizeof(m_Data)) + rehlds_syserror("%s: too large datalen (%d max %d)", __FUNCTION__, len, sizeof(m_Data)); + + if (tolen > sizeof(m_To)) + rehlds_syserror("%s: too large tolen (%d max %d)", __FUNCTION__, tolen, sizeof(m_To)); + + m_Socket = s; + m_Len = len; + m_Flags = flags; + m_ToLen = tolen; + + memcpy(m_To, to, m_ToLen); + memcpy(m_Data, buf, m_Len); + m_Res = 0; +} + +std::string CSendToCall::toString() +{ + std::stringstream ss; + ss << "sendto(s: " << m_Socket << "; data: "; + PrintBinaryArray(m_Data, m_Len, ss); + ss << "; len: " << m_Len << "; flags: " << m_Flags << "; to: "; + PrintBinaryArray(m_To, m_ToLen, ss); + ss << "; tolen: " << m_ToLen << " ) => " << m_Res; + return ss.str(); +} + +bool CSendToCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSendToCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Socket != m_Socket) + return false; + + if (strict) { + if (otherCall->m_Len != m_Len) + return false; + } else { + int maxDiff; + if (m_Len < 40) { + maxDiff = 10; + } else if (m_Len < 90) { + maxDiff = 15; + } else if (m_Len < 120) { + maxDiff = 18; + } else { + maxDiff = m_Len / 8; + } + if (abs(otherCall->m_Len - m_Len) > maxDiff) + return false; + } + + if (otherCall->m_Flags != m_Flags) + return false; + + if (otherCall->m_ToLen != m_ToLen) + return false; + + if (strict) { + if (memcmp(otherCall->m_Data, m_Data, m_Len)) + return false; + } + + if (!CompareSockAddrs(otherCall->m_To, m_To)) + return false; + + return true; +} + +void CSendToCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_Socket, 4) + .write((char*)&m_Len, 4) + .write((char*)&m_Flags, 4) + .write((char*)&m_ToLen, 4) + .write((char*)&m_To, m_ToLen) + .write((char*)&m_Data, m_Len); +} + +void CSendToCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CSendToCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_Socket, 4) + .read((char*)&m_Len, 4) + .read((char*)&m_Flags, 4) + .read((char*)&m_ToLen, 4); + + stream.read((char*)&m_To, m_ToLen) + .read((char*)&m_Data, m_Len); +} + +void CSendToCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, 4); +} + + + + + +/* ============================================================================ + CBindCall +============================================================================ */ +CBindCall::CBindCall(SOCKET s, const void* addr, int addrlen) +{ + if (addrlen > sizeof(m_Addr)) + rehlds_syserror("%s: too large tolen (%d max %d)", __FUNCTION__, addrlen, sizeof(m_Addr)); + + m_Socket = s; + m_AddrLen = addrlen; + + memcpy(m_Addr, addr, addrlen); + m_Res = 0; +} + +std::string CBindCall::toString() +{ + std::stringstream ss; + ss << "bind(s: " << m_Socket << "; addr: "; + PrintBinaryArray(m_Addr, m_AddrLen, ss); + ss << "; addrlen: " << m_AddrLen << " ) => " << m_Res; + return ss.str(); +} + +bool CBindCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CBindCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Socket != m_Socket) + return false; + + if (otherCall->m_AddrLen != m_AddrLen) + return false; + + if (!CompareSockAddrs(otherCall->m_Addr, m_Addr)) + return false; + + return true; +} + +void CBindCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_Socket, 4) + .write((char*)&m_AddrLen, 4) + .write((char*)&m_Addr, m_AddrLen); +} + +void CBindCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CBindCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_Socket, 4) + .read((char*)&m_AddrLen, 4); + + stream.read((char*)&m_Addr, m_AddrLen); +} + +void CBindCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, 4); +} + + + + +/* ============================================================================ + CGetSockNameCall +============================================================================ */ +CGetSockNameCall::CGetSockNameCall(SOCKET s, int addrlen) +{ + m_Socket = s; + m_AddrLenIn = addrlen; + m_AddrLenOut = m_Res = 0; +} + +std::string CGetSockNameCall::toString() +{ + std::stringstream ss; + ss << "getsockname(s: " << m_Socket << "; addr: "; + PrintBinaryArray(m_Addr, m_AddrLenOut, ss); + ss << "; addrlen: { in: " << m_AddrLenIn << "; out: " << m_AddrLenOut << " } ) = > " << m_Res; + return ss.str(); +} + +void CGetSockNameCall::setResult(const void* addr, int addrlen, int res) +{ + if (addrlen > sizeof(m_Addr)) + rehlds_syserror("%s: too large tolen (%d max %d)", __FUNCTION__, addrlen, sizeof(m_Addr)); + + m_Res = res; + m_AddrLenOut = addrlen; + + memcpy(m_Addr, addr, addrlen); +} + +bool CGetSockNameCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetSockNameCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Socket != m_Socket) + return false; + + if (otherCall->m_AddrLenIn != m_AddrLenIn) + return false; + + return true; +} + +void CGetSockNameCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_Socket, 4) + .write((char*)&m_AddrLenIn, 4); +} + +void CGetSockNameCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_AddrLenOut, 4) + .write((char*)&m_Res, 4) + .write((char*)&m_Addr, m_AddrLenOut); +} + +void CGetSockNameCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_Socket, 4) + .read((char*)&m_AddrLenIn, 4); +} + +void CGetSockNameCall::readEpilogue(std::istream &stream) { + stream + .read((char*)&m_AddrLenOut, 4) + .read((char*)&m_Res, 4); + + stream.read((char*)&m_Addr, m_AddrLenOut); + +} + + + + + + +/* ============================================================================ + CWSAGetLastErrorCall +============================================================================ */ +std::string CWSAGetLastErrorCall::toString() +{ + std::stringstream ss; + ss << "WSAGetLastError() = > " << m_Res; + return ss.str(); +} + +bool CWSAGetLastErrorCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CWSAGetLastErrorCall* otherCall = (CWSAGetLastErrorCall*)other; + if (otherCall == NULL) + return false; + + return true; +} + +void CWSAGetLastErrorCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CWSAGetLastErrorCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, 4); +} + + + + +/* ============================================================================ + CSteamCallbackCall1 +============================================================================ */ +CSteamCallbackCall1::CSteamCallbackCall1(int cbId, void* data, int dataSize, CCallbackBase* cb) +{ + if (dataSize > sizeof(m_Data)) + rehlds_syserror("%s: too large data (%d, max %d)", __FUNCTION__, dataSize, sizeof(m_Data)); + + m_CallbackId = cbId; + m_DataSize = dataSize; + memcpy(m_Data, data, dataSize); + m_InState.m_iCallback = cb->GetICallback(); + m_InState.m_nCallbackFlags = cb->GetFlags(); + m_OutState.clear(); +} + +std::string CSteamCallbackCall1::toString() +{ + std::stringstream ss; + ss << "Steam_Callback1: { callbackId: " << m_CallbackId << "; data: "; + PrintBinaryArray(m_Data, m_DataSize, ss); + ss << "; dataSize: " << m_DataSize << " }"; + return ss.str(); +} + +bool CSteamCallbackCall1::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamCallbackCall1* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_InState.m_iCallback != m_InState.m_iCallback) return false; + if (otherCall->m_InState.m_nCallbackFlags != m_InState.m_nCallbackFlags) return false; + + return true; +} + +void CSteamCallbackCall1::writePrologue(std::ostream &stream) { + stream.write((char*)&m_CallbackId, 4) + .write((char*)&m_InState, sizeof(m_InState)) + .write((char*)&m_DataSize, 4) + .write(m_Data, m_DataSize); +} + +void CSteamCallbackCall1::readPrologue(std::istream &stream) { + stream + .read((char*)&m_CallbackId, 4) + .read((char*)&m_InState, sizeof(m_InState)) + .read((char*)&m_DataSize, 4); + + stream.read(m_Data, m_DataSize); +} + +void CSteamCallbackCall1::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_OutState, sizeof(m_OutState)); +} + +void CSteamCallbackCall1::readEpilogue(std::istream &stream) { + stream.read((char*)&m_OutState, sizeof(m_OutState)); +} + + + +/* ============================================================================ + CSteamCallbackCall2 +============================================================================ */ +CSteamCallbackCall2::CSteamCallbackCall2(int cbId, void* data, int dataSize, bool ioFailure, SteamAPICall_t apiCall, CCallbackBase* cb) +{ + if (dataSize > sizeof(m_Data)) + rehlds_syserror("%s: too large data (%d, max %d)", __FUNCTION__, dataSize, sizeof(m_Data)); + + m_CallbackId = cbId; + m_DataSize = dataSize; + memcpy(m_Data, data, dataSize); + m_bIOFailure = ioFailure; + m_SteamAPICall = apiCall; + m_InState.m_iCallback = cb->GetICallback(); + m_InState.m_nCallbackFlags = cb->GetFlags(); + m_OutState.clear(); +} + +std::string CSteamCallbackCall2::toString() +{ + std::stringstream ss; + ss << "Steam_Callback1: { callbackId: " << m_CallbackId << "; data: "; + PrintBinaryArray(m_Data, m_DataSize, ss); + ss << "; dataSize: " << m_DataSize << "; ioFailure: " << m_bIOFailure << "; steamApiCall: " << m_SteamAPICall << " }"; + return ss.str(); +} + +bool CSteamCallbackCall2::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamCallbackCall2* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_InState.m_iCallback != m_InState.m_iCallback) return false; + if (otherCall->m_InState.m_nCallbackFlags != m_InState.m_nCallbackFlags) return false; + + return true; +} + +void CSteamCallbackCall2::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_CallbackId, 4) + .write((char*)&m_InState, sizeof(m_InState)) + .write((char*)&m_DataSize, 4) + .write((char*)&m_bIOFailure, 1) + .write((char*)&m_SteamAPICall, sizeof(m_SteamAPICall)) + .write(m_Data, m_DataSize); +} + +void CSteamCallbackCall2::readPrologue(std::istream &stream) { + m_bIOFailure = false; + stream + .read((char*)&m_CallbackId, 4) + .read((char*)&m_InState, sizeof(m_InState)) + .read((char*)&m_DataSize, 4) + .read((char*)&m_bIOFailure, 1) + .read((char*)&m_SteamAPICall, sizeof(m_SteamAPICall)); + + stream.read(m_Data, m_DataSize); +} + +void CSteamCallbackCall2::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_OutState, sizeof(m_OutState)); +} + +void CSteamCallbackCall2::readEpilogue(std::istream &stream) { + stream.read((char*)&m_OutState, sizeof(m_OutState)); +} + +/* ============================================================================ + CSteamApiRegisterCallbackCall +============================================================================ */ +CSteamApiRegisterCallbackCall::CSteamApiRegisterCallbackCall(int rehldsCallbackId, int steamCallbackId, CCallbackBase* cb) +{ + m_RehldsCallbackId = rehldsCallbackId; + m_iSteamCallbackId = steamCallbackId; + m_InState.m_iCallback = cb->GetICallback(); + m_InState.m_nCallbackFlags = cb->GetFlags(); + m_OutState.clear(); +} + +std::string CSteamApiRegisterCallbackCall::toString() +{ + std::stringstream ss; + ss << "SteamAPI_RegisterCallback( rehldsCallbackId: " << m_RehldsCallbackId << "; steamCallbackId: " << m_iSteamCallbackId << " )"; + return ss.str(); +} + +bool CSteamApiRegisterCallbackCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamApiRegisterCallbackCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_iSteamCallbackId != m_iSteamCallbackId) + return false; + + if (otherCall->m_RehldsCallbackId != m_RehldsCallbackId) + return false; + + if (otherCall->m_InState.m_iCallback != m_InState.m_iCallback) return false; + if (otherCall->m_InState.m_nCallbackFlags != m_InState.m_nCallbackFlags) return false; + + return true; +} + +void CSteamApiRegisterCallbackCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_InState, sizeof(m_InState)) + .write((char*)&m_RehldsCallbackId, 4) + .write((char*)&m_iSteamCallbackId, 4); +} + +void CSteamApiRegisterCallbackCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_InState, sizeof(m_InState)) + .read((char*)&m_RehldsCallbackId, 4) + .read((char*)&m_iSteamCallbackId, 4); +} + +void CSteamApiRegisterCallbackCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_OutState, sizeof(m_OutState)); +} + +void CSteamApiRegisterCallbackCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_OutState, sizeof(m_OutState)); +} + + + + +/* ============================================================================ + CSteamApiInitCall +============================================================================ */ + +std::string CSteamApiInitCall::toString() +{ + std::stringstream ss; + ss << "CSteamApiInitCall( ) => " << m_Res; + return ss.str(); +} + +bool CSteamApiInitCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamApiInitCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CSteamApiInitCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 1); +} + +void CSteamApiInitCall::readEpilogue(std::istream &stream) { + m_Res = false; + stream.read((char*)&m_Res, 1); +} + + + + + +/* ============================================================================ + CSteamApiUnrigestierCallResultCall +============================================================================ */ +CSteamApiUnrigestierCallResultCall::CSteamApiUnrigestierCallResultCall(int rehldsCallbackId, SteamAPICall_t steamApiCall, CCallbackBase* cb) +{ + m_RehldsCallbackId = rehldsCallbackId; + m_SteamApiCall = steamApiCall; + m_InState.m_iCallback = cb->GetICallback(); + m_InState.m_nCallbackFlags = cb->GetFlags(); + m_OutState.clear(); +} + +std::string CSteamApiUnrigestierCallResultCall::toString() +{ + std::stringstream ss; + ss << "SteamAPI_UnregisterCallResult( rehldsCallbackId: " << m_RehldsCallbackId << "; steamApiCall: " << m_SteamApiCall << " )"; + return ss.str(); +} + +bool CSteamApiUnrigestierCallResultCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamApiUnrigestierCallResultCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_SteamApiCall != m_SteamApiCall) + return false; + + if (otherCall->m_RehldsCallbackId != m_RehldsCallbackId) + return false; + + if (otherCall->m_InState.m_iCallback != m_InState.m_iCallback) return false; + if (otherCall->m_InState.m_nCallbackFlags != m_InState.m_nCallbackFlags) return false; + + return true; +} + +void CSteamApiUnrigestierCallResultCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_InState, sizeof(m_InState)) + .write((char*)&m_RehldsCallbackId, 4) + .write((char*)&m_SteamApiCall, sizeof(m_SteamApiCall)); +} + +void CSteamApiUnrigestierCallResultCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_InState, sizeof(m_InState)) + .read((char*)&m_RehldsCallbackId, 4) + .read((char*)&m_SteamApiCall, sizeof(m_SteamApiCall)); +} + +void CSteamApiUnrigestierCallResultCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_OutState, sizeof(m_OutState)); +} + +void CSteamApiUnrigestierCallResultCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_OutState, sizeof(m_OutState)); +} + + + +/* ============================================================================ + CSteamAppsCall +============================================================================ */ +std::string CSteamAppsCall::toString() +{ + std::stringstream ss; + ss << "SteamApps( )"; + return ss.str(); +} + +bool CSteamAppsCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamAppsCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CSteamAppsCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_ReturnNull, 1); +} + +void CSteamAppsCall::readEpilogue(std::istream &stream) { + m_ReturnNull = false; + stream.read((char*)&m_ReturnNull, 1); +} + + + + +/* ============================================================================ + CSteamAppGetCurrentGameLanguageCall +============================================================================ */ + +std::string CSteamAppGetCurrentGameLanguageCall::toString() +{ + std::stringstream ss; + ss << "SteamApps::GetCurrentGameLanguage( ) => " << m_Res; + return ss.str(); +} + +void CSteamAppGetCurrentGameLanguageCall::setResult(const char* res) +{ + if (res == NULL) + rehlds_syserror("%s: null result", __FUNCTION__); + + m_ResLen = strlen(res) + 1; + if (m_ResLen > sizeof(m_Res)) + rehlds_syserror("%s: too large result", __FUNCTION__); + + memcpy(m_Res, res, m_ResLen); +} + +bool CSteamAppGetCurrentGameLanguageCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamAppGetCurrentGameLanguageCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CSteamAppGetCurrentGameLanguageCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_ResLen, 4) + .write((char*)&m_Res, m_ResLen); +} + +void CSteamAppGetCurrentGameLanguageCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_ResLen, 4); + stream.read((char*)&m_Res, m_ResLen); +} + + + + + +/* ============================================================================ + CSteamGameServerInitCall +============================================================================ */ +CSteamGameServerInitCall::CSteamGameServerInitCall(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString) +{ + if (pchVersionString == NULL) + rehlds_syserror("%s: version is null", __FUNCTION__); + + m_VersionLen = strlen(pchVersionString) + 1; + if (m_VersionLen > sizeof(m_Version)) + rehlds_syserror("%s: too long version string", __FUNCTION__); + + memcpy(m_Version, pchVersionString, m_VersionLen); + m_IP = unIP; + m_SteamPort = usSteamPort; + m_GamePort = usGamePort; + m_QueryPort = usQueryPort; + m_ServerMode = eServerMode; + m_Res = false; +} + +std::string CSteamGameServerInitCall::toString() +{ + std::stringstream ss; + ss << "SteamGameServer_Init( unIP: " << m_IP << "; usSteamPort: " << m_SteamPort + << "; usQueryPort: " << m_QueryPort << "; eServerMode: " << m_ServerMode + << "; pchVersionString: " << m_Version << " ) => " << m_Res; + return ss.str(); +} + +bool CSteamGameServerInitCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamGameServerInitCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_VersionLen != m_VersionLen) + return false; + + if (strcmp(otherCall->m_Version, m_Version)) + return false; + + if (otherCall->m_IP != m_IP) + return false; + + if (otherCall->m_SteamPort != m_SteamPort) + return false; + + if (otherCall->m_GamePort != m_GamePort) + return false; + + if (otherCall->m_QueryPort != m_QueryPort) + return false; + + if (otherCall->m_ServerMode != m_ServerMode) + return false; + + return true; +} + +void CSteamGameServerInitCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_IP, sizeof(m_IP)) + .write((char*)&m_SteamPort, sizeof(m_SteamPort)) + .write((char*)&m_GamePort, sizeof(m_GamePort)) + .write((char*)&m_QueryPort, sizeof(m_QueryPort)) + .write((char*)&m_ServerMode, sizeof(m_ServerMode)) + .write((char*)&m_VersionLen, sizeof(m_VersionLen)) + .write(m_Version, m_VersionLen); +} + +void CSteamGameServerInitCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 1); +} + +void CSteamGameServerInitCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_IP, sizeof(m_IP)) + .read((char*)&m_SteamPort, sizeof(m_SteamPort)) + .read((char*)&m_GamePort, sizeof(m_GamePort)) + .read((char*)&m_QueryPort, sizeof(m_QueryPort)) + .read((char*)&m_ServerMode, sizeof(m_ServerMode)) + .read((char*)&m_VersionLen, sizeof(m_VersionLen)); + stream.read(m_Version, m_VersionLen); +} + +void CSteamGameServerInitCall::readEpilogue(std::istream &stream) { + m_Res = false; + stream.read((char*)&m_Res, 1); +} + + + + + +/* ============================================================================ + CSteamGameServerCall +============================================================================ */ +std::string CSteamGameServerCall::toString() +{ + std::stringstream ss; + ss << "SteamGameServer( )"; + return ss.str(); +} + +bool CSteamGameServerCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamGameServerCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CSteamGameServerCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_ReturnNull, 1); +} + +void CSteamGameServerCall::readEpilogue(std::istream &stream) { + m_ReturnNull = false; + stream.read((char*)&m_ReturnNull, 1); +} + + + + + +/* ============================================================================ + CGameServerSetProductCall +============================================================================ */ +CGameServerSetProductCall::CGameServerSetProductCall(const char* product) +{ + if (product == NULL) + rehlds_syserror("%s: product is null", __FUNCTION__); + + m_ProductLen = strlen(product) + 1; + if (m_ProductLen > sizeof(m_Product)) + rehlds_syserror("%s: too long product string", __FUNCTION__); + + memcpy(m_Product, product, m_ProductLen); +} + +std::string CGameServerSetProductCall::toString() +{ + std::stringstream ss; + ss << "GS::SetProduct( product: " << m_Product << " ) "; + return ss.str(); +} + +bool CGameServerSetProductCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetProductCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_ProductLen != m_ProductLen) + return false; + + if (strcmp(otherCall->m_Product, m_Product)) + return false; + + return true; +} + +void CGameServerSetProductCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_ProductLen, sizeof(m_ProductLen)) + .write(m_Product, m_ProductLen); +} + +void CGameServerSetProductCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_ProductLen, sizeof(m_ProductLen)); + stream.read(m_Product, m_ProductLen); +} + + + + + +/* ============================================================================ + CGameServerSetModDirCall +============================================================================ */ +CGameServerSetModDirCall::CGameServerSetModDirCall(const char* dir) +{ + if (dir == NULL) + rehlds_syserror("%s: dir is null", __FUNCTION__); + + m_DirLen = strlen(dir) + 1; + if (m_DirLen > sizeof(m_Dir)) + rehlds_syserror("%s: too long dir string", __FUNCTION__); + + memcpy(m_Dir, dir, m_DirLen); +} + +std::string CGameServerSetModDirCall::toString() +{ + std::stringstream ss; + ss << "GS::SetGameDir( gamedir: " << m_Dir << " ) "; + return ss.str(); +} + +bool CGameServerSetModDirCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetModDirCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_DirLen != m_DirLen) + return false; + + if (strcmp(otherCall->m_Dir, m_Dir)) + return false; + + return true; +} + +void CGameServerSetModDirCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_DirLen, sizeof(m_DirLen)) + .write(m_Dir, m_DirLen); +} + +void CGameServerSetModDirCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_DirLen, sizeof(m_DirLen)); + stream.read(m_Dir, m_DirLen); +} + + + + + +/* ============================================================================ + CGameServerSetDedicatedServerCall +============================================================================ */ +CGameServerSetDedicatedServerCall::CGameServerSetDedicatedServerCall(bool dedicated) +{ + m_Dedicated = dedicated; +} + +std::string CGameServerSetDedicatedServerCall::toString() +{ + std::stringstream ss; + ss << "GS::SetDedicatedServer( dedicated: " << m_Dedicated << " ) "; + return ss.str(); +} + +bool CGameServerSetDedicatedServerCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetDedicatedServerCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Dedicated != m_Dedicated) + return false; + + return true; +} + +void CGameServerSetDedicatedServerCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_Dedicated, 1); +} + +void CGameServerSetDedicatedServerCall::readPrologue(std::istream &stream) { + m_Dedicated = false; + stream.read((char*)&m_Dedicated, 1); +} + + + + + +/* ============================================================================ + CGameServerSetGameDescCall +============================================================================ */ +CGameServerSetGameDescCall::CGameServerSetGameDescCall(const char* desc) +{ + if (desc == NULL) + rehlds_syserror("%s: desc is null", __FUNCTION__); + + m_DescLen = strlen(desc) + 1; + if (m_DescLen > sizeof(m_Desc)) + rehlds_syserror("%s: too long dir string", __FUNCTION__); + + memcpy(m_Desc, desc, m_DescLen); +} + +std::string CGameServerSetGameDescCall::toString() +{ + std::stringstream ss; + ss << "GS::SetGameDescription( description: " << m_Desc << " ) "; + return ss.str(); +} + +bool CGameServerSetGameDescCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetGameDescCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_DescLen != m_DescLen) + return false; + + if (strcmp(otherCall->m_Desc, m_Desc)) + return false; + + return true; +} + +void CGameServerSetGameDescCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_DescLen, sizeof(m_DescLen)) + .write(m_Desc, m_DescLen); +} + +void CGameServerSetGameDescCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_DescLen, sizeof(m_DescLen)); + stream.read(m_Desc, m_DescLen); +} + + + + +/* ============================================================================ + CGameServerLogOnAnonymousCall +============================================================================ */ +std::string CGameServerLogOnAnonymousCall::toString() +{ + std::stringstream ss; + ss << "GS::LogOnAnonymous( ) "; + return ss.str(); +} + +bool CGameServerLogOnAnonymousCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerLogOnAnonymousCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + + + + + +/* ============================================================================ + CGameServerEnableHeartbeatsCall +============================================================================ */ +CGameServerEnableHeartbeatsCall::CGameServerEnableHeartbeatsCall(bool hearbeats) +{ + m_Heartbeats = hearbeats; +} + +std::string CGameServerEnableHeartbeatsCall::toString() +{ + std::stringstream ss; + ss << "GS::EnableHeartbeats( active: " << m_Heartbeats << " ) "; + return ss.str(); +} + +bool CGameServerEnableHeartbeatsCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerEnableHeartbeatsCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Heartbeats != m_Heartbeats) + return false; + + return true; +} + +void CGameServerEnableHeartbeatsCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_Heartbeats, 1); +} + +void CGameServerEnableHeartbeatsCall::readPrologue(std::istream &stream) { + m_Heartbeats = false; + stream.read((char*)&m_Heartbeats, 1); +} + + + + + +/* ============================================================================ + CGameServerSetHeartbeatIntervalCall +============================================================================ */ +CGameServerSetHeartbeatIntervalCall::CGameServerSetHeartbeatIntervalCall(int interval) +{ + m_Interval = interval; +} + +std::string CGameServerSetHeartbeatIntervalCall::toString() +{ + std::stringstream ss; + ss << "GS::SetHeartbeatInterval( interval: " << m_Interval << " ) "; + return ss.str(); +} + +bool CGameServerSetHeartbeatIntervalCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetHeartbeatIntervalCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Interval != m_Interval) + return false; + + return true; +} + +void CGameServerSetHeartbeatIntervalCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_Interval, 4); +} + +void CGameServerSetHeartbeatIntervalCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_Interval, 4); +} + + + + +/* ============================================================================ + CGameServerSetMaxPlayersCall +============================================================================ */ +CGameServerSetMaxPlayersCall::CGameServerSetMaxPlayersCall(int maxPlayers) +{ + m_MaxPlayers = maxPlayers; +} + +std::string CGameServerSetMaxPlayersCall::toString() +{ + std::stringstream ss; + ss << "GS::ServerSetMaxPlayersCount( count: " << m_MaxPlayers << " ) "; + return ss.str(); +} + +bool CGameServerSetMaxPlayersCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetMaxPlayersCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_MaxPlayers != m_MaxPlayers) + return false; + + return true; +} + +void CGameServerSetMaxPlayersCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_MaxPlayers, 4); +} + +void CGameServerSetMaxPlayersCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_MaxPlayers, 4); +} + + + + + +/* ============================================================================ + CGameServerSetBotCountCall +============================================================================ */ +CGameServerSetBotCountCall::CGameServerSetBotCountCall(int numBots) +{ + m_NumBots = numBots; +} + +std::string CGameServerSetBotCountCall::toString() +{ + std::stringstream ss; + ss << "GS::SetBotCount( count: " << m_NumBots << " ) "; + return ss.str(); +} + +bool CGameServerSetBotCountCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetBotCountCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_NumBots != m_NumBots) + return false; + + return true; +} + +void CGameServerSetBotCountCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_NumBots, 4); +} + +void CGameServerSetBotCountCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_NumBots, 4); +} + + + + + +/* ============================================================================ + CGameServerSetServerNameCall +============================================================================ */ +CGameServerSetServerNameCall::CGameServerSetServerNameCall(const char* serverName) +{ + if (serverName == NULL) + rehlds_syserror("%s: serverName is null", __FUNCTION__); + + m_ServerNameLen = strlen(serverName) + 1; + if (m_ServerNameLen > sizeof(m_ServerName)) + rehlds_syserror("%s: too long serverName string", __FUNCTION__); + + memcpy(m_ServerName, serverName, m_ServerNameLen); +} + +std::string CGameServerSetServerNameCall::toString() +{ + std::stringstream ss; + ss << "GS::SetServerName( serverName: " << m_ServerName << " ) "; + return ss.str(); +} + +bool CGameServerSetServerNameCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetServerNameCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_ServerNameLen != m_ServerNameLen) + return false; + + if (strcmp(otherCall->m_ServerName, m_ServerName)) + return false; + + return true; +} + +void CGameServerSetServerNameCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_ServerNameLen, sizeof(m_ServerNameLen)) + .write(m_ServerName, m_ServerNameLen); +} + +void CGameServerSetServerNameCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_ServerNameLen, sizeof(m_ServerNameLen)); + stream.read(m_ServerName, m_ServerNameLen); +} + + + + + +/* ============================================================================ + CGameServerSetMapNameCall +============================================================================ */ +CGameServerSetMapNameCall::CGameServerSetMapNameCall(const char* mapName) +{ + if (mapName == NULL) + rehlds_syserror("%s: serverName is null", __FUNCTION__); + + m_MapNameLen = strlen(mapName) + 1; + if (m_MapNameLen > sizeof(m_MapName)) + rehlds_syserror("%s: too long mapName string", __FUNCTION__); + + memcpy(m_MapName, mapName, m_MapNameLen); +} + +std::string CGameServerSetMapNameCall::toString() +{ + std::stringstream ss; + ss << "GS::SetMapName( serverName: " << m_MapName << " ) "; + return ss.str(); +} + +bool CGameServerSetMapNameCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetMapNameCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_MapNameLen != m_MapNameLen) + return false; + + if (strcmp(otherCall->m_MapName, m_MapName)) + return false; + + return true; +} + +void CGameServerSetMapNameCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_MapNameLen, sizeof(m_MapNameLen)) + .write(m_MapName, m_MapNameLen); +} + +void CGameServerSetMapNameCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_MapNameLen, sizeof(m_MapNameLen)); + stream.read(m_MapName, m_MapNameLen); +} + + + + + +/* ============================================================================ + CGameServerSetPasswordProtectedCall +============================================================================ */ +CGameServerSetPasswordProtectedCall::CGameServerSetPasswordProtectedCall(bool passwordProtected) +{ + m_PasswordProtected = passwordProtected; +} + +std::string CGameServerSetPasswordProtectedCall::toString() +{ + std::stringstream ss; + ss << "GS::SetPasswordProtected( protected: " << m_PasswordProtected << " ) "; + return ss.str(); +} + +bool CGameServerSetPasswordProtectedCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetPasswordProtectedCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_PasswordProtected != m_PasswordProtected) + return false; + + return true; +} + +void CGameServerSetPasswordProtectedCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_PasswordProtected, 1); +} + +void CGameServerSetPasswordProtectedCall::readPrologue(std::istream &stream) { + m_PasswordProtected = false; + stream.read((char*)&m_PasswordProtected, 1); +} + + + + + +/* ============================================================================ + CGameServerClearAllKVsCall +============================================================================ */ +std::string CGameServerClearAllKVsCall::toString() +{ + std::stringstream ss; + ss << "GS::ClearAllKeyValues( ) "; + return ss.str(); +} + +bool CGameServerClearAllKVsCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerClearAllKVsCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + + + + + +/* ============================================================================ + CGameServerSetKeyValueCall +============================================================================ */ +CGameServerSetKeyValueCall::CGameServerSetKeyValueCall(const char* key, const char* value) +{ + if (key == NULL) + rehlds_syserror("%s: key is null", __FUNCTION__); + + m_KeyLen = strlen(key) + 1; + if (m_KeyLen > sizeof(m_Key)) + rehlds_syserror("%s: too long key string", __FUNCTION__); + + memcpy(m_Key, key, m_KeyLen); + + if (value == NULL) + rehlds_syserror("%s: value is null", __FUNCTION__); + + m_ValueLen = strlen(value) + 1; + if (m_ValueLen > sizeof(m_Value)) + rehlds_syserror("%s: too long value string", __FUNCTION__); + + memcpy(m_Value, value, m_ValueLen); +} + +std::string CGameServerSetKeyValueCall::toString() +{ + std::stringstream ss; + ss << "GS::SetKeyValue( key: '" << m_Key << "'; value:'" << m_Value << "' ) "; + return ss.str(); +} + +bool CGameServerSetKeyValueCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSetKeyValueCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_KeyLen != m_KeyLen) + return false; + + if (otherCall->m_ValueLen != m_ValueLen) + return false; + + if (strcmp(otherCall->m_Key, m_Key)) + return false; + + if (strcmp(otherCall->m_Value, m_Value)) + return false; + + return true; +} + +void CGameServerSetKeyValueCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_ValueLen, sizeof(m_ValueLen)) + .write((char*)&m_KeyLen, sizeof(m_KeyLen)) + .write(m_Value, m_ValueLen) + .write(m_Key, m_KeyLen); +} + +void CGameServerSetKeyValueCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_ValueLen, sizeof(m_ValueLen)) + .read((char*)&m_KeyLen, sizeof(m_KeyLen)); + + stream + .read(m_Value, m_ValueLen) + .read(m_Key, m_KeyLen); +} + + + + +/* ============================================================================ + CSteamApiSetBreakpadAppIdCall +============================================================================ */ +CSteamApiSetBreakpadAppIdCall::CSteamApiSetBreakpadAppIdCall(uint32_t appId) +{ + m_AppId = appId; +} + +std::string CSteamApiSetBreakpadAppIdCall::toString() +{ + std::stringstream ss; + ss << "SteamAPI_SetBreakpadAppID( count: " << m_AppId << " ) "; + return ss.str(); +} + +bool CSteamApiSetBreakpadAppIdCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamApiSetBreakpadAppIdCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_AppId != m_AppId) + return false; + + return true; +} + +void CSteamApiSetBreakpadAppIdCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_AppId, 4); +} + +void CSteamApiSetBreakpadAppIdCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_AppId, 4); +} + + + + + + +/* ============================================================================ + CGameServerWasRestartRequestedCall +============================================================================ */ +std::string CGameServerWasRestartRequestedCall::toString() +{ + std::stringstream ss; + ss << "GS::WasRestartRequested() => " << m_Result; + return ss.str(); +} + +bool CGameServerWasRestartRequestedCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerWasRestartRequestedCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGameServerWasRestartRequestedCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_Result, 1); +} + +void CGameServerWasRestartRequestedCall::readPrologue(std::istream &stream) { + m_Result = false; + stream.read((char*)&m_Result, 1); +} + + + + + +/* ============================================================================ + CSteamGameServerRunCallbacksCall +============================================================================ */ +std::string CSteamGameServerRunCallbacksCall::toString() +{ + std::stringstream ss; + ss << "SteamGameServer_RunCallbacks()"; + return ss.str(); +} + +bool CSteamGameServerRunCallbacksCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamGameServerRunCallbacksCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + + + + + +/* ============================================================================ + CGameServerGetNextOutgoingPacketCall +============================================================================ */ +CGameServerGetNextOutgoingPacketCall::CGameServerGetNextOutgoingPacketCall(int maxOut) +{ + m_MaxOut = maxOut; + m_BufLen = m_Result = 0; m_Addr = 0; m_Port = 0; +} + +void CGameServerGetNextOutgoingPacketCall::setResult(void* buf, int res, uint32* pAddr, uint16* pPort) +{ + m_BufLen = res > 0 ? res : 0; + if (m_BufLen > 0) { + if (m_BufLen > sizeof(m_Buf)) + rehlds_syserror("%s: too long buffer returned", __FUNCTION__); + + memcpy(m_Buf, buf, m_BufLen); + } + m_Result = res; + + if (pAddr == NULL) + rehlds_syserror("%s: pAddr is NULL", __FUNCTION__); + + if (pPort == NULL) + rehlds_syserror("%s: pPort is NULL", __FUNCTION__); + + m_Addr = *pAddr; + m_Port = *pPort; +} + +std::string CGameServerGetNextOutgoingPacketCall::toString() +{ + std::stringstream ss; + ss << "GS::GetNextOutgoingPacket(buf: "; PrintBinaryArray(m_Buf, m_BufLen, ss); + ss << ", maxOut: " << m_MaxOut << ", addr: " << m_Addr << ", port: " << m_Port << " ) => " << m_Result; + + return ss.str(); +} + +bool CGameServerGetNextOutgoingPacketCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerGetNextOutgoingPacketCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_MaxOut != this->m_MaxOut) + return false; + + return true; +} + +void CGameServerGetNextOutgoingPacketCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_MaxOut, 4); + +} + +void CGameServerGetNextOutgoingPacketCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_Result, 4) + .write((char*)&m_Addr, 4) + .write((char*)&m_Port, 2) + .write((char*)&m_BufLen, 4) + .write(m_Buf, m_BufLen); +} + +void CGameServerGetNextOutgoingPacketCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_MaxOut, 4); + +} + +void CGameServerGetNextOutgoingPacketCall::readEpilogue(std::istream &stream) { + stream + .read((char*)&m_Result, 4) + .read((char*)&m_Addr, 4) + .read((char*)&m_Port, 2) + .read((char*)&m_BufLen, 4); + + stream.read(m_Buf, m_BufLen); +} + + + +/* ============================================================================ + CSteamApiRunCallbacksCall +============================================================================ */ +std::string CSteamApiRunCallbacksCall::toString() +{ + std::stringstream ss; + ss << "SteamAPI_RunCallbacks()"; + return ss.str(); +} + +bool CSteamApiRunCallbacksCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamApiRunCallbacksCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + + + + + +/* ============================================================================ + CGameServerGetSteamIdCall +============================================================================ */ +std::string CGameServerGetSteamIdCall::toString() +{ + std::stringstream ss; + ss << "GS::GetSteamId( ) => " << m_SteamId; + + return ss.str(); +} + +bool CGameServerGetSteamIdCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerGetSteamIdCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGameServerGetSteamIdCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_SteamId, 8); +} + +void CGameServerGetSteamIdCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_SteamId, 8); +} + + + + +/* ============================================================================ + CGameServerBSecureCall +============================================================================ */ +std::string CGameServerBSecureCall::toString() +{ + std::stringstream ss; + ss << "GS::BSecure( ) => " << m_Res; + + return ss.str(); +} + +bool CGameServerBSecureCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerBSecureCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGameServerBSecureCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 1); +} + +void CGameServerBSecureCall::readEpilogue(std::istream &stream) { + m_Res = false; + stream.read((char*)&m_Res, 1); +} + + + + +/* ============================================================================ + CGameServerHandleIncomingPacketCall +============================================================================ */ + +CGameServerHandleIncomingPacketCall::CGameServerHandleIncomingPacketCall(const void *pData, int cbData, uint32 srcIP, uint16 srcPort) +{ + m_Len = cbData; + if (m_Len > sizeof(m_Data)) + rehlds_syserror("%s: too long packet", __FUNCTION__); + + memcpy(m_Data, pData, m_Len); + m_Ip = srcIP; + m_Port = srcPort; + m_Res = false; +} + +std::string CGameServerHandleIncomingPacketCall::toString() +{ + std::stringstream ss; + ss << "GS::CGameServerHandleIncomingPacketCall(data: "; PrintBinaryArray(m_Data, m_Len, ss); + ss << ", len: " << m_Len << ", ip: " << m_Ip << ", port: " << m_Port << ") => " << m_Res; + + return ss.str(); +} + +bool CGameServerHandleIncomingPacketCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerHandleIncomingPacketCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (m_Len != otherCall->m_Len) + return false; + + if (memcmp(m_Data, otherCall->m_Data, m_Len)) + return false; + + if (m_Ip != otherCall->m_Ip || m_Port != otherCall->m_Port) + return false; + + return true; +} + +void CGameServerHandleIncomingPacketCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_Ip, 4) + .write((char*)&m_Port, 2) + .write((char*)&m_Len, 4) + .write(m_Data, m_Len); +} + +void CGameServerHandleIncomingPacketCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_Ip, 4) + .read((char*)&m_Port, 2) + .read((char*)&m_Len, 4); + + stream.read(m_Data, m_Len); +} + +void CGameServerHandleIncomingPacketCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 1); +} + +void CGameServerHandleIncomingPacketCall::readEpilogue(std::istream &stream) { + m_Res = false; + stream.read((char*)&m_Res, 1); +} + + + + + +/* ============================================================================ + CGameServerSendUserConnectAndAuthenticateCall +============================================================================ */ +CGameServerSendUserConnectAndAuthenticateCall::CGameServerSendUserConnectAndAuthenticateCall(uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize) +{ + m_AuthBlobLen = cubAuthBlobSize; + if (m_AuthBlobLen > sizeof(m_AuthBlob)) + rehlds_syserror("%s: too long auth blob", __FUNCTION__); + + memcpy(m_AuthBlob, pvAuthBlob, m_AuthBlobLen); + m_IP = unIPClient; + m_OutSteamId = 0; + m_Res = false; +} + +std::string CGameServerSendUserConnectAndAuthenticateCall::toString() +{ + std::stringstream ss; + ss << "GS::CGameServerSendUserConnectAndAuthenticateCall(ip: " << m_IP << "authBlob: "; PrintBinaryArray(m_AuthBlob, m_AuthBlobLen, ss); + ss << ", authBlobLen: " << m_AuthBlobLen << ", steamId: " << m_OutSteamId << ") => " << m_Res; + + return ss.str(); +} + +bool CGameServerSendUserConnectAndAuthenticateCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSendUserConnectAndAuthenticateCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (m_AuthBlobLen != otherCall->m_AuthBlobLen) + return false; + + if (strict) { + if (memcmp(m_AuthBlob, otherCall->m_AuthBlob, m_AuthBlobLen)) + return false; + } + + if (m_IP != otherCall->m_IP) + return false; + + return true; +} + +void CGameServerSendUserConnectAndAuthenticateCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_IP, 4) + .write((char*)&m_AuthBlobLen, 4) + .write(m_AuthBlob, m_AuthBlobLen); +} + +void CGameServerSendUserConnectAndAuthenticateCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_IP, 4) + .read((char*)&m_AuthBlobLen, 4); + + stream.read(m_AuthBlob, m_AuthBlobLen); +} + +void CGameServerSendUserConnectAndAuthenticateCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_OutSteamId, 8) + .write((char*)&m_Res, 1); +} + +void CGameServerSendUserConnectAndAuthenticateCall::readEpilogue(std::istream &stream) { + m_Res = false; + stream + .read((char*)&m_OutSteamId, 8) + .read((char*)&m_Res, 1); +} + + + + + +/* ============================================================================ + CGameServerSendUserDisconnectCall +============================================================================ */ +std::string CGameServerSendUserDisconnectCall::toString() +{ + std::stringstream ss; + ss << "GS::CGameServerSendUserDisconnectCall(steamId: " << m_SteamId << ") "; + return ss.str(); +} + +bool CGameServerSendUserDisconnectCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerSendUserDisconnectCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (m_SteamId != otherCall->m_SteamId) + return false; + + return true; +} + +void CGameServerSendUserDisconnectCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_SteamId, 8); +} + +void CGameServerSendUserDisconnectCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_SteamId, 8); +} + + + + + +/* ============================================================================ + CGameServerBUpdateUserDataCall +============================================================================ */ +CGameServerBUpdateUserDataCall::CGameServerBUpdateUserDataCall(CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore) +{ + m_PlayerNameLen = strlen(pchPlayerName) + 1; + if (m_PlayerNameLen > sizeof(m_PlayerName)) + rehlds_syserror("%s: too long player name", __FUNCTION__); + + memcpy(m_PlayerName, pchPlayerName, m_PlayerNameLen); + m_SteamId = steamIDUser.ConvertToUint64(); + m_Score = uScore; +} + +std::string CGameServerBUpdateUserDataCall::toString() +{ + std::stringstream ss; + ss << "GS::BUpdateUserData(steamIDUser: " << m_SteamId << "playerName: "; PrintBinaryArray(m_PlayerName, m_PlayerNameLen, ss); + ss << ", uScore: " << m_Score << " ) => " << m_Res; + + return ss.str(); +} + +bool CGameServerBUpdateUserDataCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerBUpdateUserDataCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (m_PlayerNameLen != otherCall->m_PlayerNameLen) + return false; + + if (memcmp(m_PlayerName, otherCall->m_PlayerName, m_PlayerNameLen)) + return false; + + if (m_SteamId != otherCall->m_SteamId) + return false; + + if (m_Score != otherCall->m_Score) + return false; + + return true; +} + +void CGameServerBUpdateUserDataCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_SteamId, 8) + .write((char*)&m_Score, 4) + .write((char*)&m_PlayerNameLen, 4) + .write(m_PlayerName, m_PlayerNameLen); +} + +void CGameServerBUpdateUserDataCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_SteamId, 8) + .read((char*)&m_Score, 4) + .read((char*)&m_PlayerNameLen, 4); + + stream.read(m_PlayerName, m_PlayerNameLen); +} + +void CGameServerBUpdateUserDataCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 1); +} + +void CGameServerBUpdateUserDataCall::readEpilogue(std::istream &stream) { + m_Res = false; + stream.read((char*)&m_Res, 1); +} + + + + +/* ============================================================================ + CGameServerCreateUnauthUserConnectionCall +============================================================================ */ +std::string CGameServerCreateUnauthUserConnectionCall::toString() +{ + std::stringstream ss; + ss << "GS::CreateUnauthUserConnection() => " << m_SteamId; + + return ss.str(); +} + +bool CGameServerCreateUnauthUserConnectionCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerCreateUnauthUserConnectionCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + + +void CGameServerCreateUnauthUserConnectionCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_SteamId, 8); +} + +void CGameServerCreateUnauthUserConnectionCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_SteamId, 8); +} + + + + + +/* ============================================================================ + CGetHostNameCall +============================================================================ */ +std::string CGetHostNameCall::toString() +{ + std::stringstream ss; + ss << "gethostname(name: " << m_Name << "; nameLen: " << m_NameLenIn << " ) => " << m_Res; + + return ss.str(); +} + +bool CGetHostNameCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetHostNameCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_NameLenIn != this->m_NameLenIn) + return false; + + return true; +} + +void CGetHostNameCall::setResult(char* hostName, int res) { + m_NameLenOut = strlen(hostName) + 1; + + if (m_NameLenOut > sizeof(m_Name)) + rehlds_syserror("%s: too long host name", __FUNCTION__); + + strcpy(m_Name, hostName); + m_Res = res; +} + +void CGetHostNameCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_NameLenIn, 4); +} + +void CGetHostNameCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_NameLenIn, 4); +} + +void CGetHostNameCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_NameLenOut, 4) + .write((char*)&m_Res, 4) + .write(m_Name, m_NameLenOut); +} + +void CGetHostNameCall::readEpilogue(std::istream &stream) { + stream + .read((char*)&m_NameLenOut, 4) + .read((char*)&m_Res, 4); + + stream.read(m_Name, m_NameLenOut); +} + + + + +/* ============================================================================ + CGetHostByNameCall +============================================================================ */ +CGetHostByNameCall::CGetHostByNameCall(const char* name) +{ + m_NameLen = strlen(name) + 1; + if (m_NameLen > sizeof(m_Name)) + rehlds_syserror("%s: too long name", __FUNCTION__); + + strcpy(m_Name, name); +} + +std::string CGetHostByNameCall::toString() +{ + std::stringstream ss; + ss << "gethostbyname(name: " << m_Name << " ) => <>"; + + return ss.str(); +} + +bool CGetHostByNameCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetHostByNameCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_NameLen != this->m_NameLen) + return false; + + if (strcmp(otherCall->m_Name, this->m_Name)) + return false; + + return true; +} + +void CGetHostByNameCall::setResult(const hostent* hostEnt) { + m_HostentData.hostNameLen = strlen(hostEnt->h_name) + 1; + if (m_HostentData.hostNameLen > sizeof(m_HostentData.hostName)) { + rehlds_syserror("%s: too long host name", __FUNCTION__); + } + + strcpy(m_HostentData.hostName, hostEnt->h_name); + int i = 0; + while (hostEnt->h_aliases[i]) { + if (i >= HOSTENT_DATA_MAX_ALIASES) { + rehlds_syserror("%s: too many aliases", __FUNCTION__); + } + + m_HostentData.aliasesLengths[i] = strlen(hostEnt->h_aliases[i]) + 1; + if (m_HostentData.aliasesLengths[i] > sizeof(m_HostentData.aliases[i])) { + rehlds_syserror("%s: too long alias", __FUNCTION__); + } + + strcpy(m_HostentData.aliases[i], hostEnt->h_aliases[i]); + i++; + } + m_HostentData.numAliases = i; + + m_HostentData.addrtype = hostEnt->h_addrtype; + m_HostentData.addrLen = hostEnt->h_length; + if (m_HostentData.addrLen > sizeof(m_HostentData.addrs[0])) { + rehlds_syserror("%s: too long addr", __FUNCTION__); + } + + i = 0; + while (hostEnt->h_addr_list[i]) { + if (i >= HOSTENT_DATA_MAX_ADDRS) { + rehlds_syserror("%s: too many addrs", __FUNCTION__); + } + + memcpy(m_HostentData.addrs[i], hostEnt->h_addr_list[i], m_HostentData.addrLen); + i++; + } + m_HostentData.numAddrs = i; +} + +void CGetHostByNameCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_NameLen, 4).write(m_Name, m_NameLen); +} + +void CGetHostByNameCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_NameLen, 4); + stream.read(m_Name, m_NameLen); +} + +void CGetHostByNameCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_HostentData.hostNameLen, 4) + .write((char*)&m_HostentData.numAddrs, 4) + .write((char*)&m_HostentData.numAliases, 4) + .write((char*)&m_HostentData.addrLen, 2) + .write((char*)&m_HostentData.addrtype, 2) + .write(m_HostentData.hostName, m_HostentData.hostNameLen) + .write((char*)&m_HostentData.aliasesLengths[0], 4 * m_HostentData.numAliases); + + for (int i = 0; i < m_HostentData.numAliases; i++) { + stream.write(m_HostentData.aliases[i], m_HostentData.aliasesLengths[i]); + } + + for (int i = 0; i < m_HostentData.numAddrs; i++) { + stream.write(m_HostentData.addrs[i], m_HostentData.addrLen); + } +} + +void CGetHostByNameCall::readEpilogue(std::istream &stream) { + stream + .read((char*)&m_HostentData.hostNameLen, 4) + .read((char*)&m_HostentData.numAddrs, 4) + .read((char*)&m_HostentData.numAliases, 4) + .read((char*)&m_HostentData.addrLen, 2) + .read((char*)&m_HostentData.addrtype, 2); + + stream + .read(m_HostentData.hostName, m_HostentData.hostNameLen) + .read((char*)&m_HostentData.aliasesLengths[0], 4 * m_HostentData.numAliases); + + for (int i = 0; i < m_HostentData.numAliases; i++) { + stream.read(m_HostentData.aliases[i], m_HostentData.aliasesLengths[i]); + } + + for (int i = 0; i < m_HostentData.numAddrs; i++) { + stream.read(m_HostentData.addrs[i], m_HostentData.addrLen); + } +} + + + + + +/* ============================================================================ + CGetProcessTimesCall +============================================================================ */ +std::string CGetProcessTimesCall::toString() +{ + std::stringstream ss; + + ss << "GetProcessTimes( creationTime: "; PrintFileTime(&m_CreationTime, ss); + ss << "; exitTime: "; PrintFileTime(&m_ExitTime, ss); + ss << "; kernelTime: "; PrintFileTime(&m_KernelTime, ss); + ss << "; userTime: "; PrintFileTime(&m_UserTime, ss); + ss << " ) => " << m_Res; + return ss.str(); +} + +bool CGetProcessTimesCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetProcessTimesCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGetProcessTimesCall::setResult(BOOL res, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) +{ + m_Res = res; + memcpy(&m_CreationTime, lpCreationTime, sizeof(m_CreationTime)); + memcpy(&m_ExitTime, lpExitTime, sizeof(m_ExitTime)); + memcpy(&m_KernelTime, lpKernelTime, sizeof(m_KernelTime)); + memcpy(&m_UserTime, lpUserTime, sizeof(m_UserTime)); +} + +void CGetProcessTimesCall::writeEpilogue(std::ostream &stream) { + stream + .write((char*)&m_CreationTime, sizeof(m_CreationTime)) + .write((char*)&m_ExitTime, sizeof(m_ExitTime)) + .write((char*)&m_KernelTime, sizeof(m_KernelTime)) + .write((char*)&m_UserTime, sizeof(m_UserTime)) + .write((char*)&m_Res, 1); +} + +void CGetProcessTimesCall::readEpilogue(std::istream &stream) { + m_Res = 0; + stream + .read((char*)&m_CreationTime, sizeof(m_CreationTime)) + .read((char*)&m_ExitTime, sizeof(m_ExitTime)) + .read((char*)&m_KernelTime, sizeof(m_KernelTime)) + .read((char*)&m_UserTime, sizeof(m_UserTime)) + .read((char*)&m_Res, 1); +} + + + + +/* ============================================================================ + CGetSystemTimeAsFileTimeCall +============================================================================ */ +std::string CGetSystemTimeAsFileTimeCall::toString() +{ + std::stringstream ss; + + ss << "GetSystemTimeAsFileTime( systemTime: "; PrintFileTime(&m_SystemTime, ss); + ss << " )"; + return ss.str(); +} + +bool CGetSystemTimeAsFileTimeCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGetSystemTimeAsFileTimeCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGetSystemTimeAsFileTimeCall::setResult(LPFILETIME systemTime) +{ + memcpy(&m_SystemTime, systemTime, sizeof(m_SystemTime)); +} + +void CGetSystemTimeAsFileTimeCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_SystemTime, sizeof(m_SystemTime)); +} + +void CGetSystemTimeAsFileTimeCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_SystemTime, sizeof(m_SystemTime)); +} + + + + + +/* ============================================================================ + CStdTimeCall +============================================================================ */ +CStdTimeCall::CStdTimeCall(uint32_t* inTime) +{ + m_InTimeNull = (inTime == NULL); +} + +std::string CStdTimeCall::toString() +{ + std::stringstream ss; + + ss << "time( isNull: " << m_InTimeNull << ") => " << m_Res; + return ss.str(); +} + +bool CStdTimeCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CStdTimeCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_InTimeNull != this->m_InTimeNull) + return false; + + return true; +} + +void CStdTimeCall::setResult(uint32_t res) +{ + m_Res = res; +} + +void CStdTimeCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_InTimeNull, 1); +} + +void CStdTimeCall::readPrologue(std::istream &stream) { + m_InTimeNull = false; + stream.read((char*)&m_InTimeNull, 1); +} + +void CStdTimeCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CStdTimeCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, 4); +} + + + + + +/* ============================================================================ + CStdLocalTimeCall +============================================================================ */ +CStdLocalTimeCall::CStdLocalTimeCall(uint32_t inTime) +{ + m_Time = inTime; +} + +std::string CStdLocalTimeCall::toString() +{ + std::stringstream ss; + + ss << "localTime( time: " << m_Time << ") => "; + PrintTm(&m_Res, ss); + return ss.str(); +} + +bool CStdLocalTimeCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CStdLocalTimeCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Time != this->m_Time) + return false; + + return true; +} + +void CStdLocalTimeCall::setResult(struct tm *res) +{ + memcpy(&m_Res, res, sizeof(m_Res)); +} + +void CStdLocalTimeCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_Time, 4); +} + +void CStdLocalTimeCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_Time, 4); +} + +void CStdLocalTimeCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, sizeof(m_Res)); +} + +void CStdLocalTimeCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, sizeof(m_Res)); +} + + + + + +/* ============================================================================ + CStdSrandCall +============================================================================ */ +std::string CStdSrandCall::toString() +{ + std::stringstream ss; + + ss << "srand( seed: " << m_Seed << ") "; + return ss.str(); +} + +bool CStdSrandCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CStdSrandCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_Seed != this->m_Seed) + return false; + + return true; +} + +void CStdSrandCall::writePrologue(std::ostream &stream) { + stream.write((char*)&m_Seed, 4); +} + +void CStdSrandCall::readPrologue(std::istream &stream) { + stream.read((char*)&m_Seed, 4); +} + + + + + +/* ============================================================================ + CStdRandCall +============================================================================ */ +std::string CStdRandCall::toString() +{ + std::stringstream ss; + + ss << "rand( ) => " << m_Res; + return ss.str(); +} + +bool CStdRandCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CStdRandCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CStdRandCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 4); +} + +void CStdRandCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_Res, 4); +} + + + + + +/* ============================================================================ + CGameServerLogOffCall +============================================================================ */ +std::string CGameServerLogOffCall::toString() +{ + std::stringstream ss; + + ss << "GS:LogOff( ) "; + return ss.str(); +} + +bool CGameServerLogOffCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerLogOffCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + + + + +/* ============================================================================ + CSteamGameServerShutdownCall +============================================================================ */ +std::string CSteamGameServerShutdownCall::toString() +{ + std::stringstream ss; + + ss << "SteamGameServer_Shutdown( ) "; + return ss.str(); +} + +bool CSteamGameServerShutdownCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamGameServerShutdownCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + + + + + +/* ============================================================================ + CSteamApiUnregisterCallbackCall +============================================================================ */ +CSteamApiUnregisterCallbackCall::CSteamApiUnregisterCallbackCall(int rehldsCallbackId, CCallbackBase* cb) +{ + m_RehldsCallbackId = rehldsCallbackId; + m_InState.m_iCallback = cb->GetICallback(); + m_InState.m_nCallbackFlags = cb->GetFlags(); + m_OutState.clear(); +} + +std::string CSteamApiUnregisterCallbackCall::toString() +{ + std::stringstream ss; + ss << "SteamAPI_UnregisterCallback( rehldsCallbackId: " << m_RehldsCallbackId << " )"; + return ss.str(); +} + +bool CSteamApiUnregisterCallbackCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CSteamApiUnregisterCallbackCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + if (otherCall->m_RehldsCallbackId != m_RehldsCallbackId) + return false; + + if (otherCall->m_InState.m_iCallback != m_InState.m_iCallback) return false; + if (otherCall->m_InState.m_nCallbackFlags != m_InState.m_nCallbackFlags) return false; + + return true; +} + +void CSteamApiUnregisterCallbackCall::writePrologue(std::ostream &stream) { + stream + .write((char*)&m_InState, sizeof(m_InState)) + .write((char*)&m_RehldsCallbackId, 4); +} + +void CSteamApiUnregisterCallbackCall::readPrologue(std::istream &stream) { + stream + .read((char*)&m_InState, sizeof(m_InState)) + .read((char*)&m_RehldsCallbackId, 4); +} + +void CSteamApiUnregisterCallbackCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_OutState, sizeof(m_OutState)); +} + +void CSteamApiUnregisterCallbackCall::readEpilogue(std::istream &stream) { + stream.read((char*)&m_OutState, sizeof(m_OutState)); +} + + + + +/* ============================================================================ + CGameServerBLoggedOnCall +============================================================================ */ +std::string CGameServerBLoggedOnCall::toString() +{ + std::stringstream ss; + ss << "GS::BLoggedOn( ) => " << m_Res; + + return ss.str(); +} + +bool CGameServerBLoggedOnCall::compareInputArgs(IEngExtCall* other, bool strict) +{ + CGameServerBLoggedOnCall* otherCall = dynamic_cast(other); + if (otherCall == NULL) + return false; + + return true; +} + +void CGameServerBLoggedOnCall::writeEpilogue(std::ostream &stream) { + stream.write((char*)&m_Res, 1); +} + +void CGameServerBLoggedOnCall::readEpilogue(std::istream &stream) { + m_Res = false; + stream.read((char*)&m_Res, 1); +} + +/* +class CGameServerBLoggedOnCall : public IEngExtCall { +public: +bool m_Res; + +public: +CGameServerBLoggedOnCall() { m_Res = false; } + +void setResult(bool res) { m_Res = res; } +virtual bool compareInputArgs(IEngExtCall* other); +virtual std::string toString(); +virtual ExtCallFuncs getOpcode() { return ECF_GS_BLOGGEDON; } +virtual void writeEpilogue(std::ostream &stream); +virtual void readEpilogue(std::istream &stream); +}; +*/ + +#define IEngExtCallFactory_CreateFuncCall(clazz, buf, bufLen) \ + if (sizeof(clazz) > bufLen) rehlds_syserror("%s: buffer to small", __FUNCTION__); \ + return new(buf) clazz(); + +IEngExtCall* IEngExtCallFactory::createByOpcode(ExtCallFuncs opc, void* buf, int ptrSize) { + switch (opc) { + case ECF_SLEEP: IEngExtCallFactory_CreateFuncCall(CSleepExtCall, buf, ptrSize); + case ECF_QUERY_PERF_FREQ: IEngExtCallFactory_CreateFuncCall(CQueryPerfFreqCall, buf, ptrSize); + case ECF_QUERY_PERF_COUNTER: IEngExtCallFactory_CreateFuncCall(CQueryPerfCounterCall, buf, ptrSize); + case ECF_GET_TICK_COUNT: IEngExtCallFactory_CreateFuncCall(CGetTickCountCall, buf, ptrSize); + case ECF_GET_LOCAL_TIME: IEngExtCallFactory_CreateFuncCall(CGetLocalTimeCall, buf, ptrSize); + case ECF_GET_SYSTEM_TIME: IEngExtCallFactory_CreateFuncCall(CGetSystemTimeCall, buf, ptrSize); + case ECF_GET_TIMEZONE_INFO: IEngExtCallFactory_CreateFuncCall(CGetTimeZoneInfoCall, buf, ptrSize); + + case ECF_SOCKET: IEngExtCallFactory_CreateFuncCall(CSocketCall, buf, ptrSize); + case ECF_IOCTL_SOCKET: IEngExtCallFactory_CreateFuncCall(CIoCtlSocketCall, buf, ptrSize); + case ECF_SET_SOCK_OPT: IEngExtCallFactory_CreateFuncCall(CSetSockOptCall, buf, ptrSize); + case ECF_CLOSE_SOCKET: IEngExtCallFactory_CreateFuncCall(CCloseSocketCall, buf, ptrSize); + case ECF_RECVFROM: IEngExtCallFactory_CreateFuncCall(CRecvFromCall, buf, ptrSize); + case ECF_SENDTO: IEngExtCallFactory_CreateFuncCall(CSendToCall, buf, ptrSize); + case ECF_BIND: IEngExtCallFactory_CreateFuncCall(CBindCall , buf, ptrSize); + case ECF_GET_SOCK_NAME: IEngExtCallFactory_CreateFuncCall(CGetSockNameCall, buf, ptrSize); + case ECF_WSA_GET_LAST_ERROR: IEngExtCallFactory_CreateFuncCall(CWSAGetLastErrorCall, buf, ptrSize); + + case ECF_STEAM_CALLBACK_CALL_1: IEngExtCallFactory_CreateFuncCall(CSteamCallbackCall1, buf, ptrSize); + case ECF_STEAM_CALLBACK_CALL_2: IEngExtCallFactory_CreateFuncCall(CSteamCallbackCall2, buf, ptrSize); + + case ECF_STEAM_API_REGISTER_CALLBACK: IEngExtCallFactory_CreateFuncCall(CSteamApiRegisterCallbackCall, buf, ptrSize); + case ECF_STEAM_API_INIT: IEngExtCallFactory_CreateFuncCall(CSteamApiRegisterCallbackCall, buf, ptrSize); + case ECF_STEAM_API_UNREGISTER_CALL_RESULT: IEngExtCallFactory_CreateFuncCall(CSteamApiUnrigestierCallResultCall, buf, ptrSize); + case ECF_STEAMAPPS: IEngExtCallFactory_CreateFuncCall(CSteamAppsCall, buf, ptrSize); + case ECF_STEAMAPPS_GET_CURRENT_GAME_LANGUAGE: IEngExtCallFactory_CreateFuncCall(CSteamAppGetCurrentGameLanguageCall, buf, ptrSize); + + case ECF_STEAMGAMESERVER_INIT: IEngExtCallFactory_CreateFuncCall(CSteamGameServerInitCall, buf, ptrSize); + case ECF_STEAMGAMESERVER: IEngExtCallFactory_CreateFuncCall(CSteamGameServerCall, buf, ptrSize); + case ECF_GS_SET_PRODUCT: IEngExtCallFactory_CreateFuncCall(CGameServerSetProductCall, buf, ptrSize); + case ECF_GS_SET_GAME_DIR: IEngExtCallFactory_CreateFuncCall(CGameServerSetModDirCall, buf, ptrSize); + case ECF_GS_SET_DEDICATED_SERVER: IEngExtCallFactory_CreateFuncCall(CGameServerSetDedicatedServerCall, buf, ptrSize); + case ECF_GS_SET_GAME_DESC: IEngExtCallFactory_CreateFuncCall(CGameServerSetGameDescCall, buf, ptrSize); + case ECF_GS_LOG_ON_ANONYMOUS: IEngExtCallFactory_CreateFuncCall(CGameServerLogOnAnonymousCall, buf, ptrSize); + case ECF_GS_ENABLE_HEARTBEATS: IEngExtCallFactory_CreateFuncCall(CGameServerEnableHeartbeatsCall, buf, ptrSize); + case ECF_GS_SET_HEARTBEATS_INTERVAL: IEngExtCallFactory_CreateFuncCall(CGameServerSetHeartbeatIntervalCall, buf, ptrSize); + case ECF_GS_SET_MAX_PLAYERS_COUNT: IEngExtCallFactory_CreateFuncCall(CGameServerSetMaxPlayersCall, buf, ptrSize); + case ECF_GS_SET_BOT_PLAYERS_COUNT: IEngExtCallFactory_CreateFuncCall(CGameServerSetBotCountCall, buf, ptrSize); + case ECF_GS_SET_SERVER_NAME: IEngExtCallFactory_CreateFuncCall(CGameServerSetServerNameCall, buf, ptrSize); + case ECF_GS_SET_MAP_NAME: IEngExtCallFactory_CreateFuncCall(CGameServerSetMapNameCall, buf, ptrSize); + case ECF_GS_SET_PASSWORD_PROTECTED: IEngExtCallFactory_CreateFuncCall(CGameServerSetPasswordProtectedCall, buf, ptrSize); + case ECF_GS_CLEAR_ALL_KEY_VALUES: IEngExtCallFactory_CreateFuncCall(CGameServerClearAllKVsCall, buf, ptrSize); + case ECF_GS_SET_KEY_VALUE: IEngExtCallFactory_CreateFuncCall(CGameServerSetKeyValueCall, buf, ptrSize); + case ECF_STEAM_API_SET_BREAKPAD_APP_ID: IEngExtCallFactory_CreateFuncCall(CSteamApiSetBreakpadAppIdCall, buf, ptrSize); + case ECF_GS_WAS_RESTART_REQUESTED: IEngExtCallFactory_CreateFuncCall(CGameServerWasRestartRequestedCall, buf, ptrSize); + case ECF_STEAMGAMESERVER_RUN_CALLBACKS: IEngExtCallFactory_CreateFuncCall(CSteamGameServerRunCallbacksCall, buf, ptrSize); + case ECF_GS_GET_NEXT_OUTGOING_PACKET: IEngExtCallFactory_CreateFuncCall(CGameServerGetNextOutgoingPacketCall, buf, ptrSize); + case ECF_STEAM_API_RUN_CALLBACKS: IEngExtCallFactory_CreateFuncCall(CSteamApiRunCallbacksCall, buf, ptrSize); + case ECF_GS_GET_STEAM_ID: IEngExtCallFactory_CreateFuncCall(CGameServerGetSteamIdCall, buf, ptrSize); + case ECF_GS_BSECURE: IEngExtCallFactory_CreateFuncCall(CGameServerBSecureCall, buf, ptrSize); + case ECF_GS_HANDLE_INCOMING_PACKET: IEngExtCallFactory_CreateFuncCall(CGameServerHandleIncomingPacketCall, buf, ptrSize); + case ECF_GS_SEND_USER_CONNECT_AND_AUTHENTICATE: IEngExtCallFactory_CreateFuncCall(CGameServerSendUserConnectAndAuthenticateCall, buf, ptrSize); + case ECF_GS_SEND_USER_DISCONNECT: IEngExtCallFactory_CreateFuncCall(CGameServerSendUserDisconnectCall, buf, ptrSize); + case ECF_GS_BUPDATE_USER_DATA: IEngExtCallFactory_CreateFuncCall(CGameServerBUpdateUserDataCall, buf, ptrSize); + case ECF_GS_CREATE_UNAUTH_USER_CONNECTION: IEngExtCallFactory_CreateFuncCall(CGameServerCreateUnauthUserConnectionCall, buf, ptrSize); + case ECF_GET_HOST_BY_NAME: IEngExtCallFactory_CreateFuncCall(CGetHostByNameCall, buf, ptrSize); + case ECF_GET_HOST_NAME: IEngExtCallFactory_CreateFuncCall(CGetHostNameCall, buf, ptrSize); + + case ECF_GET_PROCESS_TIMES: IEngExtCallFactory_CreateFuncCall(CGetProcessTimesCall, buf, ptrSize); + case ECF_GET_SYSTEM_TIME_AS_FILE_TIME: IEngExtCallFactory_CreateFuncCall(CGetSystemTimeAsFileTimeCall, buf, ptrSize); + + case ECF_CSTD_TIME: IEngExtCallFactory_CreateFuncCall(CStdTimeCall, buf, ptrSize); + case ECF_CSTD_LOCALTIME: IEngExtCallFactory_CreateFuncCall(CStdLocalTimeCall, buf, ptrSize); + case ECF_CSTD_SRAND_CALL: IEngExtCallFactory_CreateFuncCall(CStdSrandCall, buf, ptrSize); + case ECF_CSTD_RAND_CALL: IEngExtCallFactory_CreateFuncCall(CStdRandCall, buf, ptrSize); + + case ECF_GS_LOGOFF: IEngExtCallFactory_CreateFuncCall(CGameServerLogOffCall, buf, ptrSize); + + case ECF_STEAMGAMESERVER_SHUTDOWN: IEngExtCallFactory_CreateFuncCall(CSteamGameServerShutdownCall, buf, ptrSize); + + case ECF_STEAM_API_UNREGISTER_CALLBACK: IEngExtCallFactory_CreateFuncCall(CSteamApiUnregisterCallbackCall, buf, ptrSize); + + case ECF_GS_BLOGGEDON: IEngExtCallFactory_CreateFuncCall(CGameServerBLoggedOnCall, buf, ptrSize); + + + default: + rehlds_syserror("%s: unknown funccall opcode %d", __FUNCTION__, opc); + return NULL; + } +} diff --git a/rehlds/testsuite/funccalls.h b/rehlds/testsuite/funccalls.h new file mode 100644 index 0000000..42b3444 --- /dev/null +++ b/rehlds/testsuite/funccalls.h @@ -0,0 +1,1272 @@ +#pragma once +#ifdef _WIN32 + +#include "osconfig.h" + +#include "steam/steam_api.h" +#include "steam/steam_gameserver.h" + +#include +#include +#include + +#define HOSTENT_DATA_MAX_ALIASES 10 +#define HOSTENT_DATA_MAX_ADDRS 32 + +struct hostent_data_t { + char hostName[256]; + int hostNameLen; + + int numAliases; + char aliases[HOSTENT_DATA_MAX_ALIASES][256]; + int aliasesLengths[HOSTENT_DATA_MAX_ALIASES]; + + short addrtype; + short addrLen; + int numAddrs; + char addrs[HOSTENT_DATA_MAX_ADDRS][32]; + + //Used by reader only + char* preparedAddrs[HOSTENT_DATA_MAX_ADDRS + 1]; + char* preparedAliases[HOSTENT_DATA_MAX_ALIASES + 1]; + + + void clear() { + hostName[0] = 0; + hostNameLen = 0; + + numAliases = 0; + for (int i = 0; i < HOSTENT_DATA_MAX_ALIASES; i++) { + aliasesLengths[i] = 0; + aliases[i][0] = 0; + } + + addrtype = 0; + addrLen = 0; + numAddrs = 0; + } +}; + +enum ExtCallFuncs { + ECF_NONE = 0, + ECF_SLEEP = 1, + ECF_QUERY_PERF_FREQ = 2, + ECF_QUERY_PERF_COUNTER = 3, + ECF_GET_TICK_COUNT = 4, + ECF_GET_LOCAL_TIME = 5, + ECF_GET_SYSTEM_TIME = 6, + ECF_GET_TIMEZONE_INFO = 7, + + ECF_SOCKET = 8, + ECF_IOCTL_SOCKET = 9, + ECF_SET_SOCK_OPT = 10, + ECF_CLOSE_SOCKET = 11, + ECF_RECVFROM = 12, + ECF_SENDTO = 13, + ECF_BIND = 14, + ECF_GET_SOCK_NAME = 15, + ECF_WSA_GET_LAST_ERROR = 16, + + ECF_STEAM_CALLBACK_CALL_1 = 17, + ECF_STEAM_CALLBACK_CALL_2 = 18, + + ECF_STEAM_API_REGISTER_CALLBACK = 19, + ECF_STEAM_API_INIT = 20, + ECF_STEAM_API_UNREGISTER_CALL_RESULT = 21, + ECF_STEAMAPPS = 22, + ECF_STEAMAPPS_GET_CURRENT_GAME_LANGUAGE = 23, + + ECF_STEAMGAMESERVER_INIT = 24, + ECF_STEAMGAMESERVER = 25, + ECF_GS_SET_PRODUCT = 26, + ECF_GS_SET_GAME_DIR = 27, + ECF_GS_SET_DEDICATED_SERVER = 28, + ECF_GS_SET_GAME_DESC = 29, + ECF_GS_LOG_ON_ANONYMOUS = 30, + ECF_GS_ENABLE_HEARTBEATS = 31, + ECF_GS_SET_HEARTBEATS_INTERVAL = 32, + ECF_GS_SET_MAX_PLAYERS_COUNT = 33, + ECF_GS_SET_BOT_PLAYERS_COUNT = 34, + ECF_GS_SET_SERVER_NAME = 35, + ECF_GS_SET_MAP_NAME = 36, + ECF_GS_SET_PASSWORD_PROTECTED = 37, + ECF_GS_CLEAR_ALL_KEY_VALUES = 38, + ECF_GS_SET_KEY_VALUE = 39, + ECF_STEAM_API_SET_BREAKPAD_APP_ID = 40, + ECF_GS_WAS_RESTART_REQUESTED = 41, + ECF_STEAMGAMESERVER_RUN_CALLBACKS = 42, + ECF_GS_GET_NEXT_OUTGOING_PACKET = 43, + ECF_STEAM_API_RUN_CALLBACKS = 44, + ECF_GS_GET_STEAM_ID = 45, + ECF_GS_BSECURE = 46, + ECF_GS_HANDLE_INCOMING_PACKET = 47, + ECF_GS_SEND_USER_CONNECT_AND_AUTHENTICATE = 48, + ECF_GS_SEND_USER_DISCONNECT = 49, + ECF_GS_BUPDATE_USER_DATA = 50, + ECF_GS_CREATE_UNAUTH_USER_CONNECTION = 51, + + ECF_GET_HOST_NAME = 52, + ECF_GET_HOST_BY_NAME = 53, + ECF_GET_PROCESS_TIMES = 54, + ECF_GET_SYSTEM_TIME_AS_FILE_TIME = 55, + + ECF_CSTD_TIME = 56, + ECF_CSTD_LOCALTIME = 57, + ECF_CSTD_SRAND_CALL = 58, + ECF_CSTD_RAND_CALL = 59, + + ECF_GS_LOGOFF = 60, + + ECF_STEAMGAMESERVER_SHUTDOWN = 61, + ECF_STEAM_API_UNREGISTER_CALLBACK = 62, + + ECF_GS_BLOGGEDON = 63, +}; + +struct CSteamCallbackState_t { + uint8 m_nCallbackFlags; + int m_iCallback; + + void clear() { + m_nCallbackFlags = 0; + m_iCallback = 0; + } +}; + +class IEngExtCall { +public: + bool m_Start; + bool m_End; + +public: + IEngExtCall() { m_Start = m_End = false; } + virtual ~IEngExtCall() { } + virtual bool compareInputArgs(IEngExtCall* other, bool strict) = 0; + virtual std::string toString() = 0; + virtual ExtCallFuncs getOpcode() = 0; + virtual void writePrologue(std::ostream &stream) { } + virtual void writeEpilogue(std::ostream &stream) { } + virtual void readPrologue(std::istream &stream) { } + virtual void readEpilogue(std::istream &stream) { } + void ensureArgsAreEqual(IEngExtCall* other, bool strict, const char* callSource); +}; + +class IEngCallbackCall : public IEngExtCall { +public: + virtual void someFuncInVTable() { } +}; + +class IEngExtCallFactory { +public: + static IEngExtCall* createByOpcode(ExtCallFuncs opc, void* ptr, int ptrSize); +}; + +//fake call; eof marker +class CEndRecordCall : public IEngExtCall { +public: + virtual bool compareInputArgs(IEngExtCall* other, bool strict) { return false; } + virtual std::string toString() { return std::string("EOF"); } + virtual ExtCallFuncs getOpcode() { return ECF_NONE; } +}; + +class CSleepExtCall : public IEngExtCall { +public: + DWORD m_Time; + +public: + CSleepExtCall() { m_Time = 0; } + CSleepExtCall(DWORD time); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_SLEEP; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CQueryPerfFreqCall : public IEngExtCall { +public: + int64_t m_Freq; + BOOL m_Res; + +public: + CQueryPerfFreqCall() { m_Freq = 0; m_Res = false; } + + void SetResult(LARGE_INTEGER freq, BOOL res) { m_Freq = freq.QuadPart; m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_QUERY_PERF_FREQ; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CQueryPerfCounterCall : public IEngExtCall { +public: + int64_t m_Counter; + BOOL m_Res; + +public: + CQueryPerfCounterCall() { m_Counter = 0; m_Res = 0; } + + void SetResult(LARGE_INTEGER counter, BOOL res) { m_Counter = counter.QuadPart; m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_QUERY_PERF_COUNTER; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + + +class CGetTickCountCall : public IEngExtCall { +public: + DWORD m_Res; + +public: + CGetTickCountCall() { m_Res = 0; } + + void SetResult(DWORD res) { m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_TICK_COUNT; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGetLocalTimeCall : public IEngExtCall { +public: + SYSTEMTIME m_Res; + +public: + CGetLocalTimeCall() { memset(&m_Res, 0, sizeof(m_Res)); } + + void SetResult(LPSYSTEMTIME res) { m_Res = *res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_LOCAL_TIME; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGetSystemTimeCall : public IEngExtCall { +public: + SYSTEMTIME m_Res; + +public: + CGetSystemTimeCall() { memset(&m_Res, 0, sizeof(m_Res)); } + + void SetResult(LPSYSTEMTIME res) { m_Res = *res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_SYSTEM_TIME; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGetTimeZoneInfoCall : public IEngExtCall { +public: + TIME_ZONE_INFORMATION m_Res; + +public: + CGetTimeZoneInfoCall() { memset(&m_Res, 0, sizeof(m_Res)); } + + void SetResult(LPTIME_ZONE_INFORMATION res) { m_Res = *res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_TIMEZONE_INFO; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSocketCall : public IEngExtCall { +public: + int m_Af; + int m_Type; + int m_Protocol; + SOCKET m_Res; + +public: + CSocketCall() { m_Af = m_Type = m_Protocol = 0; m_Res = INVALID_SOCKET; } + CSocketCall(int af, int type, int protocol); + void setResult(SOCKET s) { m_Res = s; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_SOCKET; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CIoCtlSocketCall : public IEngExtCall { +public: + SOCKET m_Socket; + long m_Cmd; + u_long m_InValue; + + u_long m_OutValue; + int m_Res; + +public: + CIoCtlSocketCall() { m_Socket = INVALID_SOCKET; m_Cmd = 0; m_InValue = 0; m_OutValue = 0; m_Res = 0; } + CIoCtlSocketCall(SOCKET s, long cmd, u_long inValue); + void setResult(u_long outValue, int res) { m_Res = res; m_OutValue = outValue; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_IOCTL_SOCKET; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSetSockOptCall : public IEngExtCall { +public: + SOCKET m_Socket; + int m_Level; + int m_OptName; + char m_OptVal[32]; + int m_OptValLen; + + int m_Res; + +public: + CSetSockOptCall() { m_Socket = INVALID_SOCKET; m_Level = m_OptName = m_OptValLen = 0; m_Res = 0; } + CSetSockOptCall(SOCKET s, int level, int optname, const char* optval, int optlen); + void setResult(int res) { m_Res = res; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_SET_SOCK_OPT; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CCloseSocketCall : public IEngExtCall { +public: + SOCKET m_Socket; + int m_Res; + +public: + CCloseSocketCall() { m_Socket = INVALID_SOCKET; m_Res = 0; } + CCloseSocketCall(SOCKET s); + void setResult(int res) { m_Res = res; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_CLOSE_SOCKET; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CRecvFromCall : public IEngExtCall { +public: + SOCKET m_Socket; + int m_Len; + int m_Flags; + int m_FromLenIn; + + char m_Data[8192]; + int m_FromLenOut; + char m_From[32]; + int m_Res; + +public: + CRecvFromCall() { m_Socket = INVALID_SOCKET; m_Len = m_Flags = m_FromLenIn = 0; m_FromLenOut = 0; m_Res = -1; } + CRecvFromCall(SOCKET s, int len, int flags, int fromlen); + void setResult(const void* data, const void* from, int fromLen, int res); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_RECVFROM; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSendToCall : public IEngExtCall { +public: + SOCKET m_Socket; + char m_Data[8192]; + int m_Len; + int m_Flags; + char m_To[32]; + int m_ToLen; + + int m_Res; + +public: + CSendToCall() { m_Socket = INVALID_SOCKET, m_Len = m_Flags = m_ToLen = 0; m_Res = -1; } + CSendToCall(SOCKET s, const void* buf, int len, int flags, const void* to, int tolen); + void setResult(int res) { m_Res = res; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_SENDTO; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CBindCall : public IEngExtCall { +public: + SOCKET m_Socket; + char m_Addr[32]; + int m_AddrLen; + + int m_Res; + +public: + CBindCall() { m_Socket = INVALID_SOCKET; m_AddrLen = 0; m_Res = 0; } + CBindCall(SOCKET s, const void* addr, int addrlen); + void setResult(int res) { m_Res = res; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_BIND; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGetSockNameCall : public IEngExtCall { +public: + SOCKET m_Socket; + int m_AddrLenIn; + + char m_Addr[32]; + int m_AddrLenOut; + int m_Res; + +public: + CGetSockNameCall() { m_Socket = INVALID_SOCKET; m_AddrLenIn = 0; m_AddrLenOut = m_Res = 0; } + CGetSockNameCall(SOCKET s, int addrlen); + void setResult(const void* addr, int addrlen, int res); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_SOCK_NAME; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CWSAGetLastErrorCall : public IEngExtCall { +public: + int m_Res; + +public: + CWSAGetLastErrorCall() { m_Res = 0; } + void setResult(int res) { m_Res = res; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_WSA_GET_LAST_ERROR; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamCallbackCall1 : public IEngCallbackCall { +public: + int m_CallbackId; + char m_Data[1024]; + int m_DataSize; + CSteamCallbackState_t m_InState; + CSteamCallbackState_t m_OutState; + +public: + CSteamCallbackCall1() { m_CallbackId = 0; m_DataSize = 0; m_InState.clear(), m_OutState.clear(); } + CSteamCallbackCall1(int cbId, void* data, int dataSize, CCallbackBase* cb); + + void setResult(CCallbackBase* cb) { m_OutState.m_iCallback = cb->GetICallback(); m_OutState.m_nCallbackFlags = cb->GetFlags(); } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAM_CALLBACK_CALL_1; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamCallbackCall2 : public IEngCallbackCall { +public: + int m_CallbackId; + char m_Data[1024]; + int m_DataSize; + bool m_bIOFailure; + SteamAPICall_t m_SteamAPICall; + CSteamCallbackState_t m_InState; + CSteamCallbackState_t m_OutState; + +public: + CSteamCallbackCall2() { m_CallbackId = m_DataSize = 0; m_bIOFailure = false; m_SteamAPICall = k_uAPICallInvalid; m_InState.clear(), m_OutState.clear(); } + CSteamCallbackCall2(int cbId, void* data, int dataSize, bool ioFailure, SteamAPICall_t apiCall, CCallbackBase* cb); + + void setResult(CCallbackBase* cb) { m_OutState.m_iCallback = cb->GetICallback(); m_OutState.m_nCallbackFlags = cb->GetFlags(); } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAM_CALLBACK_CALL_2; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamApiRegisterCallbackCall : public IEngExtCall { +public: + int m_RehldsCallbackId; + int m_iSteamCallbackId; + CSteamCallbackState_t m_InState; + CSteamCallbackState_t m_OutState; + +public: + CSteamApiRegisterCallbackCall() { m_RehldsCallbackId = 0; m_iSteamCallbackId = 0; m_InState.clear(), m_OutState.clear(); } + CSteamApiRegisterCallbackCall(int rehldsCallbackId, int steamCallbackId, CCallbackBase* cb); + + void setResult(CCallbackBase* cb) { m_OutState.m_iCallback = cb->GetICallback(); m_OutState.m_nCallbackFlags = cb->GetFlags(); } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAM_API_REGISTER_CALLBACK; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamApiInitCall : public IEngExtCall { +public: + bool m_Res; + +public: + CSteamApiInitCall() { m_Res = false; } + void setResult(bool res) { m_Res = res; } + + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAM_API_INIT; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamApiUnrigestierCallResultCall : public IEngExtCall { +public: + int m_RehldsCallbackId; + SteamAPICall_t m_SteamApiCall; + CSteamCallbackState_t m_InState; + CSteamCallbackState_t m_OutState; + +public: + CSteamApiUnrigestierCallResultCall() { m_RehldsCallbackId = 0; m_SteamApiCall = k_uAPICallInvalid; m_InState.clear(), m_OutState.clear(); } + CSteamApiUnrigestierCallResultCall(int rehldsCallbackId, SteamAPICall_t steamApiCall, CCallbackBase* cb); + + void setResult(CCallbackBase* cb) { m_OutState.m_iCallback = cb->GetICallback(); m_OutState.m_nCallbackFlags = cb->GetFlags(); } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAM_API_UNREGISTER_CALL_RESULT; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamAppsCall : public IEngExtCall { +public: + bool m_ReturnNull; + +public: + CSteamAppsCall() { m_ReturnNull = false; } + + void setReturnNull(bool retNull) { m_ReturnNull = retNull; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAMAPPS; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamAppGetCurrentGameLanguageCall : public IEngExtCall { +public: + int m_ResLen; + char m_Res[256]; + +public: + CSteamAppGetCurrentGameLanguageCall() { m_ResLen = 0; } + + void setResult(const char* res); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAMAPPS_GET_CURRENT_GAME_LANGUAGE; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamGameServerInitCall : public IEngExtCall { +public: + uint32 m_IP; + uint16 m_SteamPort; + uint16 m_GamePort; + uint16 m_QueryPort; + EServerMode m_ServerMode; + char m_Version[256]; + int m_VersionLen; + + bool m_Res; + +public: + CSteamGameServerInitCall() { m_IP = 0; m_SteamPort = m_GamePort = m_QueryPort = 0; m_ServerMode = eServerModeInvalid; m_VersionLen = 0; m_Res = false; } + CSteamGameServerInitCall(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString); + + void setResult(bool res) { m_Res = res; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAMGAMESERVER_INIT; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamGameServerCall : public IEngExtCall { +public: + bool m_ReturnNull; + +public: + CSteamGameServerCall() { m_ReturnNull = false; } + + void setReturnNull(bool retNull) { m_ReturnNull = retNull; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAMGAMESERVER; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGameServerSetProductCall : public IEngExtCall { +public: + char m_Product[32]; + int m_ProductLen; + +public: + CGameServerSetProductCall() { m_ProductLen = 0; } + CGameServerSetProductCall(const char* product); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_PRODUCT; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetModDirCall : public IEngExtCall { +public: + char m_Dir[32]; + int m_DirLen; + +public: + CGameServerSetModDirCall() { m_DirLen = 0; } + CGameServerSetModDirCall(const char* dir); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_GAME_DIR; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetDedicatedServerCall : public IEngExtCall { +public: + bool m_Dedicated; + +public: + CGameServerSetDedicatedServerCall() { m_Dedicated = false; } + CGameServerSetDedicatedServerCall(bool dedicated); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_DEDICATED_SERVER; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetGameDescCall : public IEngExtCall { +public: + char m_Desc[128]; + int m_DescLen; + +public: + CGameServerSetGameDescCall() { m_DescLen = 0; } + CGameServerSetGameDescCall(const char* desc); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_GAME_DESC; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerLogOnAnonymousCall : public IEngExtCall { +public: + CGameServerLogOnAnonymousCall() { } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_LOG_ON_ANONYMOUS; } +}; + +class CGameServerEnableHeartbeatsCall : public IEngExtCall { +public: + bool m_Heartbeats; + +public: + CGameServerEnableHeartbeatsCall() { m_Heartbeats = false; } + CGameServerEnableHeartbeatsCall(bool hearbeats); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_ENABLE_HEARTBEATS; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetHeartbeatIntervalCall : public IEngExtCall { +public: + int m_Interval; + +public: + CGameServerSetHeartbeatIntervalCall() { m_Interval = 0; } + CGameServerSetHeartbeatIntervalCall(int interval); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_HEARTBEATS_INTERVAL; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetMaxPlayersCall : public IEngExtCall { +public: + int m_MaxPlayers; + +public: + CGameServerSetMaxPlayersCall() { m_MaxPlayers = 0; } + CGameServerSetMaxPlayersCall(int maxPlayers); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_MAX_PLAYERS_COUNT; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetBotCountCall : public IEngExtCall { +public: + int m_NumBots; + +public: + CGameServerSetBotCountCall() { m_NumBots = 0; } + CGameServerSetBotCountCall(int numBots); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_BOT_PLAYERS_COUNT; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetServerNameCall : public IEngExtCall { +public: + char m_ServerName[128]; + int m_ServerNameLen; + +public: + CGameServerSetServerNameCall() { m_ServerNameLen = 0; } + CGameServerSetServerNameCall(const char* serverName); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_SERVER_NAME; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetMapNameCall : public IEngExtCall { +public: + char m_MapName[128]; + int m_MapNameLen; + +public: + CGameServerSetMapNameCall() { m_MapNameLen = 0; } + CGameServerSetMapNameCall(const char* mapName); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_MAP_NAME; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerSetPasswordProtectedCall : public IEngExtCall { +public: + bool m_PasswordProtected; + +public: + CGameServerSetPasswordProtectedCall() { m_PasswordProtected = false; } + CGameServerSetPasswordProtectedCall(bool passwordProtected); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_PASSWORD_PROTECTED; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerClearAllKVsCall : public IEngExtCall { +public: + CGameServerClearAllKVsCall() { } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_CLEAR_ALL_KEY_VALUES; } +}; + +class CGameServerSetKeyValueCall : public IEngExtCall { +public: + char m_Key[128]; + int m_KeyLen; + char m_Value[128]; + int m_ValueLen; +public: + CGameServerSetKeyValueCall() { m_KeyLen = m_ValueLen = 0; } + CGameServerSetKeyValueCall(const char* key, const char* value); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SET_KEY_VALUE; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CSteamApiSetBreakpadAppIdCall : public IEngExtCall { +public: + uint32_t m_AppId; + +public: + CSteamApiSetBreakpadAppIdCall() { m_AppId = 0; } + CSteamApiSetBreakpadAppIdCall(uint32_t appId); + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAM_API_SET_BREAKPAD_APP_ID; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + + +class CGameServerWasRestartRequestedCall : public IEngExtCall { +public: + bool m_Result; + +public: + CGameServerWasRestartRequestedCall() { m_Result = false; } + + void setResult(bool res) { m_Result = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_WAS_RESTART_REQUESTED; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CSteamGameServerRunCallbacksCall : public IEngExtCall { +public: + CSteamGameServerRunCallbacksCall() { } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAMGAMESERVER_RUN_CALLBACKS; } +}; + +class CGameServerGetNextOutgoingPacketCall : public IEngExtCall { +public: + int m_MaxOut; + + char m_Buf[8192]; + int m_BufLen; + int m_Result; + uint32 m_Addr; + uint16 m_Port; + +public: + CGameServerGetNextOutgoingPacketCall() { m_MaxOut = 0; m_BufLen = m_Result = 0; m_Addr = 0; m_Port = 0; } + CGameServerGetNextOutgoingPacketCall(int maxOut); + + void setResult(void* buf, int res, uint32* pAddr, uint16* pPort); + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_GET_NEXT_OUTGOING_PACKET; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CSteamApiRunCallbacksCall : public IEngExtCall { +public: + CSteamApiRunCallbacksCall() { } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAM_API_RUN_CALLBACKS; } +}; + +class CGameServerGetSteamIdCall : public IEngExtCall { +public: + uint64_t m_SteamId; + +public: + CGameServerGetSteamIdCall() { m_SteamId = 0; } + + void setResult(CSteamID &res) { m_SteamId = res.ConvertToUint64(); } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_GET_STEAM_ID; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGameServerBSecureCall : public IEngExtCall { +public: + bool m_Res; + +public: + CGameServerBSecureCall() { m_Res = false; } + + void setResult(bool res) { m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_BSECURE; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGameServerHandleIncomingPacketCall : public IEngExtCall { +public: + char m_Data[8192]; + int m_Len; + uint32_t m_Ip; + uint16_t m_Port; + bool m_Res; + +public: + CGameServerHandleIncomingPacketCall() { m_Len = 0; m_Ip = 0; m_Port = 0; m_Res = false; } + CGameServerHandleIncomingPacketCall(const void *pData, int cbData, uint32 srcIP, uint16 srcPort); + + void setResult(bool res) { m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_HANDLE_INCOMING_PACKET; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGameServerSendUserConnectAndAuthenticateCall : public IEngExtCall { +public: + char m_AuthBlob[4096]; + int m_AuthBlobLen; + uint32_t m_IP; + + uint64_t m_OutSteamId; + bool m_Res; + +public: + CGameServerSendUserConnectAndAuthenticateCall() { m_IP = 0; m_AuthBlobLen = 0; m_OutSteamId = 0; m_Res = false; } + CGameServerSendUserConnectAndAuthenticateCall(uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize); + + void setResult(CSteamID& steamId, bool res) { m_OutSteamId = steamId.ConvertToUint64(); m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SEND_USER_CONNECT_AND_AUTHENTICATE; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGameServerSendUserDisconnectCall : public IEngExtCall { +public: + uint64_t m_SteamId; + +public: + CGameServerSendUserDisconnectCall() { m_SteamId = 0; } + CGameServerSendUserDisconnectCall(CSteamID& steamId) { m_SteamId = steamId.ConvertToUint64(); } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_SEND_USER_DISCONNECT; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CGameServerBUpdateUserDataCall : public IEngExtCall { +public: + uint64_t m_SteamId; + char m_PlayerName[64]; + int m_PlayerNameLen; + uint32_t m_Score; + + bool m_Res; + +public: + CGameServerBUpdateUserDataCall() { m_SteamId = 0; m_Score = 0; m_PlayerNameLen = 0; m_Res = false; } + CGameServerBUpdateUserDataCall(CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore); + + void setResult(bool res) { m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_BUPDATE_USER_DATA; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGameServerCreateUnauthUserConnectionCall : public IEngExtCall { +public: + uint64_t m_SteamId; + +public: + CGameServerCreateUnauthUserConnectionCall() { m_SteamId = 0; } + + void setResult(CSteamID &steamId) { m_SteamId = steamId.ConvertToUint64(); } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_CREATE_UNAUTH_USER_CONNECTION; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGetHostNameCall : public IEngExtCall { +public: + int m_NameLenIn; + + int m_NameLenOut; + char m_Name[2048]; + int m_Res; + +public: + CGetHostNameCall() { m_NameLenIn = 0; m_NameLenOut = 0; m_Res = 0; m_Name[0] = 0; } + CGetHostNameCall(int namelen) { m_NameLenIn = namelen; m_NameLenOut = 0; m_Res = 0; m_Name[0] = 0; } + + void setResult(char* hostName, int res); + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_HOST_NAME; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGetHostByNameCall : public IEngExtCall { +public: + char m_Name[256]; + int m_NameLen; + + hostent_data_t m_HostentData; + +public: + CGetHostByNameCall() { m_Name[0] = 0; m_NameLen = 0; m_HostentData.clear(); } + CGetHostByNameCall(const char* name); + + void setResult(const hostent* hostEnt); + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_HOST_BY_NAME; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGetProcessTimesCall : public IEngExtCall { +public: + BOOL m_Res; + FILETIME m_CreationTime; + FILETIME m_ExitTime; + FILETIME m_KernelTime; + FILETIME m_UserTime; + +public: + CGetProcessTimesCall() { + m_Res = FALSE; + memset(&m_CreationTime, 0, sizeof(m_CreationTime)); + memset(&m_ExitTime, 0, sizeof(m_ExitTime)); + memset(&m_KernelTime, 0, sizeof(m_KernelTime)); + memset(&m_UserTime, 0, sizeof(m_UserTime)); + } + + void setResult(BOOL res, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_PROCESS_TIMES; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGetSystemTimeAsFileTimeCall : public IEngExtCall { +public: + FILETIME m_SystemTime; + +public: + CGetSystemTimeAsFileTimeCall() { memset(&m_SystemTime, 0, sizeof(m_SystemTime)); } + + void setResult(LPFILETIME systemTime); + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GET_SYSTEM_TIME_AS_FILE_TIME; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CStdTimeCall : public IEngExtCall { +public: + bool m_InTimeNull; + + uint32_t m_Res; + +public: + CStdTimeCall(uint32_t* inTime); + CStdTimeCall() { m_InTimeNull = false; m_Res = 0; } + + void setResult(uint32_t res); + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_CSTD_TIME; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CStdLocalTimeCall : public IEngExtCall { +public: + uint32_t m_Time; + + struct tm m_Res; + +public: + CStdLocalTimeCall(uint32_t inTime); + CStdLocalTimeCall() { m_Time = 0; memset(&m_Res, 0, sizeof(m_Res)); } + + void setResult(struct tm *res); + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_CSTD_LOCALTIME; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CStdSrandCall : public IEngExtCall { +public: + uint32_t m_Seed; + +public: + CStdSrandCall() { m_Seed = 0; } + CStdSrandCall(uint32_t seed) { m_Seed = seed; } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_CSTD_SRAND_CALL; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); +}; + +class CStdRandCall : public IEngExtCall { +public: + int m_Res; + +public: + CStdRandCall() { m_Res = 0; } + + void setResult(int res) { m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_CSTD_RAND_CALL; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGameServerLogOffCall : public IEngExtCall { + +public: + CGameServerLogOffCall() { } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_LOGOFF; } + +}; + +class CSteamGameServerShutdownCall : public IEngExtCall { + +public: + CSteamGameServerShutdownCall() { } + + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAMGAMESERVER_SHUTDOWN; } + +}; + +class CSteamApiUnregisterCallbackCall : public IEngExtCall { +public: + int m_RehldsCallbackId; + CSteamCallbackState_t m_InState; + CSteamCallbackState_t m_OutState; + +public: + CSteamApiUnregisterCallbackCall() { m_RehldsCallbackId = 0; m_InState.clear(), m_OutState.clear(); } + CSteamApiUnregisterCallbackCall(int rehldsCallbackId, CCallbackBase* cb); + + void setResult(CCallbackBase* cb) { m_OutState.m_iCallback = cb->GetICallback(); m_OutState.m_nCallbackFlags = cb->GetFlags(); } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_STEAM_API_UNREGISTER_CALLBACK; } + virtual void writePrologue(std::ostream &stream); + virtual void readPrologue(std::istream &stream); + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +class CGameServerBLoggedOnCall : public IEngExtCall { +public: + bool m_Res; + +public: + CGameServerBLoggedOnCall() { m_Res = false; } + + void setResult(bool res) { m_Res = res; } + virtual bool compareInputArgs(IEngExtCall* other, bool strict); + virtual std::string toString(); + virtual ExtCallFuncs getOpcode() { return ECF_GS_BLOGGEDON; } + virtual void writeEpilogue(std::ostream &stream); + virtual void readEpilogue(std::istream &stream); +}; + +#endif diff --git a/rehlds/testsuite/player.cpp b/rehlds/testsuite/player.cpp new file mode 100644 index 0000000..5f0191c --- /dev/null +++ b/rehlds/testsuite/player.cpp @@ -0,0 +1,1071 @@ +#include "precompiled.h" + +CPlayingEngExtInterceptor::CPlayingEngExtInterceptor(const char* fname, bool strictChecks) +{ + for (int i = 0; i < TESTPLAYER_FUNCTREE_DEPTH; i++) + { + m_FuncCalls[i] = &m_FuncCallBuffer[i * TESTPLAYER_FUNCCALL_MAXSIZE]; + m_FuncCallsFree[i] = true; + } + + m_InStream.exceptions(std::ios::badbit | std::ios::failbit | std::ios::eofbit); + m_InStream.open(fname, std::ios::in | std::ios::binary); + + m_InStream.seekg(0, std::ios_base::end); + m_inStreamSize = m_InStream.tellg(); + m_InStream.seekg(0, std::ios_base::beg); + m_bLastRead = false; + + m_bStrictChecks = strictChecks; + + m_ServerSocket = INVALID_SOCKET; + m_SteamCallbacksCounter = 0; + m_SteamAppsWrapper = NULL; + m_GameServerWrapper = NULL; + m_SteamBreakpadContext = NULL; + + uint32_t cmdlineLen = 0; + char cmdLine[2048]; + + uint16_t versionMajor = 0; + uint16_t versionMinor = 0; + + m_InStream.read((char*)&versionMinor, 2).read((char*)&versionMajor, 2); + + if (versionMajor != TESTSUITE_PROTOCOL_VERSION_MAJOR) { + rehlds_syserror("%s: protocol major version mismatch; need %d, got %d", __FUNCTION__, TESTSUITE_PROTOCOL_VERSION_MAJOR, versionMajor); + } + + if (versionMinor > TESTSUITE_PROTOCOL_VERSION_MINOR) { + rehlds_syserror("%s: protocol minor version mismatch; need <= %d, got %d", __FUNCTION__, TESTSUITE_PROTOCOL_VERSION_MINOR, versionMinor); + } + + m_InStream.read((char*)&cmdlineLen, 4); + if (cmdlineLen > sizeof(cmdLine)) { + rehlds_syserror("%s: too long cmdline", __FUNCTION__); + } + + m_InStream.read(cmdLine, cmdlineLen); + printf("Playing testsuite\nrecorders's cmdline: %s\n", cmdLine); +} + +void* CPlayingEngExtInterceptor::allocFuncCall() +{ + for (int i = 0; i < TESTPLAYER_FUNCTREE_DEPTH; i++) + { + if (m_FuncCallsFree[i]) + { + m_FuncCallsFree[i] = false; + return m_FuncCalls[i]; + } + } + + rehlds_syserror("%s: running out of free slots", __FUNCTION__); + return NULL; +} + +void CPlayingEngExtInterceptor::freeFuncCall(void* fcall) +{ + for (int i = 0; i < TESTPLAYER_FUNCTREE_DEPTH; i++) + { + if (m_FuncCalls[i] == fcall) + { + m_FuncCallsFree[i] = true; + return; + } + } + + rehlds_syserror("%s: invalid pointer provided: %p", __FUNCTION__, fcall); +} + +bool CPlayingEngExtInterceptor::readFuncCall() { + if (m_InStream.tellg() >= m_inStreamSize) + { + if (m_bLastRead) return false; + + m_bLastRead = true; + IEngExtCall* callFunc = new(allocFuncCall()) CEndRecordCall(); + m_CommandsQueue.push(callFunc); + return true; + } + + uint16 opc; + m_InStream.read((char*)&opc, 2); + + bool startFlag = (opc & (1 << 15)) != 0; + bool endFlag = (opc & (1 << 14)) != 0; + opc &= 0x3FFF; + + if (startFlag) + { + IEngExtCall* callFunc = IEngExtCallFactory::createByOpcode((ExtCallFuncs)opc, allocFuncCall(), TESTPLAYER_FUNCCALL_MAXSIZE); + callFunc->readPrologue(m_InStream); + m_CommandsQueue.push(callFunc); + callFunc->m_Start = true; + } + + if (endFlag) + { + IEngExtCall* callFunc = IEngExtCallFactory::createByOpcode((ExtCallFuncs)opc, allocFuncCall(), TESTPLAYER_FUNCCALL_MAXSIZE); + callFunc->readEpilogue(m_InStream); + m_CommandsQueue.push(callFunc); + callFunc->m_End = true; + } + + return true; +} + +IEngExtCall* CPlayingEngExtInterceptor::getNextCallInternal(bool peek) { + if (m_CommandsQueue.empty()) { + readFuncCall(); + } + + if (m_CommandsQueue.empty()) { + rehlds_syserror("%s: command queue is empty!", __FUNCTION__); + } + + IEngExtCall* next = m_CommandsQueue.front(); + if (!peek) { + m_CommandsQueue.pop(); + } + + return next; +} + +IEngExtCall* CPlayingEngExtInterceptor::getNextCall(bool peek, bool processCallbacks, ExtCallFuncs expectedOpcode, bool needStart, const char* callSource) { + int size = (int)m_InStream.tellg(); + IEngExtCall* cmd = getNextCallInternal(peek); + if (peek) { + return cmd; + } + + if (cmd->getOpcode() == ECF_NONE) { + TerminateProcess(GetCurrentProcess(), 777); + } + + IEngCallbackCall* callback = dynamic_cast(cmd); + if (callback != NULL && callback->m_Start) { + if (!processCallbacks) { + rehlds_syserror("%s: read a callback, but it's not allowed here", __FUNCTION__); + return NULL; + } + + while (callback != NULL && callback->m_Start) { + playCallback(callback); + cmd = getNextCallInternal(false); + callback = (IEngCallbackCall*)cmd; + } + } + + if (cmd->getOpcode() != expectedOpcode) { + rehlds_syserror("%s: bad opcode; expected %d got %d; size left: %d", __FUNCTION__, expectedOpcode, cmd->getOpcode(), m_inStreamSize - size); + } + if (needStart) { + if (!cmd->m_Start) rehlds_syserror("%s: bad fcall %d; expected start flag", __FUNCTION__, cmd->getOpcode()); + } + else { + if (!cmd->m_End) rehlds_syserror("%s: bad fcall %d; expected end flag", __FUNCTION__, cmd->getOpcode()); + } + + return cmd; +} + +void CPlayingEngExtInterceptor::playCallback(IEngCallbackCall* cb) { + switch (cb->getOpcode()) { + + case ECF_STEAM_CALLBACK_CALL_1: + playSteamCallback1((CSteamCallbackCall1*)cb); + return; + + case ECF_STEAM_CALLBACK_CALL_2: + playSteamCallback2((CSteamCallbackCall2*)cb); + return; + + default: + rehlds_syserror("%s: unknown callback", __FUNCTION__); + } +} + +void CPlayingEngExtInterceptor::playSteamCallback1(CSteamCallbackCall1* cb) { + auto itr = m_SteamCallbacks.find(cb->m_CallbackId); + if (itr == m_SteamCallbacks.end()) rehlds_syserror("%s: callback %d not found", __FUNCTION__, cb->m_CallbackId); + CCallbackBase* steamCallback = (*itr).second; + + if (steamCallback->GetFlags() != cb->m_InState.m_nCallbackFlags) rehlds_syserror("%s: PRE flags desync", __FUNCTION__); + if (steamCallback->GetICallback() != cb->m_InState.m_iCallback) rehlds_syserror("%s: PRE flags desync", __FUNCTION__); + + steamCallback->Run(cb->m_Data); + + CSteamCallbackCall1* endCallback = (CSteamCallbackCall1*)getNextCall(false, true, cb->getOpcode(), false, __FUNCTION__); + + if (steamCallback->GetFlags() != endCallback->m_OutState.m_nCallbackFlags) rehlds_syserror("%s: POST flags desync", __FUNCTION__); + if (steamCallback->GetICallback() != endCallback->m_OutState.m_iCallback) rehlds_syserror("%s: POST flags desync", __FUNCTION__); + freeFuncCall(cb); + freeFuncCall(endCallback); +} + +void CPlayingEngExtInterceptor::playSteamCallback2(CSteamCallbackCall2* cb) { + auto itr = m_SteamCallbacks.find(cb->m_CallbackId); + if (itr == m_SteamCallbacks.end()) rehlds_syserror("%s: callback %d not found", __FUNCTION__, cb->m_CallbackId); + CCallbackBase* steamCallback = (*itr).second; + + if (steamCallback->GetFlags() != cb->m_InState.m_nCallbackFlags) rehlds_syserror("%s: PRE flags desync", __FUNCTION__); + if (steamCallback->GetICallback() != cb->m_InState.m_iCallback) rehlds_syserror("%s: PRE flags desync", __FUNCTION__); + + steamCallback->Run(cb->m_Data, cb->m_bIOFailure, cb->m_SteamAPICall); + + CSteamCallbackCall2* endCallback = (CSteamCallbackCall2*)getNextCall(false, true, cb->getOpcode(), false, __FUNCTION__); + + if (steamCallback->GetFlags() != endCallback->m_OutState.m_nCallbackFlags) rehlds_syserror("%s: POST flags desync", __FUNCTION__); + if (steamCallback->GetICallback() != endCallback->m_OutState.m_iCallback) rehlds_syserror("%s: POST flags desync", __FUNCTION__); + freeFuncCall(cb); + freeFuncCall(endCallback); +} + +int CPlayingEngExtInterceptor::getOrRegisterSteamCallback(CCallbackBase* cb) { + auto itr = m_SteamCallbacksReverse.find(cb); + if (itr != m_SteamCallbacksReverse.end()) { + return (*itr).second; + } + + int id = m_SteamCallbacksCounter++; + m_SteamCallbacksReverse[cb] = id; + m_SteamCallbacks[id] = cb; + + return id; +} + +uint32_t CPlayingEngExtInterceptor::time(uint32_t* pTime) +{ + CStdTimeCall* playCall = dynamic_cast(getNextCall(false, false, ECF_CSTD_TIME, true, __FUNCTION__)); + CStdTimeCall(pTime).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CStdTimeCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_CSTD_TIME, false, __FUNCTION__)); + + uint32_t res = playEndCall->m_Res; + if (pTime != NULL) *pTime = res; + + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +struct tm* CPlayingEngExtInterceptor::localtime(uint32_t time) +{ + CStdLocalTimeCall* playCall = dynamic_cast(getNextCall(false, false, ECF_CSTD_LOCALTIME, true, __FUNCTION__)); + CStdLocalTimeCall(time).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CStdLocalTimeCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_CSTD_LOCALTIME, false, __FUNCTION__)); + + setCurrentTm(&playEndCall->m_Res); + + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return &m_CurrentTm; +} + +void CPlayingEngExtInterceptor::srand(uint32_t seed) +{ + CStdSrandCall* playCall = dynamic_cast(getNextCall(false, false, ECF_CSTD_SRAND_CALL, true, __FUNCTION__)); + CStdSrandCall(seed).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CStdSrandCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_CSTD_SRAND_CALL, false, __FUNCTION__)); + + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +int CPlayingEngExtInterceptor::rand() +{ + CStdRandCall* playCall = dynamic_cast(getNextCall(false, false, ECF_CSTD_RAND_CALL, true, __FUNCTION__)); + CStdRandCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_CSTD_RAND_CALL, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +void CPlayingEngExtInterceptor::Sleep(DWORD msec) { + CSleepExtCall* playCall = dynamic_cast(getNextCall(false, false, ECF_SLEEP, true, __FUNCTION__)); + CSleepExtCall(msec).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSleepExtCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_SLEEP, false, __FUNCTION__)); + + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +BOOL CPlayingEngExtInterceptor::QueryPerfCounter(LARGE_INTEGER* counter) { + CQueryPerfCounterCall* playCall = dynamic_cast(getNextCall(false, false, ECF_QUERY_PERF_COUNTER, true, __FUNCTION__)); + CQueryPerfCounterCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_QUERY_PERF_COUNTER, false, __FUNCTION__)); + + counter->QuadPart = playEndCall->m_Counter; + BOOL res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +BOOL CPlayingEngExtInterceptor::QueryPerfFreq(LARGE_INTEGER* freq) { + CQueryPerfFreqCall* playCall = dynamic_cast(getNextCall(false, false, ECF_QUERY_PERF_FREQ, true, __FUNCTION__)); + CQueryPerfFreqCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_QUERY_PERF_FREQ, false, __FUNCTION__)); + + freq->QuadPart = playEndCall->m_Freq; + BOOL res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +DWORD CPlayingEngExtInterceptor::GetTickCount() { + CGetTickCountCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_TICK_COUNT, true, __FUNCTION__)); + CGetTickCountCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_TICK_COUNT, false, __FUNCTION__)); + + DWORD res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +void CPlayingEngExtInterceptor::GetLocalTime(LPSYSTEMTIME time) { + CGetLocalTimeCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_LOCAL_TIME, true, __FUNCTION__)); + CGetLocalTimeCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_LOCAL_TIME, false, __FUNCTION__)); + + memcpy(time, &playEndCall->m_Res, sizeof(SYSTEMTIME)); + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +void CPlayingEngExtInterceptor::GetSystemTime(LPSYSTEMTIME time) { + CGetSystemTimeCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_SYSTEM_TIME, true, __FUNCTION__)); + CGetSystemTimeCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_SYSTEM_TIME, false, __FUNCTION__)); + + memcpy(time, &playEndCall->m_Res, sizeof(SYSTEMTIME)); + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +void CPlayingEngExtInterceptor::GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo) { + CGetTimeZoneInfoCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_TIMEZONE_INFO, true, __FUNCTION__)); + CGetTimeZoneInfoCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_TIMEZONE_INFO, false, __FUNCTION__)); + + memcpy(zinfo, &playEndCall->m_Res, sizeof(TIME_ZONE_INFORMATION)); + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +BOOL CPlayingEngExtInterceptor::GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) +{ + CGetProcessTimesCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_PROCESS_TIMES, true, __FUNCTION__)); + CGetProcessTimesCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_PROCESS_TIMES, false, __FUNCTION__)); + + BOOL res = playEndCall->m_Res; + memcpy(lpCreationTime, &playEndCall->m_CreationTime, sizeof(FILETIME)); + memcpy(lpExitTime, &playEndCall->m_ExitTime, sizeof(FILETIME)); + memcpy(lpKernelTime, &playEndCall->m_KernelTime, sizeof(FILETIME)); + memcpy(lpUserTime, &playEndCall->m_UserTime, sizeof(FILETIME)); + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +void CPlayingEngExtInterceptor::GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) +{ + CGetSystemTimeAsFileTimeCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_SYSTEM_TIME_AS_FILE_TIME, true, __FUNCTION__)); + CGetSystemTimeAsFileTimeCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_SYSTEM_TIME_AS_FILE_TIME, false, __FUNCTION__)); + + memcpy(lpSystemTimeAsFileTime, &playEndCall->m_SystemTime, sizeof(FILETIME)); + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + + +SOCKET CPlayingEngExtInterceptor::socket(int af, int type, int protocol) { + CSocketCall* playCall = dynamic_cast(getNextCall(false, false, ECF_SOCKET, true, __FUNCTION__)); + CSocketCall(af, type, protocol).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSocketCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_SOCKET, false, __FUNCTION__)); + + SOCKET res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +int CPlayingEngExtInterceptor::ioctlsocket(SOCKET s, long cmd, u_long *argp) { + CIoCtlSocketCall* playCall = dynamic_cast(getNextCall(false, false, ECF_IOCTL_SOCKET, true, __FUNCTION__)); + CIoCtlSocketCall(s, cmd, *argp).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CIoCtlSocketCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_IOCTL_SOCKET, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + *argp = playEndCall->m_OutValue; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +int CPlayingEngExtInterceptor::setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen) { + CSetSockOptCall* playCall = dynamic_cast(getNextCall(false, false, ECF_SET_SOCK_OPT, true, __FUNCTION__)); + CSetSockOptCall(s, level, optname, optval, optlen).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSetSockOptCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_SET_SOCK_OPT, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +int CPlayingEngExtInterceptor::closesocket(SOCKET s) { + CCloseSocketCall* playCall = dynamic_cast(getNextCall(false, false, ECF_CLOSE_SOCKET, true, __FUNCTION__)); + CCloseSocketCall(s).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CCloseSocketCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_CLOSE_SOCKET, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +int CPlayingEngExtInterceptor::recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen) { + CRecvFromCall* playCall = dynamic_cast(getNextCall(false, false, ECF_RECVFROM, true, __FUNCTION__)); + CRecvFromCall(s, len, flags, *fromlen).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CRecvFromCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_RECVFROM, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + *fromlen = playEndCall->m_FromLenOut; + if (res >= 0) { + memcpy(buf, playEndCall->m_Data, res); + memcpy(from, playEndCall->m_From, playEndCall->m_FromLenOut); + } + + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +int CPlayingEngExtInterceptor::sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) { + CSendToCall* playCall = dynamic_cast(getNextCall(false, false, ECF_SENDTO, true, __FUNCTION__)); + CSendToCall(s, buf, len, flags, to, tolen).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSendToCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_SENDTO, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +int CPlayingEngExtInterceptor::bind(SOCKET s, const struct sockaddr* addr, int namelen) { + CBindCall* playCall = dynamic_cast(getNextCall(false, false, ECF_BIND, true, __FUNCTION__)); + CBindCall(s, addr, namelen).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CBindCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_BIND, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +int CPlayingEngExtInterceptor::getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen) { + CGetSockNameCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_SOCK_NAME, true, __FUNCTION__)); + CGetSockNameCall(s, *namelen).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGetSockNameCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_SOCK_NAME, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + *namelen = playEndCall->m_AddrLenOut; + if (res >= 0) { + memcpy(name, playEndCall->m_Addr, playEndCall->m_AddrLenOut); + } + + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +int CPlayingEngExtInterceptor::WSAGetLastError() { + CWSAGetLastErrorCall* playCall = dynamic_cast(getNextCall(false, false, ECF_WSA_GET_LAST_ERROR, true, __FUNCTION__)); + CWSAGetLastErrorCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_WSA_GET_LAST_ERROR, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +struct hostent* CPlayingEngExtInterceptor::gethostbyname(const char *name) { + CGetHostByNameCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_HOST_BY_NAME, true, __FUNCTION__)); + CGetHostByNameCall(name).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGetHostByNameCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_HOST_BY_NAME, false, __FUNCTION__)); + + setCurrentHostent(&playEndCall->m_HostentData); + + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return &m_CurrentHostent; +} + +int CPlayingEngExtInterceptor::gethostname(char *name, int namelen) { + CGetHostNameCall* playCall = dynamic_cast(getNextCall(false, false, ECF_GET_HOST_NAME, true, __FUNCTION__)); + CGetHostNameCall(namelen).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGetHostNameCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_GET_HOST_NAME, false, __FUNCTION__)); + + int res = playEndCall->m_Res; + strcpy(name, playEndCall->m_Name); + + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +void CPlayingEngExtInterceptor::setCurrentHostent(hostent_data_t* data) { + memcpy(&m_CurrentHostentData, data, sizeof(m_CurrentHostentData)); + for (int i = 0; i < m_CurrentHostentData.numAliases; i++) { + m_CurrentHostentData.preparedAliases[i] = m_CurrentHostentData.aliases[i]; + m_CurrentHostentData.preparedAliases[i + 1] = NULL; + } + + for (int i = 0; i < m_CurrentHostentData.numAddrs; i++) { + m_CurrentHostentData.preparedAddrs[i] = m_CurrentHostentData.addrs[i]; + m_CurrentHostentData.preparedAddrs[i + 1] = NULL; + } + + m_CurrentHostent.h_addr_list = m_CurrentHostentData.preparedAddrs; + m_CurrentHostent.h_addrtype = m_CurrentHostentData.addrtype; + m_CurrentHostent.h_aliases = m_CurrentHostentData.preparedAliases; + m_CurrentHostent.h_length = m_CurrentHostentData.addrLen; + m_CurrentHostent.h_name = m_CurrentHostentData.hostName; +} + +void CPlayingEngExtInterceptor::setCurrentTm(struct tm* t) { + memcpy(&m_CurrentTm, 0, sizeof(m_CurrentTm)); +} + +void CPlayingEngExtInterceptor::SteamAPI_SetBreakpadAppID(uint32 unAppID) { + CSteamApiSetBreakpadAppIdCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAM_API_SET_BREAKPAD_APP_ID, true, __FUNCTION__)); + CSteamApiSetBreakpadAppIdCall(unAppID).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSteamApiSetBreakpadAppIdCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAM_API_SET_BREAKPAD_APP_ID, false, __FUNCTION__)); + + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +void CPlayingEngExtInterceptor::SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback) { + //do nothing for now +} + +void CPlayingEngExtInterceptor::SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback) { + int rehldsId = getOrRegisterSteamCallback(pCallback); + + CSteamApiRegisterCallbackCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAM_API_REGISTER_CALLBACK, true, __FUNCTION__)); + CSteamApiRegisterCallbackCall(rehldsId, iCallback, pCallback).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSteamApiRegisterCallbackCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAM_API_REGISTER_CALLBACK, false, __FUNCTION__)); + + pCallback->SetFlags(playEndCall->m_OutState.m_nCallbackFlags); + pCallback->SetICallback(playEndCall->m_OutState.m_iCallback); + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +bool CPlayingEngExtInterceptor::SteamAPI_Init() { + CSteamApiInitCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAM_API_INIT, true, __FUNCTION__)); + CSteamApiInitCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAM_API_INIT, false, __FUNCTION__)); + + bool res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +void CPlayingEngExtInterceptor::SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall) { + int rehldsId = getOrRegisterSteamCallback(pCallback); + + CSteamApiUnrigestierCallResultCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAM_API_UNREGISTER_CALL_RESULT, true, __FUNCTION__)); + CSteamApiUnrigestierCallResultCall(rehldsId, hAPICall, pCallback).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSteamApiUnrigestierCallResultCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAM_API_UNREGISTER_CALL_RESULT, false, __FUNCTION__)); + + pCallback->SetFlags(playEndCall->m_OutState.m_nCallbackFlags); + pCallback->SetICallback(playEndCall->m_OutState.m_iCallback); + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +ISteamApps* CPlayingEngExtInterceptor::SteamApps() { + CSteamAppsCall* playCall = (CSteamAppsCall*)getNextCall(false, false, ECF_STEAMAPPS, true, __FUNCTION__); + CSteamAppsCall* playEndCall = (CSteamAppsCall*)getNextCall(false, true, ECF_STEAMAPPS, false, __FUNCTION__); + + ISteamApps* res = NULL; + if (!playEndCall->m_ReturnNull) { + if (m_SteamAppsWrapper == NULL) m_SteamAppsWrapper = new CSteamAppsPlayingWrapper(this); + res = m_SteamAppsWrapper; + } + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +bool CPlayingEngExtInterceptor::SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString) { + CSteamGameServerInitCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAMGAMESERVER_INIT, true, __FUNCTION__)); + CSteamGameServerInitCall(unIP, usSteamPort, usGamePort, usQueryPort, eServerMode, pchVersionString).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSteamGameServerInitCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAMGAMESERVER_INIT, false, __FUNCTION__)); + + bool res = playEndCall->m_Res; + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +ISteamGameServer* CPlayingEngExtInterceptor::SteamGameServer() { + CSteamGameServerCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAMGAMESERVER, true, __FUNCTION__)); + CSteamGameServerCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAMGAMESERVER, false, __FUNCTION__)); + + ISteamGameServer* res = NULL; + if (!playEndCall->m_ReturnNull) { + if (m_GameServerWrapper == NULL) m_GameServerWrapper = new CSteamGameServerPlayingWrapper(this); + res = m_GameServerWrapper; + } + freeFuncCall(playCall); freeFuncCall(playEndCall); + + return res; +} + +void CPlayingEngExtInterceptor::SteamGameServer_RunCallbacks() { + CSteamGameServerRunCallbacksCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAMGAMESERVER_RUN_CALLBACKS, true, __FUNCTION__)); + CSteamGameServerRunCallbacksCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAMGAMESERVER_RUN_CALLBACKS, false, __FUNCTION__)); + + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +void CPlayingEngExtInterceptor::SteamAPI_RunCallbacks() { + CSteamApiRunCallbacksCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAM_API_RUN_CALLBACKS, true, __FUNCTION__)); + CSteamApiRunCallbacksCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAM_API_RUN_CALLBACKS, false, __FUNCTION__)); + + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + +void CPlayingEngExtInterceptor::SteamGameServer_Shutdown() +{ + CSteamGameServerShutdownCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAMGAMESERVER_SHUTDOWN, true, __FUNCTION__)); + CSteamGameServerShutdownCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAMGAMESERVER_SHUTDOWN, false, __FUNCTION__)); + + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + + +void CPlayingEngExtInterceptor::SteamAPI_UnregisterCallback(CCallbackBase *pCallback) { + int rehldsId = getOrRegisterSteamCallback(pCallback); + + CSteamApiUnregisterCallbackCall* playCall = dynamic_cast(getNextCall(false, false, ECF_STEAM_API_UNREGISTER_CALLBACK, true, __FUNCTION__)); + CSteamApiUnregisterCallbackCall(rehldsId, pCallback).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CSteamApiUnregisterCallbackCall* playEndCall = dynamic_cast(getNextCall(false, true, ECF_STEAM_API_UNREGISTER_CALLBACK, false, __FUNCTION__)); + + pCallback->SetFlags(playEndCall->m_OutState.m_nCallbackFlags); + pCallback->SetICallback(playEndCall->m_OutState.m_iCallback); + freeFuncCall(playCall); freeFuncCall(playEndCall); +} + + + + + +CSteamGameServerPlayingWrapper::CSteamGameServerPlayingWrapper(CPlayingEngExtInterceptor* player) { + m_Player = player; + m_bStrictChecks = player->m_bStrictChecks; +} + +bool CSteamGameServerPlayingWrapper::InitGameServer(uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamGameServerPlayingWrapper::SetProduct(const char *pszProduct) { + CGameServerSetProductCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_PRODUCT, true, __FUNCTION__)); + CGameServerSetProductCall(pszProduct).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetProductCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_PRODUCT, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetGameDescription(const char *pszGameDescription) { + CGameServerSetGameDescCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_GAME_DESC, true, __FUNCTION__)); + CGameServerSetGameDescCall(pszGameDescription).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetGameDescCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_GAME_DESC, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetModDir(const char *pszModDir) { + CGameServerSetModDirCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_GAME_DIR, true, __FUNCTION__)); + CGameServerSetModDirCall(pszModDir).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetModDirCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_GAME_DIR, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetDedicatedServer(bool bDedicated) { + CGameServerSetDedicatedServerCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_DEDICATED_SERVER, true, __FUNCTION__)); + CGameServerSetDedicatedServerCall(bDedicated).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetDedicatedServerCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_DEDICATED_SERVER, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::LogOn(const char *pszAccountName, const char *pszPassword) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerPlayingWrapper::LogOnAnonymous() { + CGameServerLogOnAnonymousCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_LOG_ON_ANONYMOUS, true, __FUNCTION__)); + CGameServerLogOnAnonymousCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_LOG_ON_ANONYMOUS, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::LogOff() { + CGameServerLogOffCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_LOGOFF, true, __FUNCTION__)); + CGameServerLogOffCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_LOGOFF, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +bool CSteamGameServerPlayingWrapper::BLoggedOn() { + CGameServerBLoggedOnCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_BLOGGEDON, true, __FUNCTION__)); + CGameServerBLoggedOnCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_BLOGGEDON, false, __FUNCTION__)); + + bool res = playEndCall->m_Res; + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +bool CSteamGameServerPlayingWrapper::BSecure() { + CGameServerBSecureCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_BSECURE, true, __FUNCTION__)); + CGameServerBSecureCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_BSECURE, false, __FUNCTION__)); + + bool res = playEndCall->m_Res; + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +CSteamID CSteamGameServerPlayingWrapper::GetSteamID() { + CGameServerGetSteamIdCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_GET_STEAM_ID, true, __FUNCTION__)); + CGameServerGetSteamIdCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_GET_STEAM_ID, false, __FUNCTION__)); + + CSteamID res(playEndCall->m_SteamId); + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +bool CSteamGameServerPlayingWrapper::WasRestartRequested() { + CGameServerWasRestartRequestedCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_WAS_RESTART_REQUESTED, true, __FUNCTION__)); + CGameServerWasRestartRequestedCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_WAS_RESTART_REQUESTED, false, __FUNCTION__)); + + bool res = playEndCall->m_Result; + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +void CSteamGameServerPlayingWrapper::SetMaxPlayerCount(int cPlayersMax) { + CGameServerSetMaxPlayersCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_MAX_PLAYERS_COUNT, true, __FUNCTION__)); + CGameServerSetMaxPlayersCall(cPlayersMax).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetMaxPlayersCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_MAX_PLAYERS_COUNT, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetBotPlayerCount(int cBotplayers) { + CGameServerSetBotCountCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_BOT_PLAYERS_COUNT, true, __FUNCTION__)); + CGameServerSetBotCountCall(cBotplayers).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetBotCountCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_BOT_PLAYERS_COUNT, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetServerName(const char *pszServerName) { + CGameServerSetServerNameCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_SERVER_NAME, true, __FUNCTION__)); + CGameServerSetServerNameCall(pszServerName).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetServerNameCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_SERVER_NAME, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetMapName(const char *pszMapName) { + CGameServerSetMapNameCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_MAP_NAME, true, __FUNCTION__)); + CGameServerSetMapNameCall(pszMapName).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetMapNameCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_MAP_NAME, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetPasswordProtected(bool bPasswordProtected) { + CGameServerSetPasswordProtectedCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_PASSWORD_PROTECTED, true, __FUNCTION__)); + CGameServerSetPasswordProtectedCall(bPasswordProtected).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetPasswordProtectedCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_PASSWORD_PROTECTED, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetSpectatorPort(uint16 unSpectatorPort) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerPlayingWrapper::SetSpectatorServerName(const char *pszSpectatorServerName) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerPlayingWrapper::ClearAllKeyValues() { + CGameServerClearAllKVsCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_CLEAR_ALL_KEY_VALUES, true, __FUNCTION__)); + CGameServerClearAllKVsCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_CLEAR_ALL_KEY_VALUES, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetKeyValue(const char *pKey, const char *pValue) { + CGameServerSetKeyValueCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_KEY_VALUE, true, __FUNCTION__)); + CGameServerSetKeyValueCall(pKey, pValue).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetKeyValueCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_KEY_VALUE, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetGameTags(const char *pchGameTags) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerPlayingWrapper::SetGameData(const char *pchGameData) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerPlayingWrapper::SetRegion(const char *pszRegion) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +bool CSteamGameServerPlayingWrapper::SendUserConnectAndAuthenticate(uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser) { + CGameServerSendUserConnectAndAuthenticateCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SEND_USER_CONNECT_AND_AUTHENTICATE, true, __FUNCTION__)); + CGameServerSendUserConnectAndAuthenticateCall(unIPClient, pvAuthBlob, cubAuthBlobSize).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSendUserConnectAndAuthenticateCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SEND_USER_CONNECT_AND_AUTHENTICATE, false, __FUNCTION__)); + + bool res = playEndCall->m_Res; + *pSteamIDUser = CSteamID(playEndCall->m_OutSteamId); + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +CSteamID CSteamGameServerPlayingWrapper::CreateUnauthenticatedUserConnection() { + CGameServerCreateUnauthUserConnectionCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_CREATE_UNAUTH_USER_CONNECTION, true, __FUNCTION__)); + CGameServerCreateUnauthUserConnectionCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_CREATE_UNAUTH_USER_CONNECTION, false, __FUNCTION__)); + + CSteamID res = playEndCall->m_SteamId; + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +void CSteamGameServerPlayingWrapper::SendUserDisconnect(CSteamID steamIDUser) { + CGameServerSendUserDisconnectCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SEND_USER_DISCONNECT, true, __FUNCTION__)); + CGameServerSendUserDisconnectCall(steamIDUser).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSendUserDisconnectCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SEND_USER_DISCONNECT, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +bool CSteamGameServerPlayingWrapper::BUpdateUserData(CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore) { + CGameServerBUpdateUserDataCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_BUPDATE_USER_DATA, true, __FUNCTION__)); + CGameServerBUpdateUserDataCall(steamIDUser, pchPlayerName, uScore).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerBUpdateUserDataCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_BUPDATE_USER_DATA, false, __FUNCTION__)); + + bool res = playEndCall->m_Res; + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +HAuthTicket CSteamGameServerPlayingWrapper::GetAuthSessionTicket(void *pTicket, int cbMaxTicket, uint32 *pcbTicket) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_HAuthTicketInvalid; +} + +EBeginAuthSessionResult CSteamGameServerPlayingWrapper::BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_EBeginAuthSessionResultInvalidTicket; +} + +void CSteamGameServerPlayingWrapper::EndAuthSession(CSteamID steamID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerPlayingWrapper::CancelAuthTicket(HAuthTicket hAuthTicket) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +EUserHasLicenseForAppResult CSteamGameServerPlayingWrapper::UserHasLicenseForApp(CSteamID steamID, AppId_t appID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_EUserHasLicenseResultHasLicense; +} + +bool CSteamGameServerPlayingWrapper::RequestUserGroupStatus(CSteamID steamIDUser, CSteamID steamIDGroup) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamGameServerPlayingWrapper::GetGameplayStats() { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +SteamAPICall_t CSteamGameServerPlayingWrapper::GetServerReputation() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + +uint32 CSteamGameServerPlayingWrapper::GetPublicIP() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamGameServerPlayingWrapper::HandleIncomingPacket(const void *pData, int cbData, uint32 srcIP, uint16 srcPort) { + CGameServerHandleIncomingPacketCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_HANDLE_INCOMING_PACKET, true, __FUNCTION__)); + CGameServerHandleIncomingPacketCall(pData, cbData, srcIP, srcPort).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerHandleIncomingPacketCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_HANDLE_INCOMING_PACKET, false, __FUNCTION__)); + + bool res = playEndCall->m_Res; + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +int CSteamGameServerPlayingWrapper::GetNextOutgoingPacket(void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort) { + CGameServerGetNextOutgoingPacketCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_GET_NEXT_OUTGOING_PACKET, true, __FUNCTION__)); + CGameServerGetNextOutgoingPacketCall(cbMaxOut).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerGetNextOutgoingPacketCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_GET_NEXT_OUTGOING_PACKET, false, __FUNCTION__)); + + int res = playEndCall->m_Result; + *pNetAdr = playEndCall->m_Addr; + *pPort = playEndCall->m_Port; + memcpy(pOut, playEndCall->m_Buf, playEndCall->m_BufLen); + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); + + return res; +} + +void CSteamGameServerPlayingWrapper::EnableHeartbeats(bool bActive) { + CGameServerEnableHeartbeatsCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_ENABLE_HEARTBEATS, true, __FUNCTION__)); + CGameServerEnableHeartbeatsCall(bActive).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerEnableHeartbeatsCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_ENABLE_HEARTBEATS, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::SetHeartbeatInterval(int iHeartbeatInterval) { + CGameServerSetHeartbeatIntervalCall* playCall = dynamic_cast(m_Player->getNextCall(false, false, ECF_GS_SET_HEARTBEATS_INTERVAL, true, __FUNCTION__)); + CGameServerSetHeartbeatIntervalCall(iHeartbeatInterval).ensureArgsAreEqual(playCall, m_bStrictChecks, __FUNCTION__); + CGameServerSetHeartbeatIntervalCall* playEndCall = dynamic_cast(m_Player->getNextCall(false, true, ECF_GS_SET_HEARTBEATS_INTERVAL, false, __FUNCTION__)); + + m_Player->freeFuncCall(playCall); m_Player->freeFuncCall(playEndCall); +} + +void CSteamGameServerPlayingWrapper::ForceHeartbeat() { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +SteamAPICall_t CSteamGameServerPlayingWrapper::AssociateWithClan(CSteamID steamIDClan) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + +SteamAPICall_t CSteamGameServerPlayingWrapper::ComputeNewPlayerCompatibility(CSteamID steamIDNewPlayer) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + + + + + + + +CSteamAppsPlayingWrapper::CSteamAppsPlayingWrapper(CPlayingEngExtInterceptor* player) { + m_Player = player; + m_bStrictChecks = player->m_bStrictChecks; +} + +bool CSteamAppsPlayingWrapper::BIsSubscribed() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsPlayingWrapper::BIsLowViolence() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsPlayingWrapper::BIsCybercafe() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsPlayingWrapper::BIsVACBanned() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +const char* CSteamAppsPlayingWrapper::GetCurrentGameLanguage() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return ""; +} + +const char* CSteamAppsPlayingWrapper::GetAvailableGameLanguages() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return ""; +} + +bool CSteamAppsPlayingWrapper::BIsSubscribedApp(AppId_t appID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsPlayingWrapper::BIsDlcInstalled(AppId_t appID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +uint32 CSteamAppsPlayingWrapper::GetEarliestPurchaseUnixTime(AppId_t nAppID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamAppsPlayingWrapper::BIsSubscribedFromFreeWeekend() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +int CSteamAppsPlayingWrapper::GetDLCCount() { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamAppsPlayingWrapper::BGetDLCDataByIndex(int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamAppsPlayingWrapper::InstallDLC(AppId_t nAppID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamAppsPlayingWrapper::UninstallDLC(AppId_t nAppID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamAppsPlayingWrapper::RequestAppProofOfPurchaseKey(AppId_t nAppID) { + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +bool CSteamAppsPlayingWrapper::GetCurrentBetaName(char *pchName, int cchNameBufferSize) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsPlayingWrapper::MarkContentCorrupt(bool bMissingFilesOnly) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +uint32 CSteamAppsPlayingWrapper::GetInstalledDepots(DepotId_t *pvecDepots, uint32 cMaxDepots) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +uint32 CSteamAppsPlayingWrapper::GetAppInstallDir(AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize) { + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} diff --git a/rehlds/testsuite/player.h b/rehlds/testsuite/player.h new file mode 100644 index 0000000..619fe6a --- /dev/null +++ b/rehlds/testsuite/player.h @@ -0,0 +1,202 @@ +#pragma once +#ifdef _WIN32 + +#define TESTPLAYER_FUNCTREE_DEPTH 8 +#define TESTPLAYER_FUNCCALL_MAXSIZE 17000 + +#include "osconfig.h" +#include "funccalls.h" +#include "rehlds/platform.h" + +#include +#include + +class CPlayingEngExtInterceptor; + + +class CSteamAppsPlayingWrapper : public ISteamApps +{ +private: + CPlayingEngExtInterceptor* m_Player; + bool m_bStrictChecks; + +public: + CSteamAppsPlayingWrapper(CPlayingEngExtInterceptor* player); + + virtual bool BIsSubscribed(); + virtual bool BIsLowViolence(); + virtual bool BIsCybercafe(); + virtual bool BIsVACBanned(); + virtual const char *GetCurrentGameLanguage(); + virtual const char *GetAvailableGameLanguages(); + + virtual bool BIsSubscribedApp(AppId_t appID); + virtual bool BIsDlcInstalled(AppId_t appID); + + virtual uint32 GetEarliestPurchaseUnixTime(AppId_t nAppID); + virtual bool BIsSubscribedFromFreeWeekend(); + + virtual int GetDLCCount(); + virtual bool BGetDLCDataByIndex(int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize); + + virtual void InstallDLC(AppId_t nAppID); + virtual void UninstallDLC(AppId_t nAppID); + + virtual void RequestAppProofOfPurchaseKey(AppId_t nAppID); + + virtual bool GetCurrentBetaName(char *pchName, int cchNameBufferSize); + virtual bool MarkContentCorrupt(bool bMissingFilesOnly); + virtual uint32 GetInstalledDepots(DepotId_t *pvecDepots, uint32 cMaxDepots); + + virtual uint32 GetAppInstallDir(AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize); +}; + +class CSteamGameServerPlayingWrapper : public ISteamGameServer +{ +private: + CPlayingEngExtInterceptor* m_Player; + bool m_bStrictChecks; + +public: + CSteamGameServerPlayingWrapper(CPlayingEngExtInterceptor* player); + + virtual bool InitGameServer(uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString); + virtual void SetProduct(const char *pszProduct); + virtual void SetGameDescription(const char *pszGameDescription); + virtual void SetModDir(const char *pszModDir); + virtual void SetDedicatedServer(bool bDedicated); + virtual void LogOn(const char *pszAccountName, const char *pszPassword); + virtual void LogOnAnonymous(); + virtual void LogOff(); + virtual bool BLoggedOn(); + virtual bool BSecure(); + virtual CSteamID GetSteamID(); + virtual bool WasRestartRequested(); + virtual void SetMaxPlayerCount(int cPlayersMax); + virtual void SetBotPlayerCount(int cBotplayers); + virtual void SetServerName(const char *pszServerName); + virtual void SetMapName(const char *pszMapName); + virtual void SetPasswordProtected(bool bPasswordProtected); + virtual void SetSpectatorPort(uint16 unSpectatorPort); + virtual void SetSpectatorServerName(const char *pszSpectatorServerName); + virtual void ClearAllKeyValues(); + virtual void SetKeyValue(const char *pKey, const char *pValue); + virtual void SetGameTags(const char *pchGameTags); + virtual void SetGameData(const char *pchGameData); + virtual void SetRegion(const char *pszRegion); + virtual bool SendUserConnectAndAuthenticate(uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser); + virtual CSteamID CreateUnauthenticatedUserConnection(); + virtual void SendUserDisconnect(CSteamID steamIDUser); + virtual bool BUpdateUserData(CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore); + virtual HAuthTicket GetAuthSessionTicket(void *pTicket, int cbMaxTicket, uint32 *pcbTicket); + virtual EBeginAuthSessionResult BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID); + virtual void EndAuthSession(CSteamID steamID); + virtual void CancelAuthTicket(HAuthTicket hAuthTicket); + virtual EUserHasLicenseForAppResult UserHasLicenseForApp(CSteamID steamID, AppId_t appID); + virtual bool RequestUserGroupStatus(CSteamID steamIDUser, CSteamID steamIDGroup); + virtual void GetGameplayStats(); + virtual SteamAPICall_t GetServerReputation(); + virtual uint32 GetPublicIP(); + virtual bool HandleIncomingPacket(const void *pData, int cbData, uint32 srcIP, uint16 srcPort); + virtual int GetNextOutgoingPacket(void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort); + virtual void EnableHeartbeats(bool bActive); + virtual void SetHeartbeatInterval(int iHeartbeatInterval); + virtual void ForceHeartbeat(); + virtual SteamAPICall_t AssociateWithClan(CSteamID steamIDClan); + virtual SteamAPICall_t ComputeNewPlayerCompatibility(CSteamID steamIDNewPlayer); +}; + +class CPlayingEngExtInterceptor : public IReHLDSPlatform { + friend class CSteamGameServerPlayingWrapper; + friend class CSteamAppsPlayingWrapper; +private: + + char m_FuncCallBuffer[TESTPLAYER_FUNCTREE_DEPTH * TESTPLAYER_FUNCCALL_MAXSIZE]; + void* m_FuncCalls[TESTPLAYER_FUNCTREE_DEPTH]; + bool m_FuncCallsFree[TESTPLAYER_FUNCTREE_DEPTH]; + + std::ifstream m_InStream; + int64_t m_inStreamSize; + bool m_bLastRead; + std::queue m_CommandsQueue; + + bool m_bStrictChecks; + + SOCKET m_ServerSocket; + + int m_SteamCallbacksCounter; + std::unordered_map m_SteamCallbacks; + std::unordered_map m_SteamCallbacksReverse; + CSteamAppsPlayingWrapper* m_SteamAppsWrapper; + + CSteamGameServerPlayingWrapper* m_GameServerWrapper; + + void* m_SteamBreakpadContext; + + hostent_data_t m_CurrentHostentData; + struct hostent m_CurrentHostent; + void setCurrentHostent(hostent_data_t* data); + + struct tm m_CurrentTm; + void setCurrentTm(struct tm* t); + + bool readFuncCall(); + + IEngExtCall* getNextCallInternal(bool peek); + + void playCallback(IEngCallbackCall* cb); + void playSteamCallback1(CSteamCallbackCall1* cb); + void playSteamCallback2(CSteamCallbackCall2* cb); + + int getOrRegisterSteamCallback(CCallbackBase* cb); + +public: + void* allocFuncCall(); + void freeFuncCall(void* fcall); + CPlayingEngExtInterceptor(const char* fname, bool strictChecks); + + IEngExtCall* getNextCall(bool peek, bool processCallbacks, ExtCallFuncs expectedOpcode, bool needStart, const char* callSource); + + virtual uint32_t time(uint32_t* pTime); + virtual struct tm* localtime(uint32_t time); + virtual void srand(uint32_t seed); + virtual int rand(); + + virtual void Sleep(DWORD msec); + virtual BOOL QueryPerfCounter(LARGE_INTEGER* counter); + virtual BOOL QueryPerfFreq(LARGE_INTEGER* freq); + virtual DWORD GetTickCount(); + virtual void GetLocalTime(LPSYSTEMTIME time); + virtual void GetSystemTime(LPSYSTEMTIME time); + virtual void GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo); + virtual BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); + virtual void GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); + + + virtual SOCKET socket(int af, int type, int protocol); + virtual int ioctlsocket(SOCKET s, long cmd, u_long *argp); + virtual int setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen); + virtual int closesocket(SOCKET s); + virtual int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen); + virtual int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen); + virtual int bind(SOCKET s, const struct sockaddr* addr, int namelen); + virtual int getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen); + virtual int WSAGetLastError(); + virtual struct hostent* gethostbyname(const char *name); + virtual int gethostname(char *name, int namelen); + + virtual void SteamAPI_SetBreakpadAppID(uint32 unAppID); + virtual void SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback); + virtual void SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback); + virtual bool SteamAPI_Init(); + virtual void SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall); + virtual ISteamApps* SteamApps(); + virtual bool SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString); + virtual ISteamGameServer* SteamGameServer(); + virtual void SteamGameServer_RunCallbacks(); + virtual void SteamAPI_RunCallbacks(); + virtual void SteamGameServer_Shutdown(); + virtual void SteamAPI_UnregisterCallback(CCallbackBase *pCallback); +}; + +#endif //_WIN32 diff --git a/rehlds/testsuite/recorder.cpp b/rehlds/testsuite/recorder.cpp new file mode 100644 index 0000000..0c915ad --- /dev/null +++ b/rehlds/testsuite/recorder.cpp @@ -0,0 +1,996 @@ +#include "precompiled.h" + +CRecorderFuncCall::CRecorderFuncCall(IEngExtCall* fcall) +{ + m_FuncCall = fcall; + m_StartWritten = false; + m_Next = m_Prev = NULL; +} + +CSteamCallbackRecordingWrapper::CSteamCallbackRecordingWrapper(CRecordingEngExtInterceptor* recorder, CCallbackBase* cb, int id) +{ + m_Recorder = recorder; + m_Wrapped = cb; + m_Id = id; + m_Size = cb->GetCallbackSizeBytes(); + m_iCallback = cb->GetICallback(); + this->m_nCallbackFlags = cb->GetFlags(); +} + +void CSteamCallbackRecordingWrapper::Run(void *pvParam) +{ + if (m_Wrapped->GetICallback() != this->GetICallback()) rehlds_syserror("%s: iCallback desync", __FUNCTION__); + if (m_Wrapped->GetFlags() != this->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + CSteamCallbackCall1 fcall(m_Id, pvParam, m_Size, m_Wrapped); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->Run(pvParam); + fcall.setResult(m_Wrapped); + this->SetFlags(m_Wrapped->GetFlags()); + this->SetICallback(m_Wrapped->GetICallback()); + m_Recorder->PopFunc(&frec); +} + +void CSteamCallbackRecordingWrapper::Run(void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall) +{ + if (m_Wrapped->GetICallback() != this->GetICallback()) rehlds_syserror("%s: iCallback desync", __FUNCTION__); + if (m_Wrapped->GetFlags() != this->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + CSteamCallbackCall2 fcall(m_Id, pvParam, m_Size, bIOFailure, hSteamAPICall, m_Wrapped); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->Run(pvParam, bIOFailure, hSteamAPICall); + fcall.setResult(m_Wrapped); + this->SetFlags(m_Wrapped->GetFlags()); + this->SetICallback(m_Wrapped->GetICallback()); + m_Recorder->PopFunc(&frec); +} + +int CSteamCallbackRecordingWrapper::GetCallbackSizeBytes() +{ + return m_Wrapped->GetCallbackSizeBytes(); +} + + + + +CSteamAppsRecordingWrapper::CSteamAppsRecordingWrapper(ISteamApps* original, CRecordingEngExtInterceptor* recorder) +{ + m_Wrapped = original; + m_Recorder = recorder; +} + +bool CSteamAppsRecordingWrapper::BIsSubscribed() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsRecordingWrapper::BIsLowViolence() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsRecordingWrapper::BIsCybercafe() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsRecordingWrapper::BIsVACBanned() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +const char* CSteamAppsRecordingWrapper::GetCurrentGameLanguage() +{ + CSteamAppGetCurrentGameLanguageCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + const char* res = m_Wrapped->GetCurrentGameLanguage(); + fcall.setResult(res); + m_Recorder->PopFunc(&frec); + return res; +} + +const char* CSteamAppsRecordingWrapper::GetAvailableGameLanguages() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return NULL; +} + +bool CSteamAppsRecordingWrapper::BIsSubscribedApp(AppId_t appID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsRecordingWrapper::BIsDlcInstalled(AppId_t appID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +uint32 CSteamAppsRecordingWrapper::GetEarliestPurchaseUnixTime(AppId_t nAppID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamAppsRecordingWrapper::BIsSubscribedFromFreeWeekend() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +int CSteamAppsRecordingWrapper::GetDLCCount() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamAppsRecordingWrapper::BGetDLCDataByIndex(int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamAppsRecordingWrapper::InstallDLC(AppId_t nAppID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamAppsRecordingWrapper::UninstallDLC(AppId_t nAppID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamAppsRecordingWrapper::RequestAppProofOfPurchaseKey(AppId_t nAppID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +bool CSteamAppsRecordingWrapper::GetCurrentBetaName(char *pchName, int cchNameBufferSize) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +bool CSteamAppsRecordingWrapper::MarkContentCorrupt(bool bMissingFilesOnly) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +uint32 CSteamAppsRecordingWrapper::GetInstalledDepots(DepotId_t *pvecDepots, uint32 cMaxDepots) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +uint32 CSteamAppsRecordingWrapper::GetAppInstallDir(AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + + +CSteamGameServerRecordingWrapper::CSteamGameServerRecordingWrapper(ISteamGameServer* original, CRecordingEngExtInterceptor* recorder) +{ + m_Wrapped = original; + m_Recorder = recorder; +} + +bool CSteamGameServerRecordingWrapper::InitGameServer(uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamGameServerRecordingWrapper::SetProduct(const char *pszProduct) +{ + CGameServerSetProductCall fcall(pszProduct); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetProduct(pszProduct); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetGameDescription(const char *pszGameDescription) +{ + CGameServerSetGameDescCall fcall(pszGameDescription); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetGameDescription(pszGameDescription); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetModDir(const char *pszModDir) +{ + CGameServerSetModDirCall fcall(pszModDir); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetModDir(pszModDir); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetDedicatedServer(bool bDedicated) +{ + CGameServerSetDedicatedServerCall fcall(bDedicated); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetDedicatedServer(bDedicated); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::LogOn(const char *pszAccountName, const char *pszPassword) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerRecordingWrapper::LogOnAnonymous() +{ + CGameServerLogOnAnonymousCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->LogOnAnonymous(); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::LogOff() +{ + CGameServerLogOffCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->LogOff(); + m_Recorder->PopFunc(&frec); +} + +bool CSteamGameServerRecordingWrapper::BLoggedOn() +{ + CGameServerBLoggedOnCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + bool res = m_Wrapped->BLoggedOn(); + fcall.setResult(res); + m_Recorder->PopFunc(&frec); + return res; +} + +bool CSteamGameServerRecordingWrapper::BSecure() +{ + CGameServerBSecureCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + bool res = m_Wrapped->BSecure(); + fcall.setResult(res); + m_Recorder->PopFunc(&frec); + return res; +} + +CSteamID CSteamGameServerRecordingWrapper::GetSteamID() +{ + CGameServerGetSteamIdCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + CSteamID res = m_Wrapped->GetSteamID(); + fcall.setResult(res); + m_Recorder->PopFunc(&frec); + return res; +} + +bool CSteamGameServerRecordingWrapper::WasRestartRequested() +{ + CGameServerWasRestartRequestedCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + bool res = m_Wrapped->WasRestartRequested(); + fcall.setResult(res); + m_Recorder->PopFunc(&frec); + return res; +} + +void CSteamGameServerRecordingWrapper::SetMaxPlayerCount(int cPlayersMax) +{ + CGameServerSetMaxPlayersCall fcall(cPlayersMax); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetMaxPlayerCount(cPlayersMax); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetBotPlayerCount(int cBotplayers) +{ + CGameServerSetBotCountCall fcall(cBotplayers); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetBotPlayerCount(cBotplayers); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetServerName(const char *pszServerName) +{ + CGameServerSetServerNameCall fcall(pszServerName); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetServerName(pszServerName); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetMapName(const char *pszMapName) +{ + CGameServerSetMapNameCall fcall(pszMapName); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetMapName(pszMapName); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetPasswordProtected(bool bPasswordProtected) +{ + CGameServerSetPasswordProtectedCall fcall(bPasswordProtected); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetPasswordProtected(bPasswordProtected); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetSpectatorPort(uint16 unSpectatorPort) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerRecordingWrapper::SetSpectatorServerName(const char *pszSpectatorServerName) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerRecordingWrapper::ClearAllKeyValues() +{ + CGameServerClearAllKVsCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->ClearAllKeyValues(); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetKeyValue(const char *pKey, const char *pValue) +{ + CGameServerSetKeyValueCall fcall(pKey, pValue); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetKeyValue(pKey, pValue); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetGameTags(const char *pchGameTags) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerRecordingWrapper::SetGameData(const char *pchGameData) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerRecordingWrapper::SetRegion(const char *pszRegion) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +bool CSteamGameServerRecordingWrapper::SendUserConnectAndAuthenticate(uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser) +{ + CGameServerSendUserConnectAndAuthenticateCall fcall(unIPClient, pvAuthBlob, cubAuthBlobSize); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + bool res = m_Wrapped->SendUserConnectAndAuthenticate(unIPClient, pvAuthBlob, cubAuthBlobSize, pSteamIDUser); + fcall.setResult(*pSteamIDUser, res); + m_Recorder->PopFunc(&frec); + return res; +} + +CSteamID CSteamGameServerRecordingWrapper::CreateUnauthenticatedUserConnection() +{ + CGameServerCreateUnauthUserConnectionCall fcall; CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + CSteamID res = m_Wrapped->CreateUnauthenticatedUserConnection(); + fcall.setResult(res); + m_Recorder->PopFunc(&frec); + return res; +} + +void CSteamGameServerRecordingWrapper::SendUserDisconnect(CSteamID steamIDUser) +{ + CGameServerSendUserDisconnectCall fcall(steamIDUser); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SendUserDisconnect(steamIDUser); + m_Recorder->PopFunc(&frec); +} + +bool CSteamGameServerRecordingWrapper::BUpdateUserData(CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore) +{ + CGameServerBUpdateUserDataCall fcall(steamIDUser, pchPlayerName, uScore); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + bool res = m_Wrapped->BUpdateUserData(steamIDUser, pchPlayerName, uScore); + fcall.setResult(res); + m_Recorder->PopFunc(&frec); + return res; +} + +HAuthTicket CSteamGameServerRecordingWrapper::GetAuthSessionTicket(void *pTicket, int cbMaxTicket, uint32 *pcbTicket) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_HAuthTicketInvalid; +} + +EBeginAuthSessionResult CSteamGameServerRecordingWrapper::BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_EBeginAuthSessionResultInvalidTicket; +} + +void CSteamGameServerRecordingWrapper::EndAuthSession(CSteamID steamID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void CSteamGameServerRecordingWrapper::CancelAuthTicket(HAuthTicket hAuthTicket) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +EUserHasLicenseForAppResult CSteamGameServerRecordingWrapper::UserHasLicenseForApp(CSteamID steamID, AppId_t appID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_EUserHasLicenseResultDoesNotHaveLicense; +} + +bool CSteamGameServerRecordingWrapper::RequestUserGroupStatus(CSteamID steamIDUser, CSteamID steamIDGroup) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return false; +} + +void CSteamGameServerRecordingWrapper::GetGameplayStats() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +SteamAPICall_t CSteamGameServerRecordingWrapper::GetServerReputation() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + +uint32 CSteamGameServerRecordingWrapper::GetPublicIP() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return 0; +} + +bool CSteamGameServerRecordingWrapper::HandleIncomingPacket(const void *pData, int cbData, uint32 srcIP, uint16 srcPort) +{ + CGameServerHandleIncomingPacketCall fcall(pData, cbData, srcIP, srcPort); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + bool res = m_Wrapped->HandleIncomingPacket(pData, cbData, srcIP, srcPort); + fcall.setResult(res); + m_Recorder->PopFunc(&frec); + return res; +} + +int CSteamGameServerRecordingWrapper::GetNextOutgoingPacket(void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort) +{ + CGameServerGetNextOutgoingPacketCall fcall(cbMaxOut); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + int res = m_Wrapped->GetNextOutgoingPacket(pOut, cbMaxOut, pNetAdr, pPort); + fcall.setResult(pOut, res, pNetAdr, pPort); + m_Recorder->PopFunc(&frec); + return res; +} + +void CSteamGameServerRecordingWrapper::EnableHeartbeats(bool bActive) +{ + CGameServerEnableHeartbeatsCall fcall(bActive); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->EnableHeartbeats(bActive); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::SetHeartbeatInterval(int iHeartbeatInterval) +{ + CGameServerSetHeartbeatIntervalCall fcall(iHeartbeatInterval); CRecorderFuncCall frec(&fcall); + m_Recorder->PushFunc(&frec); + m_Wrapped->SetHeartbeatInterval(iHeartbeatInterval); + m_Recorder->PopFunc(&frec); +} + +void CSteamGameServerRecordingWrapper::ForceHeartbeat() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +SteamAPICall_t CSteamGameServerRecordingWrapper::AssociateWithClan(CSteamID steamIDClan) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + +SteamAPICall_t CSteamGameServerRecordingWrapper::ComputeNewPlayerCompatibility(CSteamID steamIDNewPlayer) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return k_uAPICallInvalid; +} + +CRecordingEngExtInterceptor::CRecordingEngExtInterceptor(const char* fname, IReHLDSPlatform* basePlatform) +{ + m_OutStream.exceptions(std::ios::badbit | std::ios::failbit); + m_OutStream.open(fname, std::ios::out | std::ios::binary); + + m_ServerSocket = INVALID_SOCKET; + m_SteamCallbacksCounter = 0; + m_SteamAppsWrapper = NULL; + m_GameServerWrapper = NULL; + m_SteamBreakpadContext = NULL; + m_RootFunc = m_LastFunc = NULL; + m_BasePlatform = basePlatform; + + uint16_t versionMajor = TESTSUITE_PROTOCOL_VERSION_MAJOR; + uint16_t versionMinor = TESTSUITE_PROTOCOL_VERSION_MINOR; + m_OutStream.write((char*)&versionMinor, 2).write((char*)&versionMajor, 2); + + const char* cmdLine = GetCommandLineA(); + int cmdLineLength = strlen(cmdLine) + 1; + + m_OutStream.write((char*)&cmdLineLength, 4); + m_OutStream.write(cmdLine, cmdLineLength); +} + +void CRecordingEngExtInterceptor::writeCall(bool start, bool end, IEngExtCall* fcall) +{ + uint16_t opc = fcall->getOpcode(); + if (start) + opc |= (1 << 15); + + if (end) + opc |= (1 << 14); + + m_OutStream.write((char*)&opc, 2); + if (start) + fcall->writePrologue(m_OutStream); + + if (end) + fcall->writeEpilogue(m_OutStream); + + m_OutStream.flush(); +} + +void CRecordingEngExtInterceptor::PushFunc(CRecorderFuncCall* func) +{ + CRecorderFuncCall* cc = m_LastFunc; + while (cc != NULL) { + if (!cc->m_StartWritten) { + writeCall(true, false, cc->m_FuncCall); + cc->m_StartWritten = true; + } + cc = cc->m_Prev; + } + + if (m_LastFunc != NULL) { + m_LastFunc->m_Next = func; + func->m_Next = NULL; + func->m_Prev = m_LastFunc; + m_LastFunc = func; + } + else + { + m_LastFunc = m_RootFunc = func; + func->m_Next = func->m_Prev = NULL; + } + +} + +void CRecordingEngExtInterceptor::PopFunc(CRecorderFuncCall* func) +{ + if (func != m_LastFunc) + rehlds_syserror("%s: stack corrupted", __FUNCTION__); + + writeCall(!func->m_StartWritten, true, func->m_FuncCall); + if (m_LastFunc->m_Prev == NULL) { + m_LastFunc = m_RootFunc = NULL; + } + else + { + m_LastFunc = m_LastFunc->m_Prev; + m_LastFunc->m_Next = NULL; + } +} + +uint32_t CRecordingEngExtInterceptor::time(uint32_t* pTime) +{ + CStdTimeCall fcall(pTime); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + uint32_t res = m_BasePlatform->time(pTime); + fcall.setResult(res); + PopFunc(&frec); + + return res; +} + +struct tm* CRecordingEngExtInterceptor::localtime(uint32_t time) +{ + CStdLocalTimeCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + struct tm* res = m_BasePlatform->localtime(time); + fcall.setResult(res); + PopFunc(&frec); + + return res; +} + +void CRecordingEngExtInterceptor::srand(uint32_t seed) +{ + CStdSrandCall fcall(seed); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->srand(seed); + PopFunc(&frec); +} + +int CRecordingEngExtInterceptor::rand() +{ + CStdRandCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->rand(); + fcall.setResult(res); + PopFunc(&frec); + + return res; +} + +void CRecordingEngExtInterceptor::Sleep(DWORD msec) +{ + CSleepExtCall fcall(msec); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->Sleep(msec); + PopFunc(&frec); +} + +BOOL CRecordingEngExtInterceptor::QueryPerfCounter(LARGE_INTEGER* counter) +{ + CQueryPerfCounterCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + BOOL res = m_BasePlatform->QueryPerfCounter(counter); + fcall.SetResult(*counter, res); + PopFunc(&frec); + return res; +} + +BOOL CRecordingEngExtInterceptor::QueryPerfFreq(LARGE_INTEGER* counter) +{ + CQueryPerfFreqCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + BOOL res = m_BasePlatform->QueryPerfFreq(counter); + fcall.SetResult(*counter, res); + PopFunc(&frec); + return res; +} + +DWORD CRecordingEngExtInterceptor::GetTickCount() +{ + CGetTickCountCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + DWORD res = m_BasePlatform->GetTickCount(); + fcall.SetResult(res); + PopFunc(&frec); + return res; +} + +void CRecordingEngExtInterceptor::GetLocalTime(LPSYSTEMTIME time) +{ + CGetLocalTimeCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->GetLocalTime(time); + fcall.SetResult(time); + PopFunc(&frec); +} + +void CRecordingEngExtInterceptor::GetSystemTime(LPSYSTEMTIME time) +{ + CGetSystemTimeCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->GetSystemTime(time); + fcall.SetResult(time); + PopFunc(&frec); +} + +void CRecordingEngExtInterceptor::GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo) +{ + CGetTimeZoneInfoCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->GetTimeZoneInfo(zinfo); + fcall.SetResult(zinfo); + PopFunc(&frec); +} + +BOOL CRecordingEngExtInterceptor::GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime) +{ + CGetProcessTimesCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + BOOL res = m_BasePlatform->GetProcessTimes(hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); + fcall.setResult(res, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); + PopFunc(&frec); + return res; +} + +void CRecordingEngExtInterceptor::GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime) +{ + CGetSystemTimeAsFileTimeCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->GetSystemTimeAsFileTime(lpSystemTimeAsFileTime); + fcall.setResult(lpSystemTimeAsFileTime); + PopFunc(&frec); +} + +SOCKET CRecordingEngExtInterceptor::socket(int af, int type, int protocol) +{ + CSocketCall fcall(af, type, protocol); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + SOCKET s = m_BasePlatform->socket(af, type, protocol); + fcall.setResult(s); + PopFunc(&frec); + return s; +} + +int CRecordingEngExtInterceptor::ioctlsocket(SOCKET s, long cmd, u_long *argp) +{ + CIoCtlSocketCall fcall(s, cmd, *argp); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->ioctlsocket(s, cmd, argp); + fcall.setResult(*argp, res); + PopFunc(&frec); + return res; +} + +int CRecordingEngExtInterceptor::setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen) +{ + CSetSockOptCall fcall(s, level, optname, optval, optlen); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->setsockopt(s, level, optname, optval, optlen); + fcall.setResult(res); + PopFunc(&frec); + return res; +} + +int CRecordingEngExtInterceptor::closesocket(SOCKET s) +{ + CCloseSocketCall fcall(s); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->closesocket(s); + fcall.setResult(s); + PopFunc(&frec); + return res; +} + +int CRecordingEngExtInterceptor::recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen) +{ + CRecvFromCall fcall(s, len, flags, *fromlen); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->recvfrom(s, buf, len, flags, from, fromlen); + fcall.setResult(buf, from, *fromlen, res); + PopFunc(&frec); + return res; +} + +int CRecordingEngExtInterceptor::sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) +{ + CSendToCall fcall(s, buf, len, flags, to, tolen); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->sendto(s, buf, len, flags, to, tolen); + fcall.setResult(res); + PopFunc(&frec); + return res; +} + +int CRecordingEngExtInterceptor::bind(SOCKET s, const struct sockaddr* addr, int namelen) +{ + CBindCall fcall(s, addr, namelen); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->bind(s, addr, namelen); + fcall.setResult(res); + PopFunc(&frec); + return res; +} + +int CRecordingEngExtInterceptor::getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen) +{ + CGetSockNameCall fcall(s, *namelen); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->getsockname(s, name, namelen); + fcall.setResult(name, *namelen, res); + PopFunc(&frec); + return res; +} + +int CRecordingEngExtInterceptor::WSAGetLastError() +{ + CWSAGetLastErrorCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->WSAGetLastError(); + fcall.setResult(res); + PopFunc(&frec); + return res; +} + +struct hostent* CRecordingEngExtInterceptor::gethostbyname(const char *name) +{ + CGetHostByNameCall fcall(name); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + struct hostent* res = m_BasePlatform->gethostbyname(name); + fcall.setResult(res); + PopFunc(&frec); + return res; +} + +int CRecordingEngExtInterceptor::gethostname(char *name, int namelen) +{ + CGetHostNameCall fcall(namelen); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + int res = m_BasePlatform->gethostname(name, namelen); + fcall.setResult(name, res); + PopFunc(&frec); + return res; +} + + +CSteamCallbackRecordingWrapper* CRecordingEngExtInterceptor::getOrCreateCallbackWrapper(CCallbackBase *pCallback) +{ + auto itr = m_SteamCallbacks.find(pCallback); + if (itr == m_SteamCallbacks.end()) + { + CSteamCallbackRecordingWrapper* wrappee = new CSteamCallbackRecordingWrapper(this, pCallback, m_SteamCallbacksCounter++); + m_SteamCallbacks[pCallback] = wrappee; + return wrappee; + } + else + { + return (*itr).second; + } +} + +void CRecordingEngExtInterceptor::SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback) +{ + CSteamCallbackRecordingWrapper* wrappee = getOrCreateCallbackWrapper(pCallback); + + if (wrappee->GetFlags() != pCallback->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + //if (wrappee->GetICallback() != pCallback->GetICallback()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + CSteamApiRegisterCallbackCall fcall(wrappee->getRehldsCallbackId(), iCallback, wrappee); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->SteamAPI_RegisterCallback(wrappee, iCallback); + + fcall.setResult(wrappee); + pCallback->SetFlags(wrappee->GetFlags()); + pCallback->SetICallback(wrappee->GetICallback()); + + PopFunc(&frec); +} + +bool CRecordingEngExtInterceptor::SteamAPI_Init() +{ + CSteamApiInitCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + bool res = m_BasePlatform->SteamAPI_Init(); + fcall.setResult(res); + PopFunc(&frec); + return res; +} + +void CRecordingEngExtInterceptor::SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall) +{ + CSteamCallbackRecordingWrapper* wrappee = getOrCreateCallbackWrapper(pCallback); + + if (wrappee->GetFlags() != pCallback->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + if (wrappee->GetICallback() != pCallback->GetICallback()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + CSteamApiUnrigestierCallResultCall fcall(wrappee->getRehldsCallbackId(), hAPICall, wrappee); CRecorderFuncCall frec(&fcall); + + PushFunc(&frec); + + m_BasePlatform->SteamAPI_UnregisterCallResult(wrappee, hAPICall); + + fcall.setResult(wrappee); + pCallback->SetFlags(wrappee->GetFlags()); + pCallback->SetICallback(wrappee->GetICallback()); + + PopFunc(&frec); +} + +ISteamApps* CRecordingEngExtInterceptor::SteamApps() +{ + CSteamAppsCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + if (m_SteamAppsWrapper == NULL) + { + ISteamApps* orig = m_BasePlatform->SteamApps(); + fcall.setReturnNull(orig == NULL); + if (orig != NULL) + m_SteamAppsWrapper = new CSteamAppsRecordingWrapper(orig, this); + } + else + { + m_BasePlatform->SteamApps(); + fcall.setReturnNull(false); + } + + PopFunc(&frec); + return m_SteamAppsWrapper; +} + +bool CRecordingEngExtInterceptor::SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString) +{ + CSteamGameServerInitCall fcall(unIP, usSteamPort, usGamePort, usQueryPort, eServerMode, pchVersionString); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + bool res = m_BasePlatform->SteamGameServer_Init(unIP, usSteamPort, usGamePort, usQueryPort, eServerMode, pchVersionString); + fcall.setResult(res); + PopFunc(&frec); + return res; +} + +ISteamGameServer* CRecordingEngExtInterceptor::SteamGameServer() +{ + CSteamGameServerCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + + if (m_GameServerWrapper == NULL) + { + ISteamGameServer* orig = m_BasePlatform->SteamGameServer(); + fcall.setReturnNull(orig == NULL); + if (orig != NULL) + m_GameServerWrapper = new CSteamGameServerRecordingWrapper(orig, this); + } + else + { + fcall.setReturnNull(false); + m_BasePlatform->SteamGameServer(); + } + + PopFunc(&frec); + return m_GameServerWrapper; +} + +void CRecordingEngExtInterceptor::SteamAPI_SetBreakpadAppID(uint32 unAppID) +{ + CSteamApiSetBreakpadAppIdCall fcall(unAppID); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->SteamAPI_SetBreakpadAppID(unAppID); + PopFunc(&frec); +} + +void CRecordingEngExtInterceptor::SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback) +{ + m_BasePlatform->SteamAPI_UseBreakpadCrashHandler(pchVersion, pchDate, pchTime, bFullMemoryDumps, pvContext, m_pfnPreMinidumpCallback); +} + +void CRecordingEngExtInterceptor::SteamGameServer_RunCallbacks() +{ + CSteamGameServerRunCallbacksCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->SteamGameServer_RunCallbacks(); + PopFunc(&frec); +} + +void CRecordingEngExtInterceptor::SteamAPI_RunCallbacks() +{ + CSteamApiRunCallbacksCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->SteamAPI_RunCallbacks(); + PopFunc(&frec); +} + +void CRecordingEngExtInterceptor::SteamGameServer_Shutdown() +{ + CSteamGameServerShutdownCall fcall; CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->SteamGameServer_Shutdown(); + m_GameServerWrapper = NULL; + PopFunc(&frec); +} + +void CRecordingEngExtInterceptor::SteamAPI_UnregisterCallback(CCallbackBase *pCallback) +{ + CSteamCallbackRecordingWrapper* wrappee = getOrCreateCallbackWrapper(pCallback); + + if (wrappee->GetFlags() != pCallback->GetFlags()) rehlds_syserror("%s: flags desync", __FUNCTION__); + if (wrappee->GetICallback() != pCallback->GetICallback()) rehlds_syserror("%s: flags desync", __FUNCTION__); + + CSteamApiUnregisterCallbackCall fcall(wrappee->getRehldsCallbackId(), wrappee); CRecorderFuncCall frec(&fcall); + PushFunc(&frec); + m_BasePlatform->SteamAPI_UnregisterCallback(wrappee); + + fcall.setResult(wrappee); + pCallback->SetFlags(wrappee->GetFlags()); + pCallback->SetICallback(wrappee->GetICallback()); + + PopFunc(&frec); +} \ No newline at end of file diff --git a/rehlds/testsuite/recorder.h b/rehlds/testsuite/recorder.h new file mode 100644 index 0000000..bb354ac --- /dev/null +++ b/rehlds/testsuite/recorder.h @@ -0,0 +1,201 @@ +#pragma once +#ifdef _WIN32 + +#include "osconfig.h" +#include "testsuite.h" +#include "funccalls.h" + +class CRecordingEngExtInterceptor; + +class CRecorderFuncCall { + friend class CRecordingEngExtInterceptor; + +private: + IEngExtCall* m_FuncCall; + bool m_StartWritten; + CRecorderFuncCall* m_Next; + CRecorderFuncCall* m_Prev; + +public: + CRecorderFuncCall(IEngExtCall* fcall); +}; + +class CSteamAppsRecordingWrapper : public ISteamApps +{ +private: + ISteamApps* m_Wrapped; + CRecordingEngExtInterceptor* m_Recorder; + +public: + CSteamAppsRecordingWrapper(ISteamApps* original, CRecordingEngExtInterceptor* recorder); + + virtual bool BIsSubscribed(); + virtual bool BIsLowViolence(); + virtual bool BIsCybercafe(); + virtual bool BIsVACBanned(); + virtual const char *GetCurrentGameLanguage(); + virtual const char *GetAvailableGameLanguages(); + + virtual bool BIsSubscribedApp(AppId_t appID); + virtual bool BIsDlcInstalled(AppId_t appID); + + virtual uint32 GetEarliestPurchaseUnixTime(AppId_t nAppID); + virtual bool BIsSubscribedFromFreeWeekend(); + + virtual int GetDLCCount(); + virtual bool BGetDLCDataByIndex(int iDLC, AppId_t *pAppID, bool *pbAvailable, char *pchName, int cchNameBufferSize); + + virtual void InstallDLC(AppId_t nAppID); + virtual void UninstallDLC(AppId_t nAppID); + + virtual void RequestAppProofOfPurchaseKey(AppId_t nAppID); + + virtual bool GetCurrentBetaName(char *pchName, int cchNameBufferSize); + virtual bool MarkContentCorrupt(bool bMissingFilesOnly); + virtual uint32 GetInstalledDepots(DepotId_t *pvecDepots, uint32 cMaxDepots); + + virtual uint32 GetAppInstallDir(AppId_t appID, char *pchFolder, uint32 cchFolderBufferSize); +}; + +class CSteamGameServerRecordingWrapper : public ISteamGameServer +{ +private: + ISteamGameServer* m_Wrapped; + CRecordingEngExtInterceptor* m_Recorder; + +public: + CSteamGameServerRecordingWrapper(ISteamGameServer* original, CRecordingEngExtInterceptor* recorder); + + virtual bool InitGameServer(uint32 unIP, uint16 usGamePort, uint16 usQueryPort, uint32 unFlags, AppId_t nGameAppId, const char *pchVersionString); + virtual void SetProduct(const char *pszProduct); + virtual void SetGameDescription(const char *pszGameDescription); + virtual void SetModDir(const char *pszModDir); + virtual void SetDedicatedServer(bool bDedicated); + virtual void LogOn(const char *pszAccountName, const char *pszPassword); + virtual void LogOnAnonymous(); + virtual void LogOff(); + virtual bool BLoggedOn(); + virtual bool BSecure(); + virtual CSteamID GetSteamID(); + virtual bool WasRestartRequested(); + virtual void SetMaxPlayerCount(int cPlayersMax); + virtual void SetBotPlayerCount(int cBotplayers); + virtual void SetServerName(const char *pszServerName); + virtual void SetMapName(const char *pszMapName); + virtual void SetPasswordProtected(bool bPasswordProtected); + virtual void SetSpectatorPort(uint16 unSpectatorPort); + virtual void SetSpectatorServerName(const char *pszSpectatorServerName); + virtual void ClearAllKeyValues(); + virtual void SetKeyValue(const char *pKey, const char *pValue); + virtual void SetGameTags(const char *pchGameTags); + virtual void SetGameData(const char *pchGameData); + virtual void SetRegion(const char *pszRegion); + virtual bool SendUserConnectAndAuthenticate(uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser); + virtual CSteamID CreateUnauthenticatedUserConnection(); + virtual void SendUserDisconnect(CSteamID steamIDUser); + virtual bool BUpdateUserData(CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore); + virtual HAuthTicket GetAuthSessionTicket(void *pTicket, int cbMaxTicket, uint32 *pcbTicket); + virtual EBeginAuthSessionResult BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID); + virtual void EndAuthSession(CSteamID steamID); + virtual void CancelAuthTicket(HAuthTicket hAuthTicket); + virtual EUserHasLicenseForAppResult UserHasLicenseForApp(CSteamID steamID, AppId_t appID); + virtual bool RequestUserGroupStatus(CSteamID steamIDUser, CSteamID steamIDGroup); + virtual void GetGameplayStats(); + virtual SteamAPICall_t GetServerReputation(); + virtual uint32 GetPublicIP(); + virtual bool HandleIncomingPacket(const void *pData, int cbData, uint32 srcIP, uint16 srcPort); + virtual int GetNextOutgoingPacket(void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort); + virtual void EnableHeartbeats(bool bActive); + virtual void SetHeartbeatInterval(int iHeartbeatInterval); + virtual void ForceHeartbeat(); + virtual SteamAPICall_t AssociateWithClan(CSteamID steamIDClan); + virtual SteamAPICall_t ComputeNewPlayerCompatibility(CSteamID steamIDNewPlayer); +}; + +class CSteamCallbackRecordingWrapper : public CCallbackBase +{ +public: + CSteamCallbackRecordingWrapper(CRecordingEngExtInterceptor* recorder, CCallbackBase* cb, int id); + virtual void Run(void *pvParam); + virtual void Run(void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall); + virtual int GetCallbackSizeBytes(); + + int getRehldsCallbackId() { return m_Id; } + +protected: + CRecordingEngExtInterceptor* m_Recorder; + CCallbackBase* m_Wrapped; + int m_Id; + int m_Size; +}; + +class CRecordingEngExtInterceptor : public IReHLDSPlatform { + friend class CSteamAppsRecordingWrapper; + friend class CSteamGameServerRecordingWrapper; + +private: + std::ofstream m_OutStream; + + SOCKET m_ServerSocket; + + int m_SteamCallbacksCounter; + std::unordered_map m_SteamCallbacks; + CSteamAppsRecordingWrapper* m_SteamAppsWrapper; + + CSteamCallbackRecordingWrapper* getOrCreateCallbackWrapper(CCallbackBase *pCallback); + + CSteamGameServerRecordingWrapper* m_GameServerWrapper; + void* m_SteamBreakpadContext; + + CRecorderFuncCall* m_RootFunc; + CRecorderFuncCall* m_LastFunc; + + void writeCall(bool start, bool end, IEngExtCall* fcall); + IReHLDSPlatform* m_BasePlatform; + +public: + CRecordingEngExtInterceptor(const char* fname, IReHLDSPlatform* basePlatform); + void PushFunc(CRecorderFuncCall* func); + void PopFunc(CRecorderFuncCall* func); + + virtual uint32_t time(uint32_t* pTime); + virtual struct tm* localtime(uint32_t time); + virtual void srand(uint32_t seed); + virtual int rand(); + + virtual void Sleep(DWORD msec); + virtual BOOL QueryPerfCounter(LARGE_INTEGER* counter); + virtual BOOL QueryPerfFreq(LARGE_INTEGER* freq); + virtual DWORD GetTickCount(); + virtual void GetLocalTime(LPSYSTEMTIME time); + virtual void GetSystemTime(LPSYSTEMTIME time); + virtual void GetTimeZoneInfo(LPTIME_ZONE_INFORMATION zinfo); + virtual BOOL GetProcessTimes(HANDLE hProcess, LPFILETIME lpCreationTime, LPFILETIME lpExitTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime); + virtual void GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); + + virtual SOCKET socket(int af, int type, int protocol); + virtual int ioctlsocket(SOCKET s, long cmd, u_long *argp); + virtual int setsockopt(SOCKET s, int level, int optname, const char* optval, int optlen); + virtual int closesocket(SOCKET s); + virtual int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, socklen_t *fromlen); + virtual int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen); + virtual int bind(SOCKET s, const struct sockaddr* addr, int namelen); + virtual int getsockname(SOCKET s, struct sockaddr* name, socklen_t* namelen); + virtual int WSAGetLastError(); + virtual struct hostent* gethostbyname(const char *name); + virtual int gethostname(char *name, int namelen); + + virtual void SteamAPI_SetBreakpadAppID(uint32 unAppID); + virtual void SteamAPI_UseBreakpadCrashHandler(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback); + virtual void SteamAPI_RegisterCallback(CCallbackBase *pCallback, int iCallback); + virtual bool SteamAPI_Init(); + virtual void SteamAPI_UnregisterCallResult(class CCallbackBase *pCallback, SteamAPICall_t hAPICall); + virtual ISteamApps* SteamApps(); + virtual bool SteamGameServer_Init(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString); + virtual ISteamGameServer* SteamGameServer(); + virtual void SteamGameServer_RunCallbacks(); + virtual void SteamAPI_RunCallbacks(); + virtual void SteamGameServer_Shutdown(); + virtual void SteamAPI_UnregisterCallback(CCallbackBase *pCallback); +}; +#endif //_WIN32 \ No newline at end of file diff --git a/rehlds/testsuite/testsuite.cpp b/rehlds/testsuite/testsuite.cpp new file mode 100644 index 0000000..23fe254 --- /dev/null +++ b/rehlds/testsuite/testsuite.cpp @@ -0,0 +1,529 @@ +#include "precompiled.h" + + +/* ============================================================================ + external function hooks + ============================================================================*/ +uint32_t __cdecl time_hooked(uint32_t* pTime) +{ + return CRehldsPlatformHolder::get()->time(pTime); +} + +struct tm* __cdecl localtime_hooked(uint32_t* pTime) +{ + if (pTime == NULL) + rehlds_syserror("%s: pTime is NULL", __FUNCTION__); + + return CRehldsPlatformHolder::get()->localtime(*pTime); +} + +void __cdecl srand_hooked(uint32_t seed) +{ + CRehldsPlatformHolder::get()->srand(seed); +} + +int __cdecl rand_hooked() +{ + return CRehldsPlatformHolder::get()->rand(); +} + +void WINAPI Sleep_hooked(DWORD msec) +{ + CRehldsPlatformHolder::get()->Sleep(msec); +} + +BOOL WINAPI QueryPerfCounter_hooked(LARGE_INTEGER* counter) +{ + return CRehldsPlatformHolder::get()->QueryPerfCounter(counter); +} + +BOOL WINAPI QueryPerfFreq_hooked(LARGE_INTEGER* freq) +{ + return CRehldsPlatformHolder::get()->QueryPerfFreq(freq); +} + +DWORD WINAPI GetTickCount_hooked() +{ + return CRehldsPlatformHolder::get()->GetTickCount(); +} + +void WINAPI GetLocalTime_hooked(LPSYSTEMTIME time) +{ + CRehldsPlatformHolder::get()->GetLocalTime(time); +} + +void WINAPI GetSystemTime_hooked(LPSYSTEMTIME time) +{ + CRehldsPlatformHolder::get()->GetSystemTime(time); +} + +void WINAPI GetTimeZoneInfo_hooked(LPTIME_ZONE_INFORMATION tzinfo) +{ + CRehldsPlatformHolder::get()->GetTimeZoneInfo(tzinfo); +} + +SOCKET __stdcall socket_hooked(int af, int type, int protocol) +{ + return CRehldsPlatformHolder::get()->socket(af, type, protocol); +} + +int __stdcall ioctlsocket_hooked(SOCKET s, long cmd, u_long *argp) +{ + return CRehldsPlatformHolder::get()->ioctlsocket(s, cmd, argp); +} + +int __stdcall setsockopt_hooked(SOCKET s, int level, int optname, const char* optval, int optlen) +{ + return CRehldsPlatformHolder::get()->setsockopt(s, level, optname, optval, optlen); +} + +int __stdcall closesocket_hooked(SOCKET s) +{ + return CRehldsPlatformHolder::get()->closesocket(s); +} + +int __stdcall recvfrom_hooked(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int *fromlen) +{ + return CRehldsPlatformHolder::get()->recvfrom(s, buf, len, flags, from, fromlen); +} + +int __stdcall sendto_hooked(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) +{ + return CRehldsPlatformHolder::get()->sendto(s, buf, len, flags, to, tolen); +} + +int __stdcall bind_hooked(SOCKET s, const struct sockaddr* addr, int namelen) +{ + return CRehldsPlatformHolder::get()->bind(s, addr, namelen); +} + +int __stdcall getsockname_hooked(SOCKET s, struct sockaddr* name, int* namelen) +{ + return CRehldsPlatformHolder::get()->getsockname(s, name, namelen); +} + +int __stdcall WSAGetLastError_hooked() +{ + return CRehldsPlatformHolder::get()->WSAGetLastError(); +} + +struct hostent* __stdcall gethostbyname_hooked(const char *name) +{ + return CRehldsPlatformHolder::get()->gethostbyname(name); +} + +int __stdcall gethostname_hooked(char *name, int namelen) +{ + return CRehldsPlatformHolder::get()->gethostname(name, namelen); +} + +void __cdecl SteamAPI_SetMiniDumpComment_hooked(const char *pchMsg) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void __cdecl SteamAPI_WriteMiniDump_hooked(uint32 uStructuredExceptionCode, void* pvExceptionInfo, uint32 uBuildID) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void __cdecl SteamAPI_RegisterCallback_hooked(class CCallbackBase *pCallback, int iCallback) +{ + return CRehldsPlatformHolder::get()->SteamAPI_RegisterCallback(pCallback, iCallback); +} + +void __cdecl SteamAPI_RunCallbacks_hooked() +{ + CRehldsPlatformHolder::get()->SteamAPI_RunCallbacks(); +} + +bool __cdecl SteamAPI_Init_hooked() +{ + return CRehldsPlatformHolder::get()->SteamAPI_Init(); +} + +ISteamUser* __cdecl SteamUser_hooked() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return NULL; +} + +ISteamFriends* __cdecl SteamFriends_hooked() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return NULL; +} + +void __cdecl SteamGameServer_RunCallbacks_hooked() +{ + CRehldsPlatformHolder::get()->SteamGameServer_RunCallbacks(); +} + +void __cdecl SteamAPI_Shutdown_hooked() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +void __cdecl SteamGameServer_Shutdown_hooked() +{ + CRehldsPlatformHolder::get()->SteamGameServer_Shutdown(); +} + +bool __cdecl SteamGameServer_Init_hooked(uint32 unIP, uint16 usSteamPort, uint16 usGamePort, uint16 usQueryPort, EServerMode eServerMode, const char *pchVersionString) +{ + return CRehldsPlatformHolder::get()->SteamGameServer_Init(unIP, usSteamPort, usGamePort, usQueryPort, eServerMode, pchVersionString); +} + +void __cdecl SteamAPI_UnregisterCallback_hooked(class CCallbackBase *pCallback) +{ + CRehldsPlatformHolder::get()->SteamAPI_UnregisterCallback(pCallback); +} + +ISteamGameServer* __cdecl SteamGameServer_hooked() +{ + return CRehldsPlatformHolder::get()->SteamGameServer(); +} + +void __cdecl SteamAPI_SetBreakpadAppID_hooked(uint32 unAppID) +{ + CRehldsPlatformHolder::get()->SteamAPI_SetBreakpadAppID(unAppID); +} + +void __cdecl SteamAPI_RegisterCallResult_hooked(class CCallbackBase *pCallback, SteamAPICall_t hAPICall) +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); +} + +ISteamHTTP* __cdecl SteamHTTP_hooked() +{ + rehlds_syserror("%s: not implemented", __FUNCTION__); + return NULL; +} + +void __cdecl SteamAPI_UnregisterCallResult_hooked(class CCallbackBase *pCallback, SteamAPICall_t hAPICall) +{ + CRehldsPlatformHolder::get()->SteamAPI_UnregisterCallResult(pCallback, hAPICall); +} + +ISteamApps* __cdecl SteamApps_hooked() +{ + return CRehldsPlatformHolder::get()->SteamApps(); +} + +void __cdecl SteamAPI_UseBreakpadCrashHandler_hooked(char const *pchVersion, char const *pchDate, char const *pchTime, bool bFullMemoryDumps, void *pvContext, PFNPreMinidumpCallback m_pfnPreMinidumpCallback) +{ + CRehldsPlatformHolder::get()->SteamAPI_UseBreakpadCrashHandler(pchVersion, pchDate, pchTime, bFullMemoryDumps, pvContext, m_pfnPreMinidumpCallback); +} + +/* ============================================================================ + Hooks installation + ============================================================================*/ +HMODULE getModuleHandleOrDie(const char* moduleName) { + HMODULE res = GetModuleHandleA(moduleName); + if (res == NULL) { + rehlds_syserror("getModuleHandleOrDie(): module not found: '%s'", moduleName); + } + + return res; +} + +void* getProcAddressOrDie(HMODULE hModule, const char* procName) { + void* res = GetProcAddress(hModule, procName); + if (res == NULL) { + rehlds_syserror("getProcAddressOrDie(): procedure not found: '%s'", procName); + } + + return res; +} + +void InstallImportTableHook(PIMAGE_THUNK_DATA thunk, void* func) +{ + DWORD oldProtect; + VirtualProtect(thunk, 4, PAGE_READWRITE, &oldProtect); + thunk->u1.Function = (DWORD)func; +} + +void TestSuite_InstallHooks(const Module* engine) { + HMODULE hKernel32 = getModuleHandleOrDie("kernel32.dll"); + HMODULE hWinSock32 = getModuleHandleOrDie("wsock32.dll"); + HMODULE hSteamApi = getModuleHandleOrDie("steam_api.dll"); + + + void* QueryPerfCounter_addr = getProcAddressOrDie(hKernel32, "QueryPerformanceCounter"); + void* QueryPerfFreq_addr = getProcAddressOrDie(hKernel32, "QueryPerformanceFrequency"); + void* Sleep_addr = getProcAddressOrDie(hKernel32, "Sleep"); + void* GetTickCount_addr = getProcAddressOrDie(hKernel32, "GetTickCount"); + void* GetLocalTime_addr = getProcAddressOrDie(hKernel32, "GetLocalTime"); + void* GetSystemTime_addr = getProcAddressOrDie(hKernel32, "GetSystemTime"); + void* GetTimeZoneInformation_addr = getProcAddressOrDie(hKernel32, "GetTimeZoneInformation"); + + void* socket_addr = getProcAddressOrDie(hWinSock32, "socket"); + void* ioctlsocket_addr = getProcAddressOrDie(hWinSock32, "ioctlsocket"); + void* setsockopt_addr = getProcAddressOrDie(hWinSock32, "setsockopt"); + void* closesocket_addr = getProcAddressOrDie(hWinSock32, "closesocket"); + void* recvfrom_addr = getProcAddressOrDie(hWinSock32, "recvfrom"); + void* sendto_addr = getProcAddressOrDie(hWinSock32, "sendto"); + void* bind_addr = getProcAddressOrDie(hWinSock32, "bind"); + void* getsockname_addr = getProcAddressOrDie(hWinSock32, "getsockname"); + void* gethostname_addr = getProcAddressOrDie(hWinSock32, "gethostname"); + void* gethostbyname_addr = getProcAddressOrDie(hWinSock32, "gethostbyname"); + void* WSAGetLastError_addr = getProcAddressOrDie(hWinSock32, "WSAGetLastError"); + + void* SteamAPI_SetMiniDumpComment_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_SetMiniDumpComment"); + void* SteamAPI_WriteMiniDump_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_WriteMiniDump"); + void* SteamAPI_RegisterCallback_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_RegisterCallback"); + void* SteamAPI_RunCallbacks_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_RunCallbacks"); + void* SteamAPI_Init_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_Init"); + void* SteamUser_addr = getProcAddressOrDie(hSteamApi, "SteamUser"); + void* SteamFriends_addr = getProcAddressOrDie(hSteamApi, "SteamFriends"); + void* SteamGameServer_RunCallbacks_addr = getProcAddressOrDie(hSteamApi, "SteamGameServer_RunCallbacks"); + void* SteamAPI_Shutdown_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_Shutdown"); + void* SteamGameServer_Shutdown_addr = getProcAddressOrDie(hSteamApi, "SteamGameServer_Shutdown"); + void* SteamGameServer_Init_addr = getProcAddressOrDie(hSteamApi, "SteamGameServer_Init"); + void* SteamAPI_UnregisterCallback_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_UnregisterCallback"); + void* SteamGameServer_addr = getProcAddressOrDie(hSteamApi, "SteamGameServer"); + void* SteamAPI_SetBreakpadAppID_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_SetBreakpadAppID"); + void* SteamAPI_RegisterCallResult_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_RegisterCallResult"); + void* SteamHTTP_addr = getProcAddressOrDie(hSteamApi, "SteamHTTP"); + void* SteamAPI_UnregisterCallResult_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_UnregisterCallResult"); + void* SteamApps_addr = getProcAddressOrDie(hSteamApi, "SteamApps"); + void* SteamAPI_UseBreakpadCrashHandler_addr = getProcAddressOrDie(hSteamApi, "SteamAPI_UseBreakpadCrashHandler"); + + + PIMAGE_DOS_HEADER peHeader = (PIMAGE_DOS_HEADER)engine->base; + PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)(engine->base + peHeader->e_lfanew); + + PIMAGE_IMPORT_DESCRIPTOR impDesc = (PIMAGE_IMPORT_DESCRIPTOR)(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + engine->base); + for (; impDesc->Name; impDesc++) + { + const char* libName = (const char*)(engine->base + impDesc->Name); + bool isKernel32 = !_stricmp("kernel32.dll", libName); + bool isWSock32 = !_stricmp("wsock32.dll", libName); + bool isSteamApi = !_stricmp("steam_api.dll", libName); + + PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(engine->base + impDesc->FirstThunk); + for (; thunk->u1.Function; ++thunk) + { + void* fptr = (void**)(thunk->u1.Function); + if (isKernel32) + { + if (fptr == Sleep_addr) + { + InstallImportTableHook(thunk, &Sleep_hooked); + } + else if (fptr == QueryPerfCounter_addr) + { + InstallImportTableHook(thunk, &QueryPerfCounter_hooked); + } + else if (fptr == QueryPerfFreq_addr) + { + InstallImportTableHook(thunk, &QueryPerfFreq_hooked); + } + else if (fptr == GetTickCount_addr) + { + InstallImportTableHook(thunk, &GetTickCount_hooked); + } + else if (fptr == GetLocalTime_addr) + { + InstallImportTableHook(thunk, &GetLocalTime_hooked); + } + else if (fptr == GetSystemTime_addr) + { + InstallImportTableHook(thunk, &GetSystemTime_hooked); + } + else if (fptr == GetTimeZoneInformation_addr) + { + InstallImportTableHook(thunk, &GetTimeZoneInfo_hooked); + } + } + else if (isWSock32) + { + if (fptr == socket_addr) + { + InstallImportTableHook(thunk, &socket_hooked); + } + else if (fptr == ioctlsocket_addr) { + InstallImportTableHook(thunk, &ioctlsocket_hooked); + } + else if (fptr == setsockopt_addr) { + InstallImportTableHook(thunk, &setsockopt_hooked); + } + else if (fptr == closesocket_addr) { + InstallImportTableHook(thunk, &closesocket_hooked); + } + else if (fptr == recvfrom_addr) { + InstallImportTableHook(thunk, &recvfrom_hooked); + } + else if (fptr == sendto_addr) { + InstallImportTableHook(thunk, &sendto_hooked); + } + else if (fptr == bind_addr) { + InstallImportTableHook(thunk, &bind_hooked); + } + else if (fptr == getsockname_addr) { + InstallImportTableHook(thunk, &getsockname_hooked); + } + else if (fptr == WSAGetLastError_addr) { + InstallImportTableHook(thunk, &WSAGetLastError_hooked); + } + else if (fptr == gethostbyname_addr) { + InstallImportTableHook(thunk, &gethostbyname_hooked); + } + else if (fptr == gethostname_addr) { + InstallImportTableHook(thunk, &gethostname_hooked); + } + } + else if (isSteamApi) + { + if (fptr == SteamAPI_SetMiniDumpComment_addr) + { + InstallImportTableHook(thunk, &SteamAPI_SetMiniDumpComment_hooked); + } + else if (fptr == SteamAPI_WriteMiniDump_addr) + { + InstallImportTableHook(thunk, &SteamAPI_WriteMiniDump_hooked); + } + else if (fptr == SteamAPI_RegisterCallback_addr) + { + InstallImportTableHook(thunk, &SteamAPI_RegisterCallback_hooked); + } + else if (fptr == SteamAPI_RunCallbacks_addr) + { + InstallImportTableHook(thunk, &SteamAPI_RunCallbacks_hooked); + } + else if (fptr == SteamAPI_Init_addr) + { + InstallImportTableHook(thunk, &SteamAPI_Init_hooked); + } + else if (fptr == SteamUser_addr) + { + InstallImportTableHook(thunk, &SteamUser_hooked); + } + else if (fptr == SteamFriends_addr) + { + InstallImportTableHook(thunk, &SteamFriends_hooked); + } + else if (fptr == SteamGameServer_RunCallbacks_addr) + { + InstallImportTableHook(thunk, &SteamGameServer_RunCallbacks_hooked); + } + else if (fptr == SteamAPI_Shutdown_addr) + { + InstallImportTableHook(thunk, &SteamAPI_Shutdown_hooked); + } + else if (fptr == SteamGameServer_Shutdown_addr) + { + InstallImportTableHook(thunk, &SteamGameServer_Shutdown_hooked); + } + else if (fptr == SteamGameServer_Init_addr) + { + InstallImportTableHook(thunk, &SteamGameServer_Init_hooked); + } + else if (fptr == SteamAPI_UnregisterCallback_addr) + { + InstallImportTableHook(thunk, &SteamAPI_UnregisterCallback_hooked); + } + else if (fptr == SteamGameServer_addr) + { + InstallImportTableHook(thunk, &SteamGameServer_hooked); + } + else if (fptr == SteamAPI_SetBreakpadAppID_addr) + { + InstallImportTableHook(thunk, &SteamAPI_SetBreakpadAppID_hooked); + } + else if (fptr == SteamAPI_RegisterCallResult_addr) + { + InstallImportTableHook(thunk, &SteamAPI_RegisterCallResult_hooked); + } + else if (fptr == SteamHTTP_addr) + { + InstallImportTableHook(thunk, &SteamHTTP_hooked); + } + else if (fptr == SteamAPI_UnregisterCallResult_addr) + { + InstallImportTableHook(thunk, &SteamAPI_UnregisterCallResult_hooked); + } + else if (fptr == SteamApps_addr) + { + InstallImportTableHook(thunk, &SteamApps_hooked); + } + else if (fptr == SteamAPI_UseBreakpadCrashHandler_addr) + { + InstallImportTableHook(thunk, &SteamAPI_UseBreakpadCrashHandler_hooked); + } + } + } + } +} + +void TestSuite_InstallCStdHooks(const AddressRef* funcRefs) { + const AddressRef* curFunc = funcRefs; + FunctionHook fhook; + while (curFunc->symbolName) + { + if (!strcmp("time", curFunc->symbolName)) { + fhook.originalAddress = curFunc->originalAddress; + fhook.handlerFunc = (size_t) &time_hooked; + HookFunction(NULL, &fhook); + } + else if (!strcmp("localtime", curFunc->symbolName)) { + fhook.originalAddress = curFunc->originalAddress; + fhook.handlerFunc = (size_t)&localtime_hooked; + HookFunction(NULL, &fhook); + } + else if (!strcmp("srand", curFunc->symbolName)) { + fhook.originalAddress = curFunc->originalAddress; + fhook.handlerFunc = (size_t)&srand_hooked; + HookFunction(NULL, &fhook); + } + else if (!strcmp("rand", curFunc->symbolName)) { + fhook.originalAddress = curFunc->originalAddress; + fhook.handlerFunc = (size_t)&rand_hooked; + HookFunction(NULL, &fhook); + } + curFunc++; + } +} + +void TestSuite_InitAnonymizer(CAnonymizingEngExtInterceptor& a) { + +} + +void TestSuite_Init(const Module* engine, const Module* executable, const AddressRef* funcRefs) { + bool needInstallImportTableHooks = false; + + if (g_RehldsRuntimeConfig.testPlayerMode == TPM_RECORD) + { + CRehldsPlatformHolder::set(new CRecordingEngExtInterceptor(g_RehldsRuntimeConfig.testRecordingFileName, CRehldsPlatformHolder::get())); + needInstallImportTableHooks = true; + } + else if (g_RehldsRuntimeConfig.testPlayerMode == TPM_PLAY) + { + CRehldsPlatformHolder::set(new CPlayingEngExtInterceptor(g_RehldsRuntimeConfig.testRecordingFileName, true)); + needInstallImportTableHooks = true; + } + else if (g_RehldsRuntimeConfig.testPlayerMode == TPM_ANONYMIZE) + { + char fname[260]; + sprintf(fname, "%s.new", g_RehldsRuntimeConfig.testRecordingFileName); + CRehldsPlatformHolder::set(new CPlayingEngExtInterceptor(g_RehldsRuntimeConfig.testRecordingFileName, false)); + auto anonymizer = new CAnonymizingEngExtInterceptor(CRehldsPlatformHolder::get()); + CRehldsPlatformHolder::set(anonymizer); + CRehldsPlatformHolder::set(new CRecordingEngExtInterceptor(fname, CRehldsPlatformHolder::get())); + TestSuite_InitAnonymizer(*anonymizer); + needInstallImportTableHooks = true; + } + + if (needInstallImportTableHooks) { + if (engine != NULL) { + TestSuite_InstallHooks(engine); + } + + TestSuite_InstallHooks(executable); + + if (funcRefs != NULL) { + TestSuite_InstallCStdHooks(funcRefs); + } + } +} + diff --git a/rehlds/testsuite/testsuite.h b/rehlds/testsuite/testsuite.h new file mode 100644 index 0000000..c8db4c3 --- /dev/null +++ b/rehlds/testsuite/testsuite.h @@ -0,0 +1,18 @@ +#pragma once +#ifdef _WIN32 + +#include "osconfig.h" +#include "memory.h" +#include "rehlds/platform.h" + +#include +#include +#include +#include + +#define TESTSUITE_PROTOCOL_VERSION_MINOR 5 +#define TESTSUITE_PROTOCOL_VERSION_MAJOR 0 + +void TestSuite_Init(const Module* engine, const Module* executable, const AddressRef* funcRefs); + +#endif \ No newline at end of file diff --git a/rehlds/unittests/TestRunner.cpp b/rehlds/unittests/TestRunner.cpp new file mode 100644 index 0000000..a5b2045 --- /dev/null +++ b/rehlds/unittests/TestRunner.cpp @@ -0,0 +1,15 @@ +#include "precompiled.h" +#include "cppunitlite/GradleAdapter.h" + +int main(int argc, char* argv[]) { + printf("TestRunner: main()\n"); + + GradleAdapter a; + int res = a.testsEntryPoint(argc, argv); + +#ifdef _BUILD_FROM_IDE + system("PAUSE"); +#endif + + return res; +} diff --git a/rehlds/unittests/common_tests.cpp b/rehlds/unittests/common_tests.cpp new file mode 100644 index 0000000..94db0d7 --- /dev/null +++ b/rehlds/unittests/common_tests.cpp @@ -0,0 +1,89 @@ +#include "precompiled.h" +#include "cppunitlite/TestHarness.h" + +TEST(BitsWritingReading, MSG, 5000) +{ + // TODO: Move to apropriate Init function + int size = 4 * 1024 * 1024; + Memory_Init(new char[size], size); + SZ_Alloc("net_message", &net_message, 1024); + + sizebuf_t *buf = &net_message; + + uint32_t ff1 = ((uint32_t)1 << 31) - 1; + uint32_t ff2 = ((uint32_t)1 << 9) - 1; + + SZ_Clear(buf); + + MSG_StartBitWriting(buf); + MSG_WriteBits(ff1, 31); + MSG_WriteBits(ff2, 9); + MSG_EndBitWriting(buf); + + MSG_BeginReading(); + + MSG_StartBitReading(buf); + uint32_t t1 = MSG_ReadBits(31); + uint32_t t2 = MSG_ReadBits(9); + MSG_EndBitReading(buf); + + UINT32_EQUALS("31/9 Read failed (31)", ff1, t1); + UINT32_EQUALS("31/9 Read failed (9)", ff2, t2); + + + SZ_Clear(buf); + + MSG_StartBitWriting(buf); + MSG_WriteBits(ff2, 9); + MSG_WriteBits(ff1, 31); + MSG_EndBitWriting(buf); + + MSG_BeginReading(); + + MSG_StartBitReading(buf); + t2 = MSG_ReadBits(9); + t1 = MSG_ReadBits(31); + MSG_EndBitReading(buf); + + UINT32_EQUALS("9/31 Read failed (9)", ff1, t1); + UINT32_EQUALS("9/31 Read failed (31)", ff2, t2); + + + uint32_t a2, a1 = 5; + uint32_t b2, b1 = 0xEFEF; + uint32_t c2, c1 = 0x7AAEAEAE; + + SZ_Clear(buf); + + MSG_StartBitWriting(buf); + MSG_WriteBits(c1, 31); + MSG_EndBitWriting(buf); + + MSG_BeginReading(); + + MSG_StartBitReading(buf); + c2 = MSG_ReadBits(31); + MSG_EndBitReading(buf); + + UINT32_EQUALS("31 Read failed", c1, c2); + + SZ_Clear(buf); + + MSG_StartBitWriting(buf); + MSG_WriteBits(a1, 7); + MSG_WriteBits(b1, 16); + MSG_WriteBits(c1, 31); + MSG_EndBitWriting(buf); + + MSG_BeginReading(); + + MSG_StartBitReading(buf); + a2 = MSG_ReadBits(7); + b2 = MSG_ReadBits(16); + c2 = MSG_ReadBits(31); + MSG_EndBitReading(buf); + + UINT32_EQUALS("7/16/31 Read failed", a1, a2); + UINT32_EQUALS("7/16/31 Read failed", b1, b2); + UINT32_EQUALS("7/16/31 Read failed", c1, c2); +} diff --git a/rehlds/unittests/struct_offsets_tests.cpp b/rehlds/unittests/struct_offsets_tests.cpp new file mode 100644 index 0000000..3bb81fb --- /dev/null +++ b/rehlds/unittests/struct_offsets_tests.cpp @@ -0,0 +1,43 @@ +#include "precompiled.h" +#include "cppunitlite/TestHarness.h" + +#pragma warning(push) +#ifndef _WIN32 +#pragma warning(disable : 1875) // warning #1875: offsetof applied to non-POD (Plain Old Data) types is nonstandard +#endif // _WIN32 + +#define CHECK_STRUCT_SIZE(s,win_size,lin_size) {\ + int needOff = __isWindows ? win_size : lin_size; \ + UINT32_EQUALS("Bad size "#s"::", needOff, sizeof(s)); \ +} + +#define CHECK_STRUCT_OFFSET(s,f,win_off,lin_off) {\ + int needOff = __isWindows ? win_off : lin_off; \ + int realOff = offsetof(s, f); \ + UINT32_EQUALS("Bad offset "#s"::"#f, needOff, realOff); \ + } + +TEST(StructOffsets, ReversingChecks, 5000) +{ + CHECK_STRUCT_OFFSET(client_t, active, 0, 0); + CHECK_STRUCT_OFFSET(client_t, chokecount, 0x2540, 0x2430); + CHECK_STRUCT_OFFSET(client_t, datagram, 0x25C0, 0x24AC); + CHECK_STRUCT_OFFSET(client_t, m_VoiceStreams, 0x5000, 0x4EE0); + CHECK_STRUCT_OFFSET(client_t, m_lastvoicetime, 0x5008, 0x4EE8); + CHECK_STRUCT_OFFSET(client_t, datagram_buf, 0x25D4, 0x24C0); + CHECK_STRUCT_OFFSET(client_t, connection_started, 0x3578, 0x3460); + + //CHECK_STRUCT_SIZE(server_t, 0x46418, 0x4640C); + + printf("sizeof server_t: 0x%2X\n", sizeof(server_t)); + printf("sizeof CSteam3Server: 0x%2X\n", sizeof(CSteam3Server)); + printf("offsetof CSteam3Server::m_SteamIDGS: 0x%2X\n", offsetof(CSteam3Server, m_SteamIDGS)); + + CHECK_STRUCT_OFFSET(CSteam3, m_bLogOnResult, 5, 5); + CHECK_STRUCT_OFFSET(CSteam3Server, m_bLogOnResult, 5, 5); + + CHECK_STRUCT_OFFSET(CSteam3Server, m_bLanOnly, 0x86, 0x9E); + CHECK_STRUCT_OFFSET(CSteam3Server, m_SteamIDGS, 0x87, 0x9F); +} + +#pragma warning( pop ) diff --git a/rehlds/unittests/tmessage_tests.cpp b/rehlds/unittests/tmessage_tests.cpp new file mode 100644 index 0000000..b24ed64 --- /dev/null +++ b/rehlds/unittests/tmessage_tests.cpp @@ -0,0 +1,11 @@ +#include "precompiled.h" +#include "cppunitlite/TestHarness.h" + + +TEST(TrimSpace, TMessage, 5000) +{ + char res[32]; + TrimSpace(" asdf ", res); + + ZSTR_EQUAL("Trim failed", res, "asdf"); +} diff --git a/rehlds/version/appversion.vm b/rehlds/version/appversion.vm new file mode 100644 index 0000000..37e63ae --- /dev/null +++ b/rehlds/version/appversion.vm @@ -0,0 +1,20 @@ +#ifndef __APPVERSION_H__ +\#define __APPVERSION_H__ + +// +// This file is generated automatically. +// Don't edit it. +// + +// Version defines +\#define VERSION_MAJOR ${verInfo.majorVersion} +\#define VERSION_MINOR ${verInfo.minorVersion} + +\#define APP_VERSION_D ${verInfo.format('.', '-', true)} +\#define APP_VERSION_STRD "${verInfo.format('.', '-', true)}" + +#set ( $commitYMD = $_DateTimeFormat.forPattern('yyyy-MM-dd').print($verInfo.lastCommitDate) ) + +\#define APP_VERSION_YMD_STR "${commitYMD}" + +#endif //__APPVERSION_H__ diff --git a/rehlds/version/version.cpp b/rehlds/version/version.cpp new file mode 100644 index 0000000..c5a6b06 --- /dev/null +++ b/rehlds/version/version.cpp @@ -0,0 +1,10 @@ +/* +* Version declaration dependency file +* +*/ + +// +// This file needed just to add the dependency and appversion.h +// +#include "precompiled.h" + diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..9e17208 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,4 @@ +rootProject.name = 'rehlds' +include 'dep/cppunitlite' +include 'dep/bzip2' +include 'rehlds' diff --git a/shared.gradle b/shared.gradle new file mode 100644 index 0000000..b251219 --- /dev/null +++ b/shared.gradle @@ -0,0 +1,33 @@ +import org.doomedsociety.gradlecpp.cfg.BinaryKind +import org.doomedsociety.gradlecpp.toolchain.icc.Icc +import org.gradle.nativeplatform.NativeBinarySpec +import org.gradle.nativeplatform.NativeExecutableBinarySpec +import org.gradle.nativeplatform.SharedLibraryBinarySpec +import org.gradle.nativeplatform.StaticLibraryBinarySpec +import org.gradle.nativeplatform.toolchain.VisualCpp + +apply from: 'shared_msvc.gradle' +apply from: 'shared_icc.gradle' + +rootProject.ext.createToolchainConfig = { NativeBinarySpec bin -> + BinaryKind binaryKind + if (bin instanceof NativeExecutableBinarySpec) { + binaryKind = BinaryKind.EXECUTABLE + } else if (bin instanceof SharedLibraryBinarySpec) { + binaryKind = BinaryKind.SHARED_LIBRARY + } else if (bin instanceof StaticLibraryBinarySpec) { + binaryKind = BinaryKind.STATIC_LIBRARY + } else { + throw new RuntimeException("Unknown executable kind ${bin.class.name}") + } + + boolean releaseBuild = bin.buildType.name.toLowerCase() == 'release' + + if (bin.toolChain instanceof VisualCpp) { + return rootProject.createMsvcConfig(releaseBuild, binaryKind) + } else if (bin.toolChain instanceof Icc) { + return rootProject.createIccConfig(releaseBuild, binaryKind) + } else { + throw new RuntimeException("Unknown native toolchain: ${bin.toolChain.class.name}") + } +} diff --git a/shared_icc.gradle b/shared_icc.gradle new file mode 100644 index 0000000..9dbd1f1 --- /dev/null +++ b/shared_icc.gradle @@ -0,0 +1,60 @@ +import org.doomedsociety.gradlecpp.cfg.BinaryKind +import org.doomedsociety.gradlecpp.gcc.GccToolchainConfig +import org.doomedsociety.gradlecpp.gcc.OptimizationLevel + +rootProject.ext.createIccConfig = { boolean release, BinaryKind binKind -> + GccToolchainConfig cfg + if (release) { + cfg = new GccToolchainConfig( + compilerOptions: new GccToolchainConfig.CompilerOptions( + optimizationLevel: OptimizationLevel.LEVEL_3, + stackProtector: false, + interProceduralOptimizations: true, + + noBuiltIn: true, + + intelExtensions: false, + asmBlocks: true, + + positionIndependentCode: false + ), + + linkerOptions: new GccToolchainConfig.LinkerOptions( + interProceduralOptimizations: true, + stripSymbolTable: true, + staticLibGcc: true, + staticIntel: true, + ), + + librarianOptions: new GccToolchainConfig.LibrarianOptions( + + ) + ) + } else { + //debug + cfg = new GccToolchainConfig( + compilerOptions: new GccToolchainConfig.CompilerOptions( + optimizationLevel: OptimizationLevel.DISABLE, + stackProtector: true, + interProceduralOptimizations: false, + + noBuiltIn: true, + intelExtensions: false, + asmBlocks: true + ), + + linkerOptions: new GccToolchainConfig.LinkerOptions( + interProceduralOptimizations: false, + stripSymbolTable: false, + staticLibGcc: true, + staticIntel: true, + ), + + librarianOptions: new GccToolchainConfig.LibrarianOptions( + + ) + ) + } + + return cfg +} diff --git a/shared_msvc.gradle b/shared_msvc.gradle new file mode 100644 index 0000000..5b69f4c --- /dev/null +++ b/shared_msvc.gradle @@ -0,0 +1,123 @@ +import org.doomedsociety.gradlecpp.cfg.BinaryKind +import org.doomedsociety.gradlecpp.msvc.CallingConvention +import org.doomedsociety.gradlecpp.msvc.CodeGenerationKind +import org.doomedsociety.gradlecpp.msvc.CppExceptions +import org.doomedsociety.gradlecpp.msvc.DebugInfoFormat +import org.doomedsociety.gradlecpp.msvc.EnhancedInstructionsSet +import org.doomedsociety.gradlecpp.msvc.ErrorReporting +import org.doomedsociety.gradlecpp.msvc.FloatingPointModel +import org.doomedsociety.gradlecpp.msvc.LinkTimeCodeGenKind +import org.doomedsociety.gradlecpp.msvc.MsvcToolchainConfig +import org.doomedsociety.gradlecpp.msvc.OptimizationLevel +import org.doomedsociety.gradlecpp.msvc.RuntimeChecks +import org.doomedsociety.gradlecpp.msvc.WarningLevel + +rootProject.ext.createMsvcConfig = { boolean release, BinaryKind binKind -> + MsvcToolchainConfig cfg + if (release) { + cfg = new MsvcToolchainConfig( + compilerOptions: new MsvcToolchainConfig.CompilerOptions( + codeGeneration: CodeGenerationKind.MULTITHREADED, + optimizationLevel: OptimizationLevel.FULL_OPTIMIZATION, + debugInfoFormat: DebugInfoFormat.PROGRAM_DATABASE, + runtimeChecks: RuntimeChecks.DEFAULT, + cppExceptions: CppExceptions.ENABLED_WITH_SEH, + warningLevel: WarningLevel.LEVEL_3, + callingConvention: CallingConvention.CDECL, + enhancedInstructionsSet: EnhancedInstructionsSet.SSE2, + floatingPointModel: FloatingPointModel.FAST, + + enableMinimalRebuild: false, + omitFramePointers: false, + wholeProgramOptimization: true, + enabledFunctionLevelLinking: true, + enableSecurityCheck: true, + analyzeCode: false, + sdlChecks: false, + treatWarningsAsErrors: false, + treatWchartAsBuiltin: true, + forceConformanceInForLoopScope: true, + + extraDefines: [ + 'WIN32': null, + '_MBCS': null, + 'NDEBUG': null, + ] + ), + + linkerOptions: new MsvcToolchainConfig.LinkerOptions( + linkTimeCodeGenKind: LinkTimeCodeGenKind.USE_LTCG, + errorReportingMode: ErrorReporting.NO_ERROR_REPORT, + + enableIncrementalLinking: false, + eliminateUnusedRefs: true, + enableCOMDATFolding: true, + generateDebugInfo: true, + dataExecutionPrevention: true, + randomizedBaseAddress: true + ), + + librarianOptions: new MsvcToolchainConfig.LibrarianOptions( + linkTimeCodeGenKind: LinkTimeCodeGenKind.USE_LTCG + ), + + generatePdb: true + ) + } else { + //debug + cfg = new MsvcToolchainConfig( + compilerOptions: new MsvcToolchainConfig.CompilerOptions( + codeGeneration: CodeGenerationKind.MULTITHREADED_DEBUG, + optimizationLevel: OptimizationLevel.DISABLED, + debugInfoFormat: DebugInfoFormat.PROGRAM_DATABASE, + runtimeChecks: RuntimeChecks.DEFAULT, + cppExceptions: CppExceptions.ENABLED_WITH_SEH, + warningLevel: WarningLevel.LEVEL_3, + callingConvention: CallingConvention.CDECL, + enhancedInstructionsSet: EnhancedInstructionsSet.SSE2, + floatingPointModel: FloatingPointModel.FAST, + + enableMinimalRebuild: true, + omitFramePointers: false, + wholeProgramOptimization: false, + enabledFunctionLevelLinking: true, + enableSecurityCheck: true, + analyzeCode: false, + sdlChecks: false, + treatWarningsAsErrors: false, + treatWchartAsBuiltin: true, + forceConformanceInForLoopScope: true, + + extraDefines: [ + 'WIN32': null, + '_MBCS': null, + '_DEBUG': null, + ] + ), + + linkerOptions: new MsvcToolchainConfig.LinkerOptions( + linkTimeCodeGenKind: LinkTimeCodeGenKind.DEFAULT, + errorReportingMode: ErrorReporting.NO_ERROR_REPORT, + + enableIncrementalLinking: true, + eliminateUnusedRefs: false, + enableCOMDATFolding: false, + generateDebugInfo: true, + dataExecutionPrevention: true, + randomizedBaseAddress: true + ), + + librarianOptions: new MsvcToolchainConfig.LibrarianOptions( + linkTimeCodeGenKind: LinkTimeCodeGenKind.USE_LTCG + ), + + generatePdb: true + ) + + if (binKind == BinaryKind.STATIC_LIBRARY) { + cfg.compilerConfig.extraDefines['_LIB'] = null + } + } + + return cfg +} \ No newline at end of file