mirror of
https://github.com/XLabsProject/s1x-client.git
synced 2023-08-02 15:02:12 +02:00
commit
86ee38de19
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discord Server
|
||||
url: https://discord.gg/sKeVmR3/
|
||||
about: Please ask and answer support questions here.
|
||||
- name: XLabsProject Website
|
||||
url: https://xlabs.dev/
|
||||
about: The official website.
|
29
.github/ISSUE_TEMPLATE/get-help.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/get-help.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Get help
|
||||
about: Get help using S1x
|
||||
title: ''
|
||||
labels: discussion
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
_Do not open an issue here if you need help with modding or have a problem getting the client to run.
|
||||
It is very likely your problem will be resolved by reading the [FAQ](https://xlabs.dev/s1x_faq) carefully.
|
||||
Ask in `s1x-support` or `s1x-modding` channels on the [Discord](https://discord.gg/sKeVmR3) server if you still have problems.
|
||||
Before opening a new issue, please see [Issues](https://github.com/XLabsProject/s1x-client/issues) and check that a similar issue does not already exist
|
||||
If this does not apply, please continue by filling in the template below._
|
||||
|
||||
**What are you trying to do?**
|
||||
A short, concise description of the outcome you are trying to achieve.
|
||||
|
||||
**What problem are you having?**
|
||||
A clear and concise description of the problem that is blocking you from your desired outcome, ex. "S1x is crashing with this error message: ..."
|
||||
If S1x is crashing, include the minidump file and the crash address in text form. Screenshots showing the message box with the crash address are not acceptable.
|
||||
|
||||
**What version of S1x are you using?**
|
||||
Please make sure you are up to date with the latest build from the master branch.
|
||||
You should be using the official XLabs Launcher.
|
||||
You should *not* be using any custom builds of the game made for "trickshotting"
|
||||
|
||||
**Anything else we should know?**
|
||||
Add any other context about the problem here.
|
27
.github/ISSUE_TEMPLATE/request-a-feature.md
vendored
Normal file
27
.github/ISSUE_TEMPLATE/request-a-feature.md
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
---
|
||||
name: Request a feature
|
||||
about: Suggest a new feature or enhancement
|
||||
title: ''
|
||||
labels: feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
_Before opening a new feature request, please see [Issues](https://github.com/XLabsProject/s1x-client/issues) and check that a similar issue does not already exist.
|
||||
If this a new request, help us help you by filling in the template below.
|
||||
S1x is not in active development right now. Please keep in mind that if there is not a clear positive impact on the gameplay to be gained by this feature request, it may be closed at the maintainers' discretion._
|
||||
|
||||
**What problem will this solve?**
|
||||
A clear and concise description of the problem this new feature is meant to solve, ex. "There is something wrong with the game" or "There is something wrong with S1x's source code".
|
||||
Please limit your request to a single feature; create multiple feature requests instead.
|
||||
|
||||
**What might be a solution?**
|
||||
A clear and concise description of what you want to happen. If you are proposing changes to S1x's source code, tell us which component you want to be changed.
|
||||
If you propose changes to the game, you may use images or videos to illustrate what aspect of the game should be changed.
|
||||
|
||||
**What other alternatives have you already considered?**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
It may help others to find workarounds until the problem is resolved.
|
||||
|
||||
**Anything else we should know?**
|
||||
Add any other context or screenshots about the feature request here.
|
20
.github/workflows/build.yml
vendored
20
.github/workflows/build.yml
vendored
@ -8,6 +8,11 @@ on:
|
||||
branches:
|
||||
- "*"
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build binaries
|
||||
@ -18,14 +23,6 @@ jobs:
|
||||
- Debug
|
||||
- Release
|
||||
steps:
|
||||
- name: Wait for previous workflows
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
uses: softprops/turnstyle@v1
|
||||
with:
|
||||
poll-interval-seconds: 10
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Check out files
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@ -95,13 +92,6 @@ jobs:
|
||||
- name: Add known hosts
|
||||
run: ssh-keyscan -H ${{ secrets.XLABS_MASTER_SSH_ADDRESS }} >> ~/.ssh/known_hosts
|
||||
|
||||
- name: Wait for previous workflows
|
||||
uses: softprops/turnstyle@v1
|
||||
with:
|
||||
poll-interval-seconds: 10
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Remove old data files
|
||||
run: ssh ${{ secrets.XLABS_MASTER_SSH_USER }}@${{ secrets.XLABS_MASTER_SSH_ADDRESS }} rm -rf ${{ env.XLABS_MASTER_PATH }}/s1x/data/*
|
||||
|
||||
|
3548
data/maps/mp/gametypes/_gamelogic.gsc
Normal file
3548
data/maps/mp/gametypes/_gamelogic.gsc
Normal file
File diff suppressed because it is too large
Load Diff
@ -1211,10 +1211,6 @@ removeplayerondisconnect()
|
||||
|
||||
initclientdvarssplitscreenspecific()
|
||||
{
|
||||
if ( level.splitscreen || self issplitscreenplayer() )
|
||||
self setclientdvars( "cg_hudGrenadeIconHeight", "37.5", "cg_hudGrenadeIconWidth", "37.5", "cg_hudGrenadeIconOffset", "75", "cg_hudGrenadePointerHeight", "18", "cg_hudGrenadePointerWidth", "37.5", "cg_hudGrenadePointerPivot", "18 40.5", "cg_fovscale", "0.75" );
|
||||
else
|
||||
self setclientdvars( "cg_hudGrenadeIconHeight", "75", "cg_hudGrenadeIconWidth", "75", "cg_hudGrenadeIconOffset", "50", "cg_hudGrenadePointerHeight", "36", "cg_hudGrenadePointerWidth", "75", "cg_hudGrenadePointerPivot", "36 81", "cg_fovscale", "1" );
|
||||
}
|
||||
|
||||
initclientdvars()
|
||||
@ -1236,24 +1232,6 @@ initclientdvars()
|
||||
setdvar( "cg_drawFriendlyNamesAlways", 1 );
|
||||
else
|
||||
setdvar( "cg_drawFriendlyNamesAlways", 0 );
|
||||
|
||||
initclientdvarssplitscreenspecific();
|
||||
|
||||
if ( maps\mp\_utility::getgametypenumlives() )
|
||||
self setclientdvars( "cg_deadChatWithDead", 1, "cg_deadChatWithTeam", 0, "cg_deadHearTeamLiving", 0, "cg_deadHearAllLiving", 0 );
|
||||
else
|
||||
self setclientdvars( "cg_deadChatWithDead", 0, "cg_deadChatWithTeam", 1, "cg_deadHearTeamLiving", 1, "cg_deadHearAllLiving", 0 );
|
||||
|
||||
if ( level.teambased )
|
||||
self setclientdvars( "cg_everyonehearseveryone", 0 );
|
||||
|
||||
if ( getdvarint( "scr_hitloc_debug" ) )
|
||||
{
|
||||
for ( var_0 = 0; var_0 < 6; var_0++ )
|
||||
self setclientdvar( "ui_hitloc_" + var_0, "" );
|
||||
|
||||
self.hitlocinited = 1;
|
||||
}
|
||||
}
|
||||
|
||||
getlowestavailableclientid()
|
||||
@ -1573,7 +1551,7 @@ callback_playerconnect()
|
||||
thread kickifdontspawn();
|
||||
return;
|
||||
}
|
||||
else if ( !maps\mp\_utility::matchmakinggame() && maps\mp\_utility::allowteamchoice() )
|
||||
else if ( maps\mp\_utility::allowteamchoice() && !isbot( self ) )
|
||||
{
|
||||
maps\mp\gametypes\_menus::menuspectator();
|
||||
thread setuioptionsmenu( 1 );
|
||||
|
517
data/maps/mp/gametypes/gun.gsc
Normal file
517
data/maps/mp/gametypes/gun.gsc
Normal file
@ -0,0 +1,517 @@
|
||||
// S1 GSC SOURCE
|
||||
// Decompiled by https://github.com/xensik/gsc-tool
|
||||
|
||||
main()
|
||||
{
|
||||
maps\mp\gametypes\_globallogic::init();
|
||||
maps\mp\gametypes\_callbacksetup::setupcallbacks();
|
||||
maps\mp\gametypes\_globallogic::setupcallbacks();
|
||||
setguns();
|
||||
|
||||
|
||||
maps\mp\_utility::registertimelimitdvar( level.gametype, 10 );
|
||||
setDvar( "scr_gun_scorelimit", level.gun_guns.size );
|
||||
maps\mp\_utility::registerscorelimitdvar( level.gametype, level.gun_guns.size );
|
||||
level thread reinitializescorelimitonmigration();
|
||||
maps\mp\_utility::registerroundlimitdvar( level.gametype, 1 );
|
||||
maps\mp\_utility::registerwinlimitdvar( level.gametype, 0 );
|
||||
maps\mp\_utility::registernumlivesdvar( level.gametype, 0 );
|
||||
maps\mp\_utility::registerhalftimedvar( level.gametype, 0 );
|
||||
level.matchrules_randomize = 0;
|
||||
level.matchrules_damagemultiplier = 0;
|
||||
level.matchrules_vampirism = 0;
|
||||
|
||||
setspecialloadout();
|
||||
level.teambased = 0;
|
||||
level.doprematch = 1;
|
||||
level.onstartgametype = ::onstartgametype;
|
||||
level.onspawnplayer = ::onspawnplayer;
|
||||
level.getspawnpoint = ::getspawnpoint;
|
||||
level.onplayerkilled = ::onplayerkilled;
|
||||
level.ontimelimit = ::ontimelimit;
|
||||
level.onplayerscore = ::onplayerscore;
|
||||
level.bypassclasschoicefunc = ::gungameclass;
|
||||
level.assists_disabled = 1;
|
||||
level.setbacklevel = maps\mp\_utility::getintproperty( "scr_setback_levels", 1 );
|
||||
level.lastguntimevo = 0;
|
||||
|
||||
if ( level.matchrules_damagemultiplier )
|
||||
level.modifyplayerdamage = maps\mp\gametypes\_damage::gamemodemodifyplayerdamage;
|
||||
|
||||
setteamscore( "ffa" );
|
||||
game["dialog"]["gametype"] = "gg_intro";
|
||||
game["dialog"]["defense_obj"] = "gbl_start";
|
||||
game["dialog"]["offense_obj"] = "gbl_start";
|
||||
game["dialog"]["humiliation"] = "gg_humiliation";
|
||||
game["dialog"]["lastgun"] = "at_anr1_gg_lastgun";
|
||||
|
||||
if ( maps\mp\_utility::isgrapplinghookgamemode() )
|
||||
game["dialog"]["gametype"] = "grap_" + game["dialog"]["gametype"];
|
||||
}
|
||||
|
||||
initializematchrules()
|
||||
{
|
||||
maps\mp\_utility::setcommonrulesfrommatchrulesdata( 1 );
|
||||
level.matchrules_randomize = getmatchrulesdata( "gunData", "randomize" );
|
||||
setDvar( "scr_gun_scorelimit", level.gun_guns.size );
|
||||
maps\mp\_utility::registerscorelimitdvar( level.gametype, level.gun_guns.size );
|
||||
setDvar( "scr_gun_winlimit", 1 );
|
||||
maps\mp\_utility::registerwinlimitdvar( "gun", 1 );
|
||||
setDvar( "scr_gun_roundlimit", 1 );
|
||||
maps\mp\_utility::registerroundlimitdvar( "gun", 1 );
|
||||
setDvar( "scr_gun_halftime", 0 );
|
||||
maps\mp\_utility::registerhalftimedvar( "gun", 0 );
|
||||
setDvar( "scr_gun_playerrespawndelay", 0 );
|
||||
setDvar( "scr_gun_waverespawndelay", 0 );
|
||||
setDvar( "scr_player_forcerespawn", 1 );
|
||||
setDvar( "scr_setback_levels", getmatchrulesdata( "gunData", "setbackLevels" ) );
|
||||
}
|
||||
|
||||
reinitializescorelimitonmigration()
|
||||
{
|
||||
setDvar( "scr_gun_scorelimit", level.gun_guns.size );
|
||||
maps\mp\_utility::registerscorelimitdvar( level.gametype, level.gun_guns.size );
|
||||
}
|
||||
|
||||
onstartgametype()
|
||||
{
|
||||
getteamplayersalive( "auto_change" );
|
||||
maps\mp\_utility::setobjectivetext( "allies", &"OBJECTIVES_DM" );
|
||||
maps\mp\_utility::setobjectivetext( "axis", &"OBJECTIVES_DM" );
|
||||
|
||||
maps\mp\_utility::setobjectivescoretext( "allies", &"OBJECTIVES_DM_SCORE" );
|
||||
maps\mp\_utility::setobjectivescoretext( "axis", &"OBJECTIVES_DM_SCORE" );
|
||||
|
||||
maps\mp\_utility::setobjectivehinttext( "allies", &"OBJECTIVES_DM_HINT" );
|
||||
maps\mp\_utility::setobjectivehinttext( "axis", &"OBJECTIVES_DM_HINT" );
|
||||
initspawns();
|
||||
allowed = [];
|
||||
maps\mp\gametypes\_gameobjects::main( allowed );
|
||||
level.quickmessagetoall = 1;
|
||||
level.blockweapondrops = 1;
|
||||
level thread onplayerconnect();
|
||||
}
|
||||
|
||||
initspawns()
|
||||
{
|
||||
level.spawnmins = ( 0.0, 0.0, 0.0 );
|
||||
level.spawnmaxs = ( 0.0, 0.0, 0.0 );
|
||||
level.spawn_name = "mp_dm_spawn";
|
||||
maps\mp\gametypes\_spawnlogic::addspawnpoints( "allies", level.spawn_name );
|
||||
maps\mp\gametypes\_spawnlogic::addspawnpoints( "axis", level.spawn_name );
|
||||
level.mapcenter = maps\mp\gametypes\_spawnlogic::findboxcenter( level.spawnmins, level.spawnmaxs );
|
||||
setmapcenter( level.mapcenter );
|
||||
}
|
||||
|
||||
onplayerconnect()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
level waittill( "connected", player );
|
||||
player.gungamegunindex = 0;
|
||||
player.gungameprevgunindex = 0;
|
||||
player.stabs = 0;
|
||||
player.mysetbacks = 0;
|
||||
player.lastleveluptime = 0;
|
||||
player.showsetbacksplash = 0;
|
||||
|
||||
if ( level.matchrules_randomize )
|
||||
player.gunlist = common_scripts\utility::array_randomize( level.gun_guns );
|
||||
|
||||
player thread refillammo();
|
||||
player thread refillsinglecountammo();
|
||||
player thread watchforhostmigration();
|
||||
}
|
||||
}
|
||||
|
||||
getspawnpoint()
|
||||
{
|
||||
var_0 = maps\mp\gametypes\_spawnlogic::getteamspawnpoints( self.pers["team"] );
|
||||
|
||||
if ( level.ingraceperiod )
|
||||
var_1 = maps\mp\gametypes\_spawnlogic::getspawnpoint_random( var_0 );
|
||||
else
|
||||
var_1 = maps\mp\gametypes\_spawnscoring::getspawnpoint_freeforall( var_0 );
|
||||
|
||||
maps\mp\gametypes\_spawnlogic::recon_set_spawnpoint( var_1 );
|
||||
return var_1;
|
||||
}
|
||||
|
||||
gungameclass()
|
||||
{
|
||||
self.pers["class"] = "gamemode";
|
||||
self.pers["lastClass"] = "";
|
||||
self.pers["gamemodeLoadout"] = level.gun_loadout;
|
||||
self.class = self.pers["class"];
|
||||
self.lastclass = self.pers["lastClass"];
|
||||
self loadweapons( level.gun_guns[0] );
|
||||
}
|
||||
|
||||
onspawnplayer()
|
||||
{
|
||||
thread waitloadoutdone();
|
||||
}
|
||||
|
||||
waitloadoutdone()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "disconnect" );
|
||||
level waittill( "player_spawned" );
|
||||
givenextgun( 1 );
|
||||
|
||||
if ( self.showsetbacksplash )
|
||||
{
|
||||
self.showsetbacksplash = 0;
|
||||
thread maps\mp\_events::decreasegunlevelevent();
|
||||
}
|
||||
}
|
||||
|
||||
watchforhostmigration()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
for (;;)
|
||||
{
|
||||
self waittill( "player_migrated" );
|
||||
|
||||
if ( self.sessionstate == "spectator" )
|
||||
maps\mp\gametypes\_menus::handleclasschoicedisallowed();
|
||||
}
|
||||
}
|
||||
|
||||
onplayerscore( var_0, var_1, var_2 )
|
||||
{
|
||||
if ( var_0 == "gained_gun_score" )
|
||||
{
|
||||
var_3 = maps\mp\gametypes\_rank::getscoreinfovalue( var_0 );
|
||||
var_1 maps\mp\_utility::setextrascore0( var_1.extrascore0 + var_3 );
|
||||
var_1 maps\mp\gametypes\_gamescore::updatescorestatsffa( var_1, var_3 );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( var_0 == "dropped_gun_score" )
|
||||
{
|
||||
var_4 = min( level.setbacklevel, self.score );
|
||||
return int( var_4 * -1 );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
onplayerkilled( var_0, attacker, var_2, sMeansOfDeath, sWeapon, var_5, var_6, var_7, var_8, var_9 )
|
||||
{
|
||||
if ( !isdefined( attacker ) )
|
||||
return;
|
||||
|
||||
if ( sMeansOfDeath == "MOD_TRIGGER_HURT" && !isplayer( attacker ) )
|
||||
attacker = self;
|
||||
|
||||
if ( sMeansOfDeath == "MOD_FALLING" || isplayer( attacker ) )
|
||||
{
|
||||
if ( sMeansOfDeath == "MOD_FALLING" || attacker == self || maps\mp\_utility::ismeleemod( sMeansOfDeath ) && sWeapon != "riotshield_mp" || sWeapon == "boost_slam_mp" || sWeapon == "iw5_dlcgun12loot8_mp" )
|
||||
{
|
||||
self playlocalsound( "mp_war_objective_lost" );
|
||||
self.gungameprevgunindex = self.gungamegunindex;
|
||||
self.gungamegunindex = int( max( 0, self.gungamegunindex - level.setbacklevel ) );
|
||||
self.lastkillweapon = undefined;
|
||||
|
||||
if ( self.gungameprevgunindex > self.gungamegunindex )
|
||||
{
|
||||
self.mysetbacks++;
|
||||
maps\mp\_utility::setextrascore1( self.mysetbacks );
|
||||
self.showsetbacksplash = 1;
|
||||
|
||||
if ( maps\mp\_utility::ismeleemod( sMeansOfDeath ) || sWeapon == "boost_slam_mp" || sWeapon == "iw5_dlcgun12loot8_mp" )
|
||||
{
|
||||
attacker.stabs++;
|
||||
attacker.assists = attacker.stabs;
|
||||
attacker thread maps\mp\_events::setbackenemygunlevelevent();
|
||||
|
||||
if ( self.gungameprevgunindex == level.gun_guns.size - 1 )
|
||||
{
|
||||
attacker thread maps\mp\_events::setbackfirstplayergunlevelevent();
|
||||
attacker maps\mp\_utility::leaderdialogonplayer( "humiliation", "status" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( sMeansOfDeath == "MOD_PISTOL_BULLET" || sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_HEAD_SHOT" || sMeansOfDeath == "MOD_PROJECTILE" || sMeansOfDeath == "MOD_PROJECTILE_SPLASH" || sMeansOfDeath == "MOD_EXPLOSIVE" || sMeansOfDeath == "MOD_IMPACT" || sMeansOfDeath == "MOD_GRENADE" || sMeansOfDeath == "MOD_GRENADE_SPLASH" || maps\mp\_utility::ismeleemod( sMeansOfDeath ) && sWeapon == "riotshield_mp" )
|
||||
{
|
||||
if ( isdefined( attacker.lastkillweapon ) && attacker.lastkillweapon == sWeapon )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var_10 = level.gun_guns;
|
||||
|
||||
if ( level.matchrules_randomize )
|
||||
var_10 = attacker.gunlist;
|
||||
|
||||
var_11 = var_10[attacker.gungamegunindex];
|
||||
|
||||
if ( !issubstr( sWeapon, maps\mp\_utility::getbaseweaponname( var_11 ) ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
attacker.lastkillweapon = sWeapon;
|
||||
|
||||
if ( attacker.lastleveluptime + 3000 > gettime() )
|
||||
attacker thread maps\mp\_events::quickgunlevelevent();
|
||||
|
||||
attacker.lastleveluptime = gettime();
|
||||
attacker.gungameprevgunindex = attacker.gungamegunindex;
|
||||
attacker.gungamegunindex++;
|
||||
attacker thread maps\mp\_events::increasegunlevelevent();
|
||||
|
||||
if ( attacker.gungamegunindex == level.gun_guns.size - 1 )
|
||||
{
|
||||
maps\mp\_utility::playsoundonplayers( "mp_enemy_obj_captured" );
|
||||
level thread maps\mp\_utility::teamplayercardsplash( "callout_top_gun_rank", attacker );
|
||||
var_12 = gettime();
|
||||
|
||||
if ( level.lastguntimevo + 4500 < var_12 )
|
||||
{
|
||||
level thread maps\mp\_utility::leaderdialogonplayers( "lastgun", level.players, "status" );
|
||||
level.lastguntimevo = var_12;
|
||||
}
|
||||
}
|
||||
|
||||
if ( attacker.gungamegunindex < level.gun_guns.size )
|
||||
attacker givenextgun( 0, sWeapon );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
givenextgun( var_0, var_1 )
|
||||
{
|
||||
self endon( "disconnect" );
|
||||
var_2 = getnextgun();
|
||||
self.gun_curgun = var_2;
|
||||
var_2 = addattachments( var_2 );
|
||||
|
||||
while ( !self loadweapons( var_2 ) )
|
||||
{
|
||||
waitframe();
|
||||
}
|
||||
|
||||
if ( isdefined( var_1 ) )
|
||||
self takeweapon( var_1 );
|
||||
else
|
||||
self takeallweapons();
|
||||
|
||||
maps\mp\_utility::_giveweapon( var_2 );
|
||||
self switchtoweaponimmediate( var_2 );
|
||||
|
||||
if ( isdefined( var_0 ) && var_0 == 1 )
|
||||
self setspawnweapon( var_2 );
|
||||
|
||||
var_3 = maps\mp\_utility::getbaseweaponname( var_2 );
|
||||
self.pers["primaryWeapon"] = var_3;
|
||||
self.primaryweapon = var_2;
|
||||
self givestartammo( var_2 );
|
||||
self switchtoweapon( var_2 );
|
||||
self.gungameprevgunindex = self.gungamegunindex;
|
||||
}
|
||||
|
||||
getnextgun()
|
||||
{
|
||||
var_0 = level.gun_guns;
|
||||
var_1 = [];
|
||||
newWeapon = undefined;
|
||||
|
||||
if ( level.matchrules_randomize )
|
||||
var_0 = self.gunlist;
|
||||
|
||||
newWeapon = var_0[self.gungamegunindex];
|
||||
var_1[var_1.size] = newWeapon;
|
||||
|
||||
if ( self.gungamegunindex + 1 < var_0.size )
|
||||
var_1[var_1.size] = var_0[self.gungamegunindex + 1];
|
||||
|
||||
if ( self.gungamegunindex > 0 )
|
||||
var_1[var_1.size] = var_0[self.gungamegunindex - 1];
|
||||
|
||||
self loadweapons( var_1 );
|
||||
return newWeapon;
|
||||
}
|
||||
|
||||
addattachments( weaponName )
|
||||
{
|
||||
if ( getdvarint( "scr_gun_loot_variants", 0 ) == 1 )
|
||||
{
|
||||
var_1 = tablelookup( "mp/statstable.csv", 4, weaponName , 40 );
|
||||
|
||||
if ( isdefined( var_1 ) && var_1 != "" )
|
||||
var_2 = maps\mp\gametypes\_class::buildweaponname( weaponName , var_1, "none", "none", 0, 0 );
|
||||
else
|
||||
var_2 = maps\mp\gametypes\_class::buildweaponname( weaponName , "none", "none", "none", 0, 0 );
|
||||
}
|
||||
else
|
||||
var_2 = maps\mp\gametypes\_class::buildweaponname( weaponName , "none", "none", "none", 0, 0 );
|
||||
|
||||
return var_2;
|
||||
}
|
||||
|
||||
ontimelimit()
|
||||
{
|
||||
level.finalkillcam_winner = "none";
|
||||
winners = gethighestprogressedplayers();
|
||||
|
||||
if ( !isdefined( winners ) || !winners.size )
|
||||
thread maps\mp\gametypes\_gamelogic::endgame( "tie", game["end_reason"]["time_limit_reached"] );
|
||||
else if ( winners.size == 1 )
|
||||
thread maps\mp\gametypes\_gamelogic::endgame( winners[0], game["end_reason"]["time_limit_reached"] );
|
||||
else if ( winners[winners.size - 1].gungamegunindex > winners[winners.size - 2].gungamegunindex )
|
||||
thread maps\mp\gametypes\_gamelogic::endgame( winners[winners.size - 1], game["end_reason"]["time_limit_reached"] );
|
||||
else
|
||||
thread maps\mp\gametypes\_gamelogic::endgame( "tie", game["end_reason"]["time_limit_reached"] );
|
||||
}
|
||||
|
||||
gethighestprogressedplayers()
|
||||
{
|
||||
var_0 = -1;
|
||||
var_1 = [];
|
||||
|
||||
foreach ( var_3 in level.players )
|
||||
{
|
||||
if ( isdefined( var_3.gungamegunindex ) && var_3.gungamegunindex >= var_0 )
|
||||
{
|
||||
var_0 = var_3.gungamegunindex;
|
||||
var_1[var_1.size] = var_3;
|
||||
}
|
||||
}
|
||||
|
||||
return var_1;
|
||||
}
|
||||
|
||||
refillammo()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
for (;;)
|
||||
{
|
||||
self waittill( "reload" );
|
||||
self givestartammo( self.primaryweapon );
|
||||
}
|
||||
}
|
||||
|
||||
refillsinglecountammo()
|
||||
{
|
||||
level endon( "game_ended" );
|
||||
self endon( "disconnect" );
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if ( maps\mp\_utility::isreallyalive( self ) && self.team != "spectator" && isdefined( self.primaryweapon ) && self getammocount( self.primaryweapon ) == 0 )
|
||||
{
|
||||
wait 2;
|
||||
self notify( "reload" );
|
||||
wait 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
wait 0.05;
|
||||
}
|
||||
}
|
||||
|
||||
setguns()
|
||||
{
|
||||
var_0 = getdvarint( "scr_gun_loot_variants", 0 );
|
||||
level.gun_guns = [];
|
||||
level.gun_guns[0] = "iw5_asm1";
|
||||
level.gun_guns[1] = "iw5_asaw";
|
||||
level.gun_guns[2] = "iw5_himar";
|
||||
level.gun_guns[3] = "iw5_kf5";
|
||||
level.gun_guns[4] = "iw5_hbra3";
|
||||
level.gun_guns[5] = "iw5_mp11";
|
||||
level.gun_guns[6] = "iw5_ak12";
|
||||
level.gun_guns[7] = "iw5_sn6";
|
||||
level.gun_guns[8] = "iw5_arx160";
|
||||
level.gun_guns[9] = "iw5_hmr9";
|
||||
level.gun_guns[10] = "iw5_maul";
|
||||
level.gun_guns[11] = "iw5_dlcgun3";
|
||||
level.gun_guns[12] = "iw5_em1";
|
||||
level.gun_guns[13] = "iw5_uts19";
|
||||
level.gun_guns[14] = "iw5_lsat";
|
||||
level.gun_guns[15] = "iw5_rhino";
|
||||
level.gun_guns[16] = "iw5_exoxmg";
|
||||
level.gun_guns[17] = "iw5_epm3";
|
||||
level.gun_guns[18] = "iw5_mors";
|
||||
level.gun_guns[19] = "iw5_rw1";
|
||||
level.gun_guns[20] = "iw5_vbr";
|
||||
level.gun_guns[21] = "iw5_pbw";
|
||||
level.gun_guns[22] = "iw5_thor";
|
||||
level.gun_guns[23] = "iw5_mahem";
|
||||
level.gun_guns[24] = "iw5_exocrossbow";
|
||||
|
||||
if ( isdefined( var_0 ) && var_0 )
|
||||
{
|
||||
for ( var_1 = 0; var_1 < level.gun_guns.size; var_1++ )
|
||||
{
|
||||
var_2 = level.gun_guns[var_1];
|
||||
|
||||
if ( maps\mp\_utility::getweaponclass( var_2 ) == "weapon_projectile" || maps\mp\_utility::getweaponclass( var_2 ) == "weapon_sec_special" )
|
||||
var_2 = assign_random_loot_variant( var_2, 4 );
|
||||
else
|
||||
var_2 = assign_random_loot_variant( var_2, 10 );
|
||||
|
||||
level.gun_guns[var_1] = var_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assign_random_loot_variant( var_0, var_1 )
|
||||
{
|
||||
var_2 = randomint( var_1 );
|
||||
|
||||
switch ( var_2 )
|
||||
{
|
||||
case 0:
|
||||
var_0 += "loot0";
|
||||
break;
|
||||
case 1:
|
||||
var_0 += "loot1";
|
||||
break;
|
||||
case 2:
|
||||
var_0 += "loot2";
|
||||
break;
|
||||
case 3:
|
||||
var_0 += "loot3";
|
||||
break;
|
||||
case 4:
|
||||
var_0 += "loot4";
|
||||
break;
|
||||
case 5:
|
||||
var_0 += "loot5";
|
||||
break;
|
||||
case 6:
|
||||
var_0 += "loot6";
|
||||
break;
|
||||
case 7:
|
||||
var_0 += "loot7";
|
||||
break;
|
||||
case 8:
|
||||
var_0 += "loot8";
|
||||
break;
|
||||
case 9:
|
||||
var_0 += "loot9";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return var_0;
|
||||
}
|
||||
|
||||
setspecialloadout()
|
||||
{
|
||||
level.gun_loadout = maps\mp\gametypes\_class::getemptyloadout();
|
||||
|
||||
if ( maps\mp\gametypes\_class::isvalidprimary( level.gun_guns[0] ) )
|
||||
level.gun_loadout["loadoutPrimary"] = level.gun_guns[0];
|
||||
else if ( maps\mp\gametypes\_class::isvalidsecondary( level.gun_guns[0], 0 ) )
|
||||
level.gun_loadout["loadoutSecondary"] = level.gun_guns[0];
|
||||
}
|
19
data/ui_scripts/patches/__init__.lua
Normal file
19
data/ui_scripts/patches/__init__.lua
Normal file
@ -0,0 +1,19 @@
|
||||
if (game:issingleplayer()) then
|
||||
return
|
||||
end
|
||||
|
||||
function GetGameModeName()
|
||||
return Engine.Localize(Engine.TableLookup(GameTypesTable.File, GameTypesTable.Cols.Ref, GameX.GetGameMode(), GameTypesTable.Cols.Name))
|
||||
end
|
||||
|
||||
-- Allow players to change teams in game.
|
||||
function CanChangeTeam()
|
||||
local f9_local0 = GameX.GetGameMode()
|
||||
local f9_local1
|
||||
if f9_local0 ~= "aliens" and Engine.TableLookup( GameTypesTable.File, GameTypesTable.Cols.Ref, f9_local0, GameTypesTable.Cols.TeamChoice ) == "1" then
|
||||
f9_local1 = not MLG.IsMLGSpectator()
|
||||
else
|
||||
f9_local1 = false
|
||||
end
|
||||
return f9_local1
|
||||
end
|
2
deps/GSL
vendored
2
deps/GSL
vendored
@ -1 +1 @@
|
||||
Subproject commit 517ed29228d18cf2c5004d10826090108e06f049
|
||||
Subproject commit cbf5e664fc55cbcc33b10f3058ede325cd133a01
|
2
deps/asmjit
vendored
2
deps/asmjit
vendored
@ -1 +1 @@
|
||||
Subproject commit 0c03ed2f7497441ac0de232bda2e6b8cc041b2dc
|
||||
Subproject commit e13642567393a4bfc8c5607b33337b2ed3b0d01e
|
2
deps/libtomcrypt
vendored
2
deps/libtomcrypt
vendored
@ -1 +1 @@
|
||||
Subproject commit 3474ca37124c6fe78f5461876542e226a25b5f1f
|
||||
Subproject commit 29986d04f2dca985ee64fbca1c7431ea3e3422f4
|
2
deps/lua
vendored
2
deps/lua
vendored
@ -1 +1 @@
|
||||
Subproject commit be908a7d4d8130264ad67c5789169769f824c5d1
|
||||
Subproject commit d69789da1ccfa4db7c241de6b471d6b729f1561e
|
2
deps/minhook
vendored
2
deps/minhook
vendored
@ -1 +1 @@
|
||||
Subproject commit 426cb6880035ee3cceed05384bb3f2db01a20a15
|
||||
Subproject commit 49d03ad118cf7f6768c79a8f187e14b8f2a07f94
|
2
deps/protobuf
vendored
2
deps/protobuf
vendored
@ -1 +1 @@
|
||||
Subproject commit 57786d126249b5ed4f42b579047941805e742949
|
||||
Subproject commit 8d5fdedd42ef361dcfc1531fba4f33470273f375
|
2
deps/rapidjson
vendored
2
deps/rapidjson
vendored
@ -1 +1 @@
|
||||
Subproject commit 06d58b9e848c650114556a23294d0b6440078c61
|
||||
Subproject commit 012be8528783cdbf4b7a9e64f78bd8f056b97e24
|
2
deps/sol2
vendored
2
deps/sol2
vendored
@ -1 +1 @@
|
||||
Subproject commit f81643aa0c0c507c0cd8400b8cfedc74a34a19f6
|
||||
Subproject commit 19898d8d3e6c3def33625082343428be1bb9387b
|
2
deps/zlib
vendored
2
deps/zlib
vendored
@ -1 +1 @@
|
||||
Subproject commit 04f42ceca40f73e2978b50e93806c2a18c1281fc
|
||||
Subproject commit 02a6049eb3884c430268bb0fe3296d597a03174c
|
@ -41,7 +41,7 @@ namespace branding
|
||||
}
|
||||
localized_strings::override("LUA_MENU_LEGAL_COPYRIGHT", "S1x: " VERSION);
|
||||
|
||||
dvars::override::Dvar_SetString("version", utils::string::va("S1x %s", VERSION));
|
||||
dvars::override::set_string("version", utils::string::va("S1x %s", VERSION));
|
||||
|
||||
ui_get_formatted_build_number_hook.create(
|
||||
SELECT_VALUE(0x14035B3F0, 0x1404A8950), ui_get_formatted_build_number_stub);
|
||||
|
@ -182,13 +182,13 @@ namespace dedicated
|
||||
sv_lanOnly = game::Dvar_RegisterBool("sv_lanOnly", false, game::DVAR_FLAG_NONE, "Don't send heartbeat");
|
||||
|
||||
// Disable VirtualLobby
|
||||
dvars::override::Dvar_RegisterBool("virtualLobbyEnabled", false, game::DVAR_FLAG_NONE | game::DVAR_FLAG_READ);
|
||||
dvars::override::register_bool("virtualLobbyEnabled", false, game::DVAR_FLAG_NONE | game::DVAR_FLAG_READ);
|
||||
|
||||
// Disable r_preloadShaders
|
||||
dvars::override::Dvar_RegisterBool("r_preloadShaders", false, game::DVAR_FLAG_NONE | game::DVAR_FLAG_READ);
|
||||
dvars::override::register_bool("r_preloadShaders", false, game::DVAR_FLAG_NONE | game::DVAR_FLAG_READ);
|
||||
|
||||
// Don't allow sv_hostname to be changed by the game
|
||||
dvars::disable::Dvar_SetString("sv_hostname");
|
||||
dvars::disable::set_string("sv_hostname");
|
||||
|
||||
// Stop crashing from sys_errors
|
||||
utils::hook::jump(0x1404D6260, sys_error_stub);
|
||||
|
@ -11,7 +11,6 @@ namespace dvars
|
||||
struct dvar_base
|
||||
{
|
||||
unsigned int flags{};
|
||||
std::string description{};
|
||||
};
|
||||
|
||||
struct dvar_bool : dvar_base
|
||||
@ -83,22 +82,22 @@ namespace dvars
|
||||
static std::unordered_set<std::string> set_int_disables;
|
||||
static std::unordered_set<std::string> set_string_disables;
|
||||
|
||||
void Dvar_SetBool(const std::string& name)
|
||||
void set_bool(const std::string& name)
|
||||
{
|
||||
set_bool_disables.emplace(name);
|
||||
}
|
||||
|
||||
void Dvar_SetFloat(const std::string& name)
|
||||
void set_float(const std::string& name)
|
||||
{
|
||||
set_float_disables.emplace(name);
|
||||
}
|
||||
|
||||
void Dvar_SetInt(const std::string& name)
|
||||
void set_int(const std::string& name)
|
||||
{
|
||||
set_int_disables.emplace(name);
|
||||
}
|
||||
|
||||
void Dvar_SetString(const std::string& name)
|
||||
void set_string(const std::string& name)
|
||||
{
|
||||
set_string_disables.emplace(name);
|
||||
}
|
||||
@ -118,54 +117,43 @@ namespace dvars
|
||||
static std::unordered_map<std::string, int> set_int_overrides;
|
||||
static std::unordered_map<std::string, std::string> set_string_overrides;
|
||||
|
||||
void Dvar_RegisterBool(const std::string& name, const bool value, const unsigned int flags,
|
||||
const std::string& description)
|
||||
void register_bool(const std::string& name, const bool value, const unsigned int flags)
|
||||
{
|
||||
dvar_bool values;
|
||||
values.value = value;
|
||||
values.flags = flags;
|
||||
values.description = description;
|
||||
register_bool_overrides[name] = std::move(values);
|
||||
}
|
||||
|
||||
void Dvar_RegisterFloat(const std::string& name, const float value, const float min, const float max,
|
||||
const unsigned int flags,
|
||||
const std::string& description)
|
||||
void register_float(const std::string& name, const float value, const float min, const float max, const unsigned int flags)
|
||||
{
|
||||
dvar_float values;
|
||||
values.value = value;
|
||||
values.min = min;
|
||||
values.max = max;
|
||||
values.flags = flags;
|
||||
values.description = description;
|
||||
register_float_overrides[name] = std::move(values);
|
||||
}
|
||||
|
||||
void Dvar_RegisterInt(const std::string& name, const int value, const int min, const int max,
|
||||
const unsigned int flags,
|
||||
const std::string& description)
|
||||
void register_int(const std::string& name, const int value, const int min, const int max, const unsigned int flags)
|
||||
{
|
||||
dvar_int values;
|
||||
values.value = value;
|
||||
values.min = min;
|
||||
values.max = max;
|
||||
values.flags = flags;
|
||||
values.description = description;
|
||||
register_int_overrides[name] = std::move(values);
|
||||
}
|
||||
|
||||
void Dvar_RegisterString(const std::string& name, const std::string& value, const unsigned int flags,
|
||||
const std::string& description)
|
||||
void register_string(const std::string& name, const std::string& value, const unsigned int flags)
|
||||
{
|
||||
dvar_string values;
|
||||
values.value = value;
|
||||
values.flags = flags;
|
||||
values.description = description;
|
||||
register_string_overrides[name] = std::move(values);
|
||||
}
|
||||
|
||||
void Dvar_RegisterVector2(const std::string& name, float x, float y, float min, float max,
|
||||
const unsigned int flags, const std::string& description)
|
||||
void register_vector2(const std::string& name, float x, float y, float min, float max, const unsigned int flags)
|
||||
{
|
||||
dvar_vector2 values;
|
||||
values.x = x;
|
||||
@ -173,12 +161,10 @@ namespace dvars
|
||||
values.min = min;
|
||||
values.max = max;
|
||||
values.flags = flags;
|
||||
values.description = description;
|
||||
register_vector2_overrides[name] = std::move(values);
|
||||
}
|
||||
|
||||
void Dvar_RegisterVector3(const std::string& name, float x, float y, float z, float min,
|
||||
float max, const unsigned int flags, const std::string& description)
|
||||
void register_vector3(const std::string& name, float x, float y, float z, float min, float max, const unsigned int flags)
|
||||
{
|
||||
dvar_vector3 values;
|
||||
values.x = x;
|
||||
@ -187,26 +173,25 @@ namespace dvars
|
||||
values.min = min;
|
||||
values.max = max;
|
||||
values.flags = flags;
|
||||
values.description = description;
|
||||
register_vector3_overrides[name] = std::move(values);
|
||||
}
|
||||
|
||||
void Dvar_SetBool(const std::string& name, const bool value)
|
||||
void set_bool(const std::string& name, const bool value)
|
||||
{
|
||||
set_bool_overrides[name] = value;
|
||||
}
|
||||
|
||||
void Dvar_SetFloat(const std::string& name, const float value)
|
||||
void set_float(const std::string& name, const float value)
|
||||
{
|
||||
set_float_overrides[name] = value;
|
||||
}
|
||||
|
||||
void Dvar_SetInt(const std::string& name, const int value)
|
||||
void set_int(const std::string& name, const int value)
|
||||
{
|
||||
set_int_overrides[name] = value;
|
||||
}
|
||||
|
||||
void Dvar_SetString(const std::string& name, const std::string& value)
|
||||
void set_string(const std::string& name, const std::string& value)
|
||||
{
|
||||
set_string_overrides[name] = value;
|
||||
}
|
||||
@ -224,20 +209,19 @@ namespace dvars
|
||||
utils::hook::detour dvar_set_int_hook;
|
||||
utils::hook::detour dvar_set_string_hook;
|
||||
|
||||
game::dvar_t* dvar_register_bool(const char* name, bool value, unsigned int flags, const char* description)
|
||||
game::dvar_t* dvar_register_bool_stub(const char* name, bool value, unsigned int flags, const char* description)
|
||||
{
|
||||
auto* var = find_dvar(override::register_bool_overrides, name);
|
||||
if (var)
|
||||
{
|
||||
value = var->value;
|
||||
flags = var->flags;
|
||||
description = var->description.data();
|
||||
}
|
||||
|
||||
return dvar_register_bool_hook.invoke<game::dvar_t*>(name, value, flags, description);
|
||||
}
|
||||
|
||||
game::dvar_t* dvar_register_float(const char* name, float value, float min, float max, unsigned int flags,
|
||||
game::dvar_t* dvar_register_float_stub(const char* name, float value, float min, float max, unsigned int flags,
|
||||
const char* description)
|
||||
{
|
||||
auto* var = find_dvar(override::register_float_overrides, name);
|
||||
@ -247,13 +231,12 @@ namespace dvars
|
||||
min = var->min;
|
||||
max = var->max;
|
||||
flags = var->flags;
|
||||
description = var->description.data();
|
||||
}
|
||||
|
||||
return dvar_register_float_hook.invoke<game::dvar_t*>(name, value, min, max, flags, description);
|
||||
}
|
||||
|
||||
game::dvar_t* dvar_register_int(const char* name, int value, int min, int max, unsigned int flags,
|
||||
game::dvar_t* dvar_register_int_stub(const char* name, int value, int min, int max, unsigned int flags,
|
||||
const char* description)
|
||||
{
|
||||
auto* var = find_dvar(override::register_int_overrides, name);
|
||||
@ -263,26 +246,24 @@ namespace dvars
|
||||
min = var->min;
|
||||
max = var->max;
|
||||
flags = var->flags;
|
||||
description = var->description.data();
|
||||
}
|
||||
|
||||
return dvar_register_int_hook.invoke<game::dvar_t*>(name, value, min, max, flags, description);
|
||||
}
|
||||
|
||||
game::dvar_t* dvar_register_string(const char* name, const char* value, unsigned int flags, const char* description)
|
||||
game::dvar_t* dvar_register_string_stub(const char* name, const char* value, unsigned int flags, const char* description)
|
||||
{
|
||||
auto* var = find_dvar(override::register_string_overrides, name);
|
||||
if (var)
|
||||
{
|
||||
value = var->value.data();
|
||||
flags = var->flags;
|
||||
description = var->description.data();
|
||||
}
|
||||
|
||||
return dvar_register_string_hook.invoke<game::dvar_t*>(name, value, flags, description);
|
||||
}
|
||||
|
||||
game::dvar_t* dvar_register_vector2(const char* name, float x, float y, float min, float max,
|
||||
game::dvar_t* dvar_register_vector2_stub(const char* name, float x, float y, float min, float max,
|
||||
unsigned int flags, const char* description)
|
||||
{
|
||||
auto* var = find_dvar(override::register_vector2_overrides, name);
|
||||
@ -293,13 +274,12 @@ namespace dvars
|
||||
min = var->min;
|
||||
max = var->max;
|
||||
flags = var->flags;
|
||||
description = var->description.data();
|
||||
}
|
||||
|
||||
return dvar_register_vector2_hook.invoke<game::dvar_t*>(name, x, y, min, max, flags, description);
|
||||
}
|
||||
|
||||
game::dvar_t* dvar_register_vector3(const char* name, float x, float y, float z, float min,
|
||||
game::dvar_t* dvar_register_vector3_stub(const char* name, float x, float y, float z, float min,
|
||||
float max, unsigned int flags, const char* description)
|
||||
{
|
||||
auto* var = find_dvar(override::register_vector3_overrides, name);
|
||||
@ -311,13 +291,12 @@ namespace dvars
|
||||
min = var->min;
|
||||
max = var->max;
|
||||
flags = var->flags;
|
||||
description = var->description.data();
|
||||
}
|
||||
|
||||
return dvar_register_vector3_hook.invoke<game::dvar_t*>(name, x, y, z, min, max, flags, description);
|
||||
}
|
||||
|
||||
void dvar_set_bool(game::dvar_t* dvar, bool boolean)
|
||||
void dvar_set_bool_stub(game::dvar_t* dvar, bool boolean)
|
||||
{
|
||||
const auto disabled = find_dvar(disable::set_bool_disables, dvar->name);
|
||||
if (disabled)
|
||||
@ -334,7 +313,7 @@ namespace dvars
|
||||
return dvar_set_bool_hook.invoke<void>(dvar, boolean);
|
||||
}
|
||||
|
||||
void dvar_set_float(game::dvar_t* dvar, float fl)
|
||||
void dvar_set_float_stub(game::dvar_t* dvar, float fl)
|
||||
{
|
||||
const auto disabled = find_dvar(disable::set_float_disables, dvar->name);
|
||||
if (disabled)
|
||||
@ -351,7 +330,7 @@ namespace dvars
|
||||
return dvar_set_float_hook.invoke<void>(dvar, fl);
|
||||
}
|
||||
|
||||
void dvar_set_int(game::dvar_t* dvar, int integer)
|
||||
void dvar_set_int_stub(game::dvar_t* dvar, int integer)
|
||||
{
|
||||
const auto disabled = find_dvar(disable::set_int_disables, dvar->name);
|
||||
if (disabled)
|
||||
@ -368,7 +347,7 @@ namespace dvars
|
||||
return dvar_set_int_hook.invoke<void>(dvar, integer);
|
||||
}
|
||||
|
||||
void dvar_set_string(game::dvar_t* dvar, const char* string)
|
||||
void dvar_set_string_stub(game::dvar_t* dvar, const char* string)
|
||||
{
|
||||
const auto disabled = find_dvar(disable::set_string_disables, dvar->name);
|
||||
if (disabled)
|
||||
@ -390,17 +369,17 @@ namespace dvars
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
dvar_register_bool_hook.create(SELECT_VALUE(0x140371850, 0x1404C0BE0), &dvar_register_bool);
|
||||
dvar_register_float_hook.create(SELECT_VALUE(0x140371C20, 0x1404C0FB0), &dvar_register_float);
|
||||
dvar_register_int_hook.create(SELECT_VALUE(0x140371CF0, 0x1404C1080), &dvar_register_int);
|
||||
dvar_register_string_hook.create(SELECT_VALUE(0x140372050, 0x1404C1450), &dvar_register_string);
|
||||
dvar_register_vector2_hook.create(SELECT_VALUE(0x140372120, 0x1404C1520), &dvar_register_vector2);
|
||||
dvar_register_vector3_hook.create(SELECT_VALUE(0x140372230, 0x1404C1600), &dvar_register_vector3);
|
||||
dvar_register_bool_hook.create(SELECT_VALUE(0x140371850, 0x1404C0BE0), &dvar_register_bool_stub);
|
||||
dvar_register_float_hook.create(SELECT_VALUE(0x140371C20, 0x1404C0FB0), &dvar_register_float_stub);
|
||||
dvar_register_int_hook.create(SELECT_VALUE(0x140371CF0, 0x1404C1080), &dvar_register_int_stub);
|
||||
dvar_register_string_hook.create(SELECT_VALUE(0x140372050, 0x1404C1450), &dvar_register_string_stub);
|
||||
dvar_register_vector2_hook.create(SELECT_VALUE(0x140372120, 0x1404C1520), &dvar_register_vector2_stub);
|
||||
dvar_register_vector3_hook.create(SELECT_VALUE(0x140372230, 0x1404C1600), &dvar_register_vector3_stub);
|
||||
|
||||
dvar_set_bool_hook.create(SELECT_VALUE(0x140372B70, 0x1404C1F30), &dvar_set_bool);
|
||||
dvar_set_float_hook.create(SELECT_VALUE(0x140373420, 0x1404C2A10), &dvar_set_float);
|
||||
dvar_set_int_hook.create(SELECT_VALUE(0x1403738D0, 0x1404C2F40), &dvar_set_int);
|
||||
dvar_set_string_hook.create(SELECT_VALUE(0x140373DE0, 0x1404C3610), &dvar_set_string);
|
||||
dvar_set_bool_hook.create(SELECT_VALUE(0x140372B70, 0x1404C1F30), &dvar_set_bool_stub);
|
||||
dvar_set_float_hook.create(SELECT_VALUE(0x140373420, 0x1404C2A10), &dvar_set_float_stub);
|
||||
dvar_set_int_hook.create(SELECT_VALUE(0x1403738D0, 0x1404C2F40), &dvar_set_int_stub);
|
||||
dvar_set_string_hook.create(SELECT_VALUE(0x140373DE0, 0x1404C3610), &dvar_set_string_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -4,24 +4,24 @@ namespace dvars
|
||||
{
|
||||
namespace disable
|
||||
{
|
||||
void Dvar_SetBool(const std::string& name);
|
||||
void Dvar_SetFloat(const std::string& name);
|
||||
void Dvar_SetInt(const std::string& name);
|
||||
void Dvar_SetString(const std::string& name);
|
||||
void set_bool(const std::string& name);
|
||||
void set_float(const std::string& name);
|
||||
void set_int(const std::string& name);
|
||||
void set_string(const std::string& name);
|
||||
}
|
||||
|
||||
namespace override
|
||||
{
|
||||
void Dvar_RegisterBool(const std::string& name, bool value, const unsigned int flags, const std::string& description = "");
|
||||
void Dvar_RegisterFloat(const std::string& name, float value, float min, float max, const unsigned int flags, const std::string& description = "");
|
||||
void Dvar_RegisterInt(const std::string& name, int value, int min, int max, const unsigned int flags, const std::string& description = "");
|
||||
void Dvar_RegisterString(const std::string& name, const std::string& value, const unsigned int flags, const std::string& description = "");
|
||||
void Dvar_RegisterVector2(const std::string& name, float x, float y, float min, float max, const unsigned int flags, const std::string& description = "");
|
||||
void Dvar_RegisterVector3(const std::string& name, float x, float y, float z, float min, float max, const unsigned int flags, const std::string& description = "");
|
||||
void register_bool(const std::string& name, bool value, unsigned int flags);
|
||||
void register_float(const std::string& name, float value, float min, float max, unsigned int flags);
|
||||
void register_int(const std::string& name, int value, int min, int max, unsigned int flags);
|
||||
void register_string(const std::string& name, const std::string& value, unsigned int flags);
|
||||
void register_vector2(const std::string& name, float x, float y, float min, float max, unsigned int flags);
|
||||
void register_vector3(const std::string& name, float x, float y, float z, float min, float max, unsigned int flags);
|
||||
|
||||
void Dvar_SetBool(const std::string& name, bool boolean);
|
||||
void Dvar_SetFloat(const std::string& name, float fl);
|
||||
void Dvar_SetInt(const std::string& name, int integer);
|
||||
void Dvar_SetString(const std::string& name, const std::string& string);
|
||||
void set_bool(const std::string& name, bool boolean);
|
||||
void set_float(const std::string& name, float fl);
|
||||
void set_int(const std::string& name, int integer);
|
||||
void set_string(const std::string& name, const std::string& string);
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ namespace filesystem
|
||||
void post_unpack() override
|
||||
{
|
||||
// Set fs_basegame
|
||||
dvars::override::Dvar_RegisterString("fs_basegame", "s1x", game::DVAR_FLAG_WRITE);
|
||||
dvars::override::register_string("fs_basegame", "s1x", game::DVAR_FLAG_WRITE);
|
||||
|
||||
if (game::environment::is_sp())
|
||||
{
|
||||
|
@ -173,7 +173,7 @@ namespace fps
|
||||
scheduler::loop(cg_draw_fps, scheduler::pipeline::renderer);
|
||||
if (game::environment::is_mp())
|
||||
{
|
||||
cg_drawPing = game::Dvar_RegisterInt("cg_drawPing", 0, 0, 1, game::DVAR_FLAG_SAVED, "Choose to draw ping");
|
||||
cg_drawPing = game::Dvar_RegisterInt("cg_drawPing", 0, 0, 1, game::DVAR_FLAG_SAVED, "Draw ping");
|
||||
scheduler::loop(cg_draw_ping, scheduler::pipeline::renderer);
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ namespace gsc
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto script_file_ptr = static_cast<game::ScriptFile*>(game::PMem_AllocFromSource_NoDebug(sizeof(game::ScriptFile), 4, 1, 5));
|
||||
const auto script_file_ptr = static_cast<game::ScriptFile*>(game::Hunk_AllocateTempMemoryHighInternal(sizeof(game::ScriptFile)));
|
||||
script_file_ptr->name = file_name;
|
||||
|
||||
const auto stack = assembler->output_stack();
|
||||
@ -130,16 +130,15 @@ namespace gsc
|
||||
const auto script = assembler->output_script();
|
||||
script_file_ptr->bytecodeLen = static_cast<int>(script.size());
|
||||
|
||||
const auto script_size = script.size();
|
||||
// Use PMem for both stack and byte code
|
||||
const auto buffer_size = script_size + stack.size() + 2;
|
||||
const auto stack_size = static_cast<std::uint32_t>(stack.size() + 1);
|
||||
const auto byte_code_size = static_cast<std::uint32_t>(script.size() + 1);
|
||||
|
||||
const auto buffer = static_cast<std::uint8_t*>(game::PMem_AllocFromSource_NoDebug(static_cast<std::uint32_t>(buffer_size), 4, 1, 5));
|
||||
std::memcpy(buffer, script.data(), script_size);
|
||||
std::memcpy(&buffer[script_size], stack.data(), stack.size());
|
||||
script_file_ptr->buffer = static_cast<char*>(game::Hunk_AllocateTempMemoryHighInternal(stack_size));
|
||||
std::memcpy(const_cast<char*>(script_file_ptr->buffer), stack.data(), stack.size());
|
||||
|
||||
script_file_ptr->bytecode = static_cast<std::uint8_t*>(game::PMem_AllocFromSource_NoDebug(byte_code_size, 4, 1, 5));
|
||||
std::memcpy(script_file_ptr->bytecode, script.data(), script.size());
|
||||
|
||||
script_file_ptr->bytecode = &buffer[0];
|
||||
script_file_ptr->buffer = reinterpret_cast<char*>(&buffer[script.size()]);
|
||||
script_file_ptr->compressedLen = 0;
|
||||
|
||||
loaded_scripts[real_name] = script_file_ptr;
|
||||
|
@ -5,35 +5,40 @@
|
||||
#include "command.hpp"
|
||||
#include "console.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "map_rotation.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace map_rotation
|
||||
{
|
||||
DWORD previousPriority;
|
||||
namespace
|
||||
{
|
||||
void set_dvar(const std::string& dvar, const std::string& value)
|
||||
{
|
||||
command::execute(utils::string::va("%s \"%s\"", dvar.data(), value.data()), true);
|
||||
}
|
||||
rotation_data dedicated_rotation;
|
||||
|
||||
const game::dvar_t* sv_map_rotation;
|
||||
const game::dvar_t* sv_map_rotation_current;
|
||||
const game::dvar_t* sv_random_map_rotation;
|
||||
|
||||
void set_gametype(const std::string& gametype)
|
||||
{
|
||||
set_dvar("g_gametype", gametype);
|
||||
assert(!gametype.empty());
|
||||
|
||||
auto* g_gametype = game::Dvar_FindVar("g_gametype");
|
||||
game::Dvar_SetString(g_gametype, gametype.data());
|
||||
}
|
||||
|
||||
void launch_map(const std::string& mapname)
|
||||
{
|
||||
assert(!mapname.empty());
|
||||
|
||||
command::execute(utils::string::va("map %s", mapname.data()), false);
|
||||
}
|
||||
|
||||
void launch_default_map()
|
||||
{
|
||||
auto* mapname = game::Dvar_FindVar("mapname");
|
||||
if (mapname && mapname->current.string && strlen(mapname->current.string) && mapname->current.string !=
|
||||
"mp_vlobby_room"s)
|
||||
if (mapname && std::strcmp(mapname->current.string, "mp_vlobby_room") != 0)
|
||||
{
|
||||
launch_map(mapname->current.string);
|
||||
}
|
||||
@ -50,55 +55,113 @@ namespace map_rotation
|
||||
}
|
||||
}
|
||||
|
||||
std::string load_current_map_rotation()
|
||||
void apply_rotation(rotation_data& rotation)
|
||||
{
|
||||
auto* rotation = game::Dvar_FindVar("sv_mapRotationCurrent");
|
||||
if (!strlen(rotation->current.string))
|
||||
assert(!rotation.empty());
|
||||
|
||||
std::size_t i = 0;
|
||||
while (i < rotation.get_entries_size())
|
||||
{
|
||||
rotation = game::Dvar_FindVar("sv_mapRotation");
|
||||
set_dvar("sv_mapRotationCurrent", rotation->current.string);
|
||||
}
|
||||
|
||||
return rotation->current.string;
|
||||
}
|
||||
|
||||
std::vector<std::string> parse_current_map_rotation()
|
||||
{
|
||||
const auto rotation = load_current_map_rotation();
|
||||
return utils::string::split(rotation, ' ');
|
||||
}
|
||||
|
||||
void store_new_rotation(const std::vector<std::string>& elements, const size_t index)
|
||||
{
|
||||
std::string value{};
|
||||
|
||||
for (auto i = index; i < elements.size(); ++i)
|
||||
{
|
||||
if (i != index)
|
||||
const auto& entry = rotation.get_next_entry();
|
||||
if (entry.first == "map"s)
|
||||
{
|
||||
value.push_back(' ');
|
||||
console::info("Loading new map: '%s'\n", entry.second.data());
|
||||
if (!game::SV_MapExists(entry.second.data()))
|
||||
{
|
||||
console::info("map_rotation: '%s' map doesn't exist!\n", entry.second.data());
|
||||
launch_default_map();
|
||||
return;
|
||||
}
|
||||
|
||||
launch_map(entry.second);
|
||||
|
||||
// Map was found so we exit the loop
|
||||
break;
|
||||
}
|
||||
|
||||
value.append(elements[i]);
|
||||
if (entry.first == "gametype"s)
|
||||
{
|
||||
console::info("Applying new gametype: '%s'\n", entry.second.data());
|
||||
set_gametype(entry.second);
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
set_dvar("sv_mapRotationCurrent", value);
|
||||
if (i == rotation.get_entries_size())
|
||||
{
|
||||
console::error("Map rotation does not contain any map. Restarting\n");
|
||||
launch_default_map();
|
||||
}
|
||||
}
|
||||
|
||||
void change_process_priority()
|
||||
void load_rotation(const std::string& data)
|
||||
{
|
||||
auto* const dvar = game::Dvar_FindVar("sv_autoPriority");
|
||||
if (dvar && dvar->current.enabled)
|
||||
static auto loaded = false;
|
||||
if (loaded)
|
||||
{
|
||||
scheduler::on_game_initialized([]()
|
||||
{
|
||||
//printf("=======================setting OLD priority=======================\n");
|
||||
SetPriorityClass(GetCurrentProcess(), previousPriority);
|
||||
}, scheduler::pipeline::main, 1s);
|
||||
return;
|
||||
}
|
||||
|
||||
previousPriority = GetPriorityClass(GetCurrentProcess());
|
||||
//printf("=======================setting NEW priority=======================\n");
|
||||
SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
|
||||
loaded = true;
|
||||
try
|
||||
{
|
||||
dedicated_rotation.parse(data);
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
console::error("%s: %s contains invalid data!\n", ex.what(), sv_map_rotation->name);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
console::info("dedicated_rotation size after parsing is '%llu'", dedicated_rotation.get_entries_size());
|
||||
#endif
|
||||
}
|
||||
|
||||
void load_map_rotation()
|
||||
{
|
||||
const std::string map_rotation = sv_map_rotation->current.string;
|
||||
if (!map_rotation.empty())
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
console::info("%s is not empty. Parsing...\n", sv_map_rotation->name);
|
||||
#endif
|
||||
load_rotation(map_rotation);
|
||||
}
|
||||
}
|
||||
|
||||
void apply_map_rotation_current(const std::string& data)
|
||||
{
|
||||
assert(!data.empty());
|
||||
|
||||
rotation_data rotation_current;
|
||||
|
||||
try
|
||||
{
|
||||
rotation_current.parse(data);
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
console::error("%s: %s contains invalid data!\n", ex.what(), sv_map_rotation_current->name);
|
||||
}
|
||||
|
||||
game::Dvar_SetString(sv_map_rotation_current, "");
|
||||
|
||||
if (rotation_current.empty())
|
||||
{
|
||||
console::warn("%s is empty or contains invalid data\n", sv_map_rotation_current->name);
|
||||
launch_default_map();
|
||||
return;
|
||||
}
|
||||
|
||||
apply_rotation(rotation_current);
|
||||
}
|
||||
|
||||
void randomize_map_rotation()
|
||||
{
|
||||
if (sv_random_map_rotation->current.enabled)
|
||||
{
|
||||
console::info("Randomizing the map rotation\n");
|
||||
dedicated_rotation.randomize();
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,42 +173,35 @@ namespace map_rotation
|
||||
return;
|
||||
}
|
||||
|
||||
const auto rotation = parse_current_map_rotation();
|
||||
console::info("Rotating map...\n");
|
||||
|
||||
for (size_t i = 0; !rotation.empty() && i < (rotation.size() - 1); i += 2)
|
||||
// This takes priority because of backwards compatibility
|
||||
const std::string map_rotation_current = sv_map_rotation_current->current.string;
|
||||
if (!map_rotation_current.empty())
|
||||
{
|
||||
const auto& key = rotation[i];
|
||||
const auto& value = rotation[i + 1];
|
||||
|
||||
if (key == "gametype")
|
||||
{
|
||||
set_gametype(value);
|
||||
}
|
||||
else if (key == "map")
|
||||
{
|
||||
store_new_rotation(rotation, i + 2);
|
||||
change_process_priority();
|
||||
if (!game::SV_MapExists(value.data()))
|
||||
{
|
||||
console::info("map_rotation: '%s' map doesn't exist!\n", value.data());
|
||||
launch_default_map();
|
||||
return;
|
||||
}
|
||||
launch_map(value);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
console::info("Invalid map rotation key: %s\n", key.data());
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
console::info("Applying %s\n", sv_map_rotation_current->name);
|
||||
#endif
|
||||
apply_map_rotation_current(map_rotation_current);
|
||||
return;
|
||||
}
|
||||
|
||||
launch_default_map();
|
||||
load_map_rotation();
|
||||
if (dedicated_rotation.empty())
|
||||
{
|
||||
console::warn("%s is empty or contains invalid data. Restarting map\n", sv_map_rotation->name);
|
||||
launch_default_map();
|
||||
return;
|
||||
}
|
||||
|
||||
randomize_map_rotation();
|
||||
|
||||
apply_rotation(dedicated_rotation);
|
||||
}
|
||||
|
||||
void trigger_map_rotation()
|
||||
{
|
||||
scheduler::schedule([]()
|
||||
scheduler::schedule([]
|
||||
{
|
||||
if (game::CL_IsCgameInitialized())
|
||||
{
|
||||
@ -159,6 +215,68 @@ namespace map_rotation
|
||||
|
||||
}
|
||||
|
||||
rotation_data::rotation_data()
|
||||
: index_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void rotation_data::randomize()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
|
||||
std::ranges::shuffle(this->rotation_entries_, gen);
|
||||
}
|
||||
|
||||
void rotation_data::add_entry(const std::string& key, const std::string& value)
|
||||
{
|
||||
this->rotation_entries_.emplace_back(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
bool rotation_data::contains(const std::string& key, const std::string& value) const
|
||||
{
|
||||
return std::ranges::any_of(this->rotation_entries_, [&](const auto& entry)
|
||||
{
|
||||
return entry.first == key && entry.second == value;
|
||||
});
|
||||
}
|
||||
|
||||
bool rotation_data::empty() const noexcept
|
||||
{
|
||||
return this->rotation_entries_.empty();
|
||||
}
|
||||
|
||||
std::size_t rotation_data::get_entries_size() const noexcept
|
||||
{
|
||||
return this->rotation_entries_.size();
|
||||
}
|
||||
|
||||
rotation_data::rotation_entry& rotation_data::get_next_entry()
|
||||
{
|
||||
const auto index = this->index_;
|
||||
++this->index_ %= this->rotation_entries_.size();
|
||||
return this->rotation_entries_.at(index);
|
||||
}
|
||||
|
||||
void rotation_data::parse(const std::string& data)
|
||||
{
|
||||
const auto tokens = utils::string::split(data, ' ');
|
||||
for (std::size_t i = 0; !tokens.empty() && i < (tokens.size() - 1); i += 2)
|
||||
{
|
||||
const auto& key = tokens[i];
|
||||
const auto& value = tokens[i + 1];
|
||||
|
||||
if (key == "map"s || key == "gametype"s)
|
||||
{
|
||||
this->add_entry(key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw map_rotation_parse_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
@ -169,19 +287,18 @@ namespace map_rotation
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler::once([]()
|
||||
scheduler::once([]
|
||||
{
|
||||
game::Dvar_RegisterString("sv_mapRotation", "", game::DVAR_FLAG_NONE, "");
|
||||
game::Dvar_RegisterString("sv_mapRotationCurrent", "", game::DVAR_FLAG_NONE, "");
|
||||
game::Dvar_RegisterBool("sv_autoPriority", true, game::DVAR_FLAG_NONE, "Lowers the process priority during map changes to not cause lags on other servers.");
|
||||
sv_map_rotation = game::Dvar_RegisterString("sv_mapRotation", "", game::DVAR_FLAG_NONE, "");
|
||||
sv_map_rotation_current = game::Dvar_RegisterString("sv_mapRotationCurrent", "", game::DVAR_FLAG_NONE, "");
|
||||
}, scheduler::pipeline::main);
|
||||
|
||||
sv_random_map_rotation = game::Dvar_RegisterBool("sv_randomMapRotation", false, game::DVAR_FLAG_NONE, "Randomize map rotation");
|
||||
|
||||
command::add("map_rotate", &perform_map_rotation);
|
||||
|
||||
// Hook GScr_ExitLevel
|
||||
utils::hook::jump(0x14032E490, &trigger_map_rotation);
|
||||
|
||||
previousPriority = GetPriorityClass(GetCurrentProcess());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
34
src/client/component/map_rotation.hpp
Normal file
34
src/client/component/map_rotation.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
namespace map_rotation
|
||||
{
|
||||
struct map_rotation_parse_error : public std::exception
|
||||
{
|
||||
[[nodiscard]] const char* what() const noexcept override { return "Map Rotation Parse Erro"; }
|
||||
};
|
||||
|
||||
class rotation_data
|
||||
{
|
||||
public:
|
||||
using rotation_entry = std::pair<std::string, std::string>;
|
||||
|
||||
rotation_data();
|
||||
|
||||
void randomize();
|
||||
|
||||
// In case a new way to enrich the map rotation is added (other than sv_mapRotation)
|
||||
// this method should be called to add a new entry (gamemode/map & value)
|
||||
void add_entry(const std::string& key, const std::string& value);
|
||||
|
||||
[[nodiscard]] bool contains(const std::string& key, const std::string& value) const;
|
||||
[[nodiscard]] bool empty() const noexcept;
|
||||
[[nodiscard]] std::size_t get_entries_size() const noexcept;
|
||||
[[nodiscard]] rotation_entry& get_next_entry();
|
||||
|
||||
void parse(const std::string& data);
|
||||
|
||||
private:
|
||||
std::vector<rotation_entry> rotation_entries_;
|
||||
std::size_t index_;
|
||||
};
|
||||
}
|
@ -243,10 +243,10 @@ namespace network
|
||||
utils::hook::call(0x140439D98, &net_compare_address);
|
||||
|
||||
// increase cl_maxpackets
|
||||
dvars::override::Dvar_RegisterInt("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED);
|
||||
|
||||
// increase snaps
|
||||
dvars::override::Dvar_RegisterInt("sv_remote_client_snapshot_msec", 33, 33, 100, game::DVAR_FLAG_NONE);
|
||||
dvars::override::register_int("sv_remote_client_snapshot_msec", 33, 33, 100, game::DVAR_FLAG_NONE);
|
||||
|
||||
// ignore impure client
|
||||
utils::hook::jump(0x14043AC0D, reinterpret_cast<void*>(0x14043ACA3));
|
||||
|
@ -187,13 +187,15 @@ namespace notifies
|
||||
message.erase(message.begin());
|
||||
}
|
||||
|
||||
scheduler::once([params, message, client_num]
|
||||
scheduler::once([params, message, msg_index, client_num]
|
||||
{
|
||||
const scripting::entity level{*game::levelEntityId};
|
||||
const auto player = scripting::call("getEntByNum", {client_num}).as<scripting::entity>();
|
||||
// Remove \x1F before sending the notify only if present
|
||||
const auto notify_msg = msg_index ? message.substr(1) : message;
|
||||
|
||||
notify(level, params[0], {player, message});
|
||||
notify(player, params[0], {message});
|
||||
notify(level, params[0], {player, notify_msg});
|
||||
notify(player, params[0], {notify_msg});
|
||||
|
||||
game_log::g_log_printf("%s;%s;%i;%s;%s\n",
|
||||
params[0],
|
||||
|
@ -286,15 +286,15 @@ namespace patches
|
||||
utils::hook::set(0x14023BDC0, 0xC3C033);
|
||||
|
||||
// disable emblems
|
||||
dvars::override::Dvar_RegisterInt("emblems_active", 0, 0, 0, game::DVAR_FLAG_NONE);
|
||||
dvars::override::register_int("emblems_active", 0, 0, 0, game::DVAR_FLAG_NONE);
|
||||
utils::hook::set<uint8_t>(0x140479590, 0xC3); // don't register commands
|
||||
|
||||
// disable elite_clan
|
||||
dvars::override::Dvar_RegisterInt("elite_clan_active", 0, 0, 0, game::DVAR_FLAG_NONE);
|
||||
dvars::override::register_int("elite_clan_active", 0, 0, 0, game::DVAR_FLAG_NONE);
|
||||
utils::hook::set<uint8_t>(0x14054AB20, 0xC3); // don't register commands
|
||||
|
||||
// disable codPointStore
|
||||
dvars::override::Dvar_RegisterInt("codPointStore_enabled", 0, 0, 0, game::DVAR_FLAG_NONE);
|
||||
dvars::override::register_int("codPointStore_enabled", 0, 0, 0, game::DVAR_FLAG_NONE);
|
||||
|
||||
// don't register every replicated dvar as a network dvar
|
||||
utils::hook::nop(0x1403534BE, 5); // dvar_foreach
|
||||
@ -309,27 +309,27 @@ namespace patches
|
||||
utils::hook::set<uint8_t>(0x14019B9B9, 0xEB);
|
||||
|
||||
// some anti tamper thing that kills performance
|
||||
dvars::override::Dvar_RegisterInt("dvl", 0, 0, 0, game::DVAR_FLAG_READ);
|
||||
dvars::override::register_int("dvl", 0, 0, 0, game::DVAR_FLAG_READ);
|
||||
|
||||
// unlock safeArea_*
|
||||
utils::hook::jump(0x140219F5E, 0x140219F67);
|
||||
utils::hook::jump(0x140219F80, 0x140219F8E);
|
||||
dvars::override::Dvar_RegisterFloat("safeArea_adjusted_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::Dvar_RegisterFloat("safeArea_adjusted_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::Dvar_RegisterFloat("safeArea_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::Dvar_RegisterFloat("safeArea_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::register_float("safeArea_adjusted_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::register_float("safeArea_adjusted_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::register_float("safeArea_horizontal", 1, 0, 1, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::register_float("safeArea_vertical", 1, 0, 1, game::DVAR_FLAG_SAVED);
|
||||
|
||||
// move chat position on the screen above menu splashes
|
||||
dvars::override::Dvar_RegisterVector2("cg_hudChatPosition", 5, 170, 0, 640, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::register_vector2("cg_hudChatPosition", 5, 170, 0, 640, game::DVAR_FLAG_SAVED);
|
||||
|
||||
// allow servers to check for new packages more often
|
||||
dvars::override::Dvar_RegisterInt("sv_network_fps", 1000, 20, 1000, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::register_int("sv_network_fps", 1000, 20, 1000, game::DVAR_FLAG_SAVED);
|
||||
|
||||
// Massively increate timeouts
|
||||
dvars::override::Dvar_RegisterInt("cl_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // Seems unused
|
||||
dvars::override::Dvar_RegisterInt("sv_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // 30 - 0 - 1800
|
||||
dvars::override::Dvar_RegisterInt("cl_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // Seems unused
|
||||
dvars::override::Dvar_RegisterInt("sv_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // 60 - 0 - 1800
|
||||
dvars::override::register_int("cl_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // Seems unused
|
||||
dvars::override::register_int("sv_timeout", 90, 90, 1800, game::DVAR_FLAG_NONE); // 30 - 0 - 1800
|
||||
dvars::override::register_int("cl_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // Seems unused
|
||||
dvars::override::register_int("sv_connectTimeout", 120, 120, 1800, game::DVAR_FLAG_NONE); // 60 - 0 - 1800
|
||||
|
||||
game::Dvar_RegisterInt("scr_game_spectatetype", 1, 0, 99, game::DVAR_FLAG_REPLICATED, "");
|
||||
|
||||
|
@ -23,12 +23,12 @@ namespace ranked
|
||||
|
||||
if (game::environment::is_mp())
|
||||
{
|
||||
dvars::override::Dvar_RegisterBool("xblive_privatematch", false, game::DVAR_FLAG_REPLICATED);
|
||||
dvars::override::register_bool("xblive_privatematch", false, game::DVAR_FLAG_REPLICATED);
|
||||
}
|
||||
|
||||
if (game::environment::is_dedi() && !utils::flags::has_flag("unranked"))
|
||||
{
|
||||
dvars::override::Dvar_RegisterBool("xblive_privatematch", false, game::DVAR_FLAG_REPLICATED | game::DVAR_FLAG_WRITE);
|
||||
dvars::override::register_bool("xblive_privatematch", false, game::DVAR_FLAG_REPLICATED | game::DVAR_FLAG_WRITE);
|
||||
|
||||
// Some dvar used in gsc
|
||||
game::Dvar_RegisterBool("force_ranking", true, game::DVAR_FLAG_WRITE, "Force ranking");
|
||||
|
@ -91,6 +91,7 @@ namespace scripting
|
||||
{
|
||||
script_function_table_sort.clear();
|
||||
script_function_table.clear();
|
||||
script_function_table_rev.clear();
|
||||
canonical_string_table.clear();
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,8 @@ namespace game
|
||||
WEAK symbol<bool(const char* name)> Dvar_IsValidName{0x140370CB0, 0x1404BFF70};
|
||||
WEAK symbol<void(dvar_t* dvar, DvarSetSource source)> Dvar_Reset{0x140372950, 0x1404C1DB0};
|
||||
WEAK symbol<void(const char* dvar, const char* buffer)> Dvar_SetCommand{0x1403730D0, 0x1404C2520};
|
||||
WEAK symbol<void(dvar_t* dvar, const char* string)> Dvar_SetString{0x140373DE0, 0x1404C3610};
|
||||
WEAK symbol<void(const dvar_t* dvar, const char* string)> Dvar_SetString{0x140373DE0, 0x1404C3610};
|
||||
WEAK symbol<void(const dvar_t* dvar, bool value)> Dvar_SetBool{0x0, 0x1404C1F30};
|
||||
WEAK symbol<void(const char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{0x1403737D0, 0x1404C2E40};
|
||||
WEAK symbol<const char*(dvar_t* dvar, dvar_value value)> Dvar_ValueToString{0x140374E10, 0x1404C47B0};
|
||||
|
||||
@ -217,8 +218,8 @@ namespace game
|
||||
|
||||
WEAK symbol<const char*()> SEH_GetCurrentLanguageName{0x140339300, 0x1404745C0};
|
||||
|
||||
WEAK symbol<void*(unsigned int size, unsigned int alignment, unsigned int type, int source)> PMem_AllocFromSource_NoDebug{0x0, 0x1404C7BA0};
|
||||
WEAK symbol<void*(unsigned int size)> Hunk_AllocateTempMemoryHighInternal{0x0, 0x1404B68B0};
|
||||
WEAK symbol<void*(unsigned int size, unsigned int alignment, unsigned int type, int source)> PMem_AllocFromSource_NoDebug{0x1403775F0, 0x1404C7BA0};
|
||||
WEAK symbol<void*(unsigned int size)> Hunk_AllocateTempMemoryHighInternal{0x140369D60, 0x1404B68B0};
|
||||
|
||||
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14059C5C0, 0x1406FD930};
|
||||
WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x14059CD00, 0x1406FE070};
|
||||
|
@ -2,41 +2,65 @@
|
||||
#include "html_frame.hpp"
|
||||
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
std::atomic<int> html_frame::frame_count_ = 0;
|
||||
|
||||
namespace
|
||||
{
|
||||
void* original_func{};
|
||||
GUID browser_emulation_guid{ 0xac969931, 0x3566, 0x4b50, {0xae, 0x48, 0x71, 0xb9, 0x6a, 0x75, 0xc8, 0x79} };
|
||||
|
||||
int WINAPI co_internet_feature_value_internal_stub(const GUID* guid, uint32_t* result)
|
||||
{
|
||||
const auto res = static_cast<decltype(co_internet_feature_value_internal_stub)*>(original_func)(guid, result);
|
||||
|
||||
if (IsEqualGUID(*guid, browser_emulation_guid))
|
||||
{
|
||||
*result = 11000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void setup_ie_hook()
|
||||
{
|
||||
static const auto _ = []
|
||||
{
|
||||
const auto urlmon = utils::nt::library::load("urlmon.dll"s);
|
||||
const auto target = urlmon.get_iat_entry("iertutil.dll", MAKEINTRESOURCEA(700));
|
||||
|
||||
original_func = *target;
|
||||
utils::hook::set(target, co_internet_feature_value_internal_stub);
|
||||
|
||||
return 0;
|
||||
}();
|
||||
(void)_;
|
||||
}
|
||||
}
|
||||
|
||||
html_frame::callback_params::callback_params(DISPPARAMS* params, VARIANT* res) : result(res)
|
||||
{
|
||||
for (auto i = params->cArgs; i > 0; --i)
|
||||
{
|
||||
auto* param = ¶ms->rgvarg[i - 1];
|
||||
auto param = ¶ms->rgvarg[i - 1];
|
||||
this->arguments.emplace_back(param);
|
||||
}
|
||||
}
|
||||
|
||||
html_frame::html_frame()
|
||||
: in_place_frame_(this)
|
||||
, in_place_site_(this)
|
||||
, ui_handler_(this)
|
||||
, client_site_(this)
|
||||
, html_dispatch_(this)
|
||||
html_frame::html_frame() : in_place_frame_(this), in_place_site_(this), ui_handler_(this), client_site_(this),
|
||||
html_dispatch_(this)
|
||||
{
|
||||
setup_ie_hook();
|
||||
if (frame_count_++ == 0 && OleInitialize(nullptr) != S_OK)
|
||||
{
|
||||
throw std::runtime_error("Unable to initialize the OLE library");
|
||||
}
|
||||
|
||||
auto needs_restart = false;
|
||||
needs_restart |= set_browser_feature("FEATURE_BROWSER_EMULATION", 11000);
|
||||
needs_restart |= set_browser_feature("FEATURE_GPU_RENDERING", 1);
|
||||
|
||||
if (needs_restart)
|
||||
{
|
||||
utils::nt::relaunch_self();
|
||||
utils::nt::terminate(0);
|
||||
}
|
||||
set_browser_feature("FEATURE_BROWSER_EMULATION", 11000);
|
||||
set_browser_feature("FEATURE_GPU_RENDERING", 1);
|
||||
}
|
||||
|
||||
html_frame::~html_frame()
|
||||
{
|
||||
if (--frame_count_ <= 0)
|
||||
|
@ -55,25 +55,27 @@
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
#include <ranges>
|
||||
#include <map>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <optional>
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <random>
|
||||
#include <ranges>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <gsl/gsl>
|
||||
#include <udis86.h>
|
||||
|
@ -76,10 +76,7 @@ namespace utils
|
||||
|
||||
void memory::free(void* data)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
std::free(data);
|
||||
}
|
||||
std::free(data);
|
||||
}
|
||||
|
||||
void memory::free(const void* data)
|
||||
|
@ -15,7 +15,8 @@ namespace utils::nt
|
||||
library library::get_by_address(void* address)
|
||||
{
|
||||
HMODULE handle = nullptr;
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast<LPCSTR>(address), &handle);
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
static_cast<LPCSTR>(address), &handle);
|
||||
return library(handle);
|
||||
}
|
||||
|
||||
@ -157,6 +158,11 @@ namespace utils::nt
|
||||
}
|
||||
|
||||
void** library::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
|
||||
{
|
||||
return this->get_iat_entry(module_name, proc_name.data());
|
||||
}
|
||||
|
||||
void** library::get_iat_entry(const std::string& module_name, const char* proc_name) const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
|
||||
@ -166,7 +172,7 @@ namespace utils::nt
|
||||
auto* const target_function = other_module.get_proc<void*>(proc_name);
|
||||
if (!target_function) return nullptr;
|
||||
|
||||
auto* header = this->get_optional_header();
|
||||
const auto* header = this->get_optional_header();
|
||||
if (!header) return nullptr;
|
||||
|
||||
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
|
||||
@ -183,16 +189,22 @@ namespace utils::nt
|
||||
|
||||
while (original_thunk_data->u1.AddressOfData)
|
||||
{
|
||||
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
|
||||
|
||||
if (ordinal_number > 0xFFFF) continue;
|
||||
|
||||
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) ==
|
||||
target_function)
|
||||
if (thunk_data->u1.Function == reinterpret_cast<uint64_t>(target_function))
|
||||
{
|
||||
return reinterpret_cast<void**>(&thunk_data->u1.Function);
|
||||
}
|
||||
|
||||
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
|
||||
|
||||
if (ordinal_number <= 0xFFFF)
|
||||
{
|
||||
auto* proc = GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number));
|
||||
if (reinterpret_cast<void*>(proc) == target_function)
|
||||
{
|
||||
return reinterpret_cast<void**>(&thunk_data->u1.Function);
|
||||
}
|
||||
}
|
||||
|
||||
++original_thunk_data;
|
||||
++thunk_data;
|
||||
}
|
||||
|
@ -59,6 +59,13 @@ namespace utils::nt
|
||||
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get_proc(const char* name) const
|
||||
{
|
||||
if (!this->is_valid()) T{};
|
||||
return reinterpret_cast<T>(GetProcAddress(this->module_, name));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::function<T> get(const std::string& process) const
|
||||
{
|
||||
@ -97,6 +104,7 @@ namespace utils::nt
|
||||
PIMAGE_OPTIONAL_HEADER get_optional_header() const;
|
||||
|
||||
void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const;
|
||||
void** get_iat_entry(const std::string& module_name, const char* name) const;
|
||||
|
||||
private:
|
||||
HMODULE module_;
|
||||
|
@ -34,24 +34,26 @@ namespace utils::string
|
||||
return elems;
|
||||
}
|
||||
|
||||
std::string to_lower(std::string text)
|
||||
std::string to_lower(const std::string& text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const unsigned char input)
|
||||
std::string result;
|
||||
std::ranges::transform(text, std::back_inserter(result), [](const unsigned char input)
|
||||
{
|
||||
return static_cast<char>(std::tolower(input));
|
||||
});
|
||||
|
||||
return text;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_upper(std::string text)
|
||||
std::string to_upper(const std::string& text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const unsigned char input)
|
||||
std::string result;
|
||||
std::ranges::transform(text, std::back_inserter(result), [](const unsigned char input)
|
||||
{
|
||||
return static_cast<char>(std::toupper(input));
|
||||
});
|
||||
|
||||
return text;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool starts_with(const std::string& text, const std::string& substring)
|
||||
|
@ -2,10 +2,8 @@
|
||||
#include "memory.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
template <class Type, size_t n>
|
||||
size_t ARRAYSIZE(Type (&)[n]) { return n; }
|
||||
#endif
|
||||
constexpr auto ARRAY_COUNT(Type(&)[n]) { return n; }
|
||||
|
||||
namespace utils::string
|
||||
{
|
||||
@ -21,7 +19,7 @@ namespace utils::string
|
||||
|
||||
char* get(const char* format, const va_list ap)
|
||||
{
|
||||
++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
|
||||
++this->current_buffer_ %= ARRAY_COUNT(this->string_pool_);
|
||||
auto entry = &this->string_pool_[this->current_buffer_];
|
||||
|
||||
if (!entry->size || !entry->buffer)
|
||||
@ -82,8 +80,8 @@ namespace utils::string
|
||||
|
||||
std::vector<std::string> split(const std::string& s, char delim);
|
||||
|
||||
std::string to_lower(std::string text);
|
||||
std::string to_upper(std::string text);
|
||||
std::string to_lower(const std::string& text);
|
||||
std::string to_upper(const std::string& text);
|
||||
bool starts_with(const std::string& text, const std::string& substring);
|
||||
bool ends_with(const std::string& text, const std::string& substring);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user