From 7d436ac0c5614639042ac0871df3dea45ff504b3 Mon Sep 17 00:00:00 2001 From: xerxes-at <5236639+xerxes-at@users.noreply.github.com> Date: Mon, 29 May 2023 03:15:52 +0200 Subject: [PATCH] Fix Game Interface / AC Callbacks + support for T5ZM, T6MP and T6ZM for the Game Interface. (#288) * Fix trying to write to a struct before its initialized. Same issue on IW4, IW5 and T5 game modules. * Fix path issues in the scripts + add support for t5zm. * Fix deploy.bat * Change paths inside the gsc scripts used to call functions in other scripts * Remove mp includes from base gsc file. #include maps\mp\_utility; #include maps\mp\gametypes\_hud_util; * Define GetXuid as overrideMethod as t5zm doesn't have it. * Define GetPlayerFromClientNum as getting all players is slightly different on t5zm. * Remove the precompiled gsc file for T6 as PlutoT6 can load uncompiled GSC now. * Fix _customcallbacks.gsc for T6 * Add T6 support to the game interface. * Update _integration_base.gsc use camelCase for functionName * Make sure the Setup functions are always called in the right order. Base -> shared -> game Otherwise we might write to structs before they are created. * Move functions interacting with the game from _base to _shared GetPlayerFromClientNum OnPlayerJoinedTeam OnPlayerJoinedSpectators GenerateJoinTeamString PlayerTrackingOnInterval SaveTrackingMetrics * Block execution until game specific setup is done Block _shared execution until the game specific file finished. This allows the game specific file to override the events in _shared. * Fix setup event flow Move check of sv_iw4madmin_integration_enabled dvar after waittill in _shared so _base has a chance to set it to 1. Move check of sv_iw4madmin_autobalance dvar to OnPlayerConnect in _shared so the game specific script has a chance to set the dvar. * ignore bots * add more spaces --- .../t6/scripts/mp/_customcallbacks.gsc | Bin 5522 -> 6696 bytes .../t6/scripts/mp/_customcallbacks.gsc.src | 263 -------- GameFiles/GameInterface/_integration_base.gsc | 138 +---- GameFiles/GameInterface/_integration_iw4x.gsc | 13 +- GameFiles/GameInterface/_integration_iw5.gsc | 47 +- .../GameInterface/_integration_shared.gsc | 147 ++++- GameFiles/GameInterface/_integration_t5.gsc | 51 +- GameFiles/GameInterface/_integration_t5zm.gsc | 552 +++++++++++++++++ GameFiles/GameInterface/_integration_t6.gsc | 571 ++++++++++++++++++ .../_integration_t6zm_helper.gsc | 86 +++ GameFiles/deploy.bat | 14 +- Plugins/ScriptPlugins/GameInterface.js | 22 +- 12 files changed, 1446 insertions(+), 458 deletions(-) delete mode 100644 GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc.src create mode 100644 GameFiles/GameInterface/_integration_t5zm.gsc create mode 100644 GameFiles/GameInterface/_integration_t6.gsc create mode 100644 GameFiles/GameInterface/_integration_t6zm_helper.gsc diff --git a/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc b/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc index 909b029219601f7f5d88d23fa23a00cff3c5a0e9..133a6a59f366d87646ca71643872a1dd4e1cf06f 100644 GIT binary patch literal 6696 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 IT(}ed7n)%BwEzGB diff --git a/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc.src b/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc.src deleted file mode 100644 index fbdf34fff..000000000 --- a/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc.src +++ /dev/null @@ -1,263 +0,0 @@ -#include maps\mp\_utility; -#include maps\mp\gametypes\_hud_util; -#include common_scripts\utility; - -init() -{ - SetDvarIfUninitialized( "sv_customcallbacks", true ); - SetDvarIfUninitialized( "sv_framewaittime", 0.05 ); - SetDvarIfUninitialized( "sv_additionalwaittime", 0.1 ); - SetDvarIfUninitialized( "sv_maxstoredframes", 12 ); - SetDvarIfUninitialized( "sv_printradarupdates", 0 ); - SetDvarIfUninitialized( "sv_printradar_updateinterval", 500 ); - SetDvarIfUninitialized( "sv_iw4madmin_url", "http://127.0.0.1:1624" ); - - level thread onPlayerConnect(); - if (getDvarInt("sv_printradarupdates") == 1) - { - level thread runRadarUpdates(); - } - - level waittill( "prematch_over" ); - level.callbackPlayerKilled = ::Callback_PlayerKilled; - level.callbackPlayerDamage = ::Callback_PlayerDamage; - level.callbackPlayerDisconnect = ::Callback_PlayerDisconnect; -} - -//It's called slightly different in T6 -//set_dvar_if_unset(dvar, val, reset) -SetDvarIfUninitialized(dvar, val) -{ - set_dvar_if_unset(dvar,val); -} - -onPlayerConnect( player ) -{ - for( ;; ) - { - level waittill( "connected", player ); - player thread waitForFrameThread(); - player thread waitForAttack(); - } -} - -//Got added to T6 on April 2020 -waitForAttack() -{ - self endon( "disconnect" ); - - self notifyOnPlayerCommand( "player_shot", "+attack" ); - self.lastAttackTime = 0; - - for( ;; ) - { - self waittill( "player_shot" ); - - self.lastAttackTime = getTime(); - } -} - -runRadarUpdates() -{ - interval = getDvarInt( "sv_printradar_updateinterval" ); - - for ( ;; ) - { - for ( i = 0; i <= 17; i++ ) - { - player = level.players[i]; - - if ( isDefined( player ) ) - { - payload = player.guid + ";" + player.origin + ";" + player getPlayerAngles() + ";" + player.team + ";" + player.kills + ";" + player.deaths + ";" + player.score + ";" + player GetCurrentWeapon() + ";" + player.health + ";" + isAlive(player) + ";" + player.timePlayed["total"]; - logPrint( "LiveRadar;" + payload + "\n" ); - } - } - - wait( interval / 1000 ); - } -} - -hitLocationToBone( hitloc ) -{ - switch( hitloc ) - { - case "helmet": - return "j_helmet"; - case "head": - return "j_head"; - case "neck": - return "j_neck"; - case "torso_upper": - return "j_spineupper"; - case "torso_lower": - return "j_spinelower"; - case "right_arm_upper": - return "j_shoulder_ri"; - case "left_arm_upper": - return "j_shoulder_le"; - case "right_arm_lower": - return "j_elbow_ri"; - case "left_arm_lower": - return "j_elbow_le"; - case "right_hand": - return "j_wrist_ri"; - case "left_hand": - return "j_wrist_le"; - case "right_leg_upper": - return "j_hip_ri"; - case "left_leg_upper": - return "j_hip_le"; - case "right_leg_lower": - return "j_knee_ri"; - case "left_leg_lower": - return "j_knee_le"; - case "right_foot": - return "j_ankle_ri"; - case "left_foot": - return "j_ankle_le"; - default: - return "tag_origin"; - } -} - -waitForFrameThread() -{ - self endon( "disconnect" ); - - self.currentAnglePosition = 0; - self.anglePositions = []; - - for (i = 0; i < getDvarInt( "sv_maxstoredframes" ); i++) - { - self.anglePositions[i] = self getPlayerAngles(); - } - - for( ;; ) - { - self.anglePositions[self.currentAnglePosition] = self getPlayerAngles(); - wait( getDvarFloat( "sv_framewaittime" ) ); - self.currentAnglePosition = (self.currentAnglePosition + 1) % getDvarInt( "sv_maxstoredframes" ); - } -} - -waitForAdditionalAngles( logString, beforeFrameCount, afterFrameCount ) -{ - currentIndex = self.currentAnglePosition; - wait( 0.05 * afterFrameCount ); - - self.angleSnapshot = []; - - for( j = 0; j < self.anglePositions.size; j++ ) - { - self.angleSnapshot[j] = self.anglePositions[j]; - } - - anglesStr = ""; - collectedFrames = 0; - i = currentIndex - beforeFrameCount; - - while (collectedFrames < beforeFrameCount) - { - fixedIndex = i; - if (i < 0) - { - fixedIndex = self.angleSnapshot.size - abs(i); - } - anglesStr += self.angleSnapshot[int(fixedIndex)] + ":"; - collectedFrames++; - i++; - } - - if (i == currentIndex) - { - anglesStr += self.angleSnapshot[i] + ":"; - i++; - } - - collectedFrames = 0; - - while (collectedFrames < afterFrameCount) - { - fixedIndex = i; - if (i > self.angleSnapshot.size - 1) - { - fixedIndex = i % self.angleSnapshot.size; - } - anglesStr += self.angleSnapshot[int(fixedIndex)] + ":"; - collectedFrames++; - i++; - } - - lastAttack = getTime() - self.lastAttackTime; - isAlive = isAlive(self); - - logPrint(logString + ";" + anglesStr + ";" + isAlive + ";" + lastAttack + "\n" ); -} - -vectorScale( vector, scale ) -{ - return ( vector[0] * scale, vector[1] * scale, vector[2] * scale ); -} - -Process_Hit( type, attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon ) -{ - if (sMeansOfDeath == "MOD_FALLING" || !isPlayer(attacker)) - { - return; - } - - victim = self; - _attacker = attacker; - - if ( !isPlayer( attacker ) && isDefined( attacker.owner ) ) - { - _attacker = attacker.owner; - } - - else if( !isPlayer( attacker ) && sMeansOfDeath == "MOD_FALLING" ) - { - _attacker = victim; - } - - location = victim GetTagOrigin( hitLocationToBone( sHitLoc ) ); - isKillstreakKill = false; - if(!isPlayer(attacker)) - { - isKillstreakKill = true; - } - if(maps/mp/killstreaks/_killstreaks::iskillstreakweapon(sWeapon)) - { - isKillstreakKill = true; - } - - logLine = "Script" + type + ";" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + int(gettime()) + ";" + isKillstreakKill + ";" + _attacker playerADS() + ";0;0"; - attacker thread waitForAdditionalAngles( logLine, 2, 2 ); -} - -Callback_PlayerDamage( eInflictor, attacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ) -{ - if ( level.teamBased && isDefined( attacker ) && ( self != attacker ) && isDefined( attacker.team ) && ( self.pers[ "team" ] == attacker.team ) ) - { - return; - } - - if ( self.health - iDamage > 0 ) - { - self Process_Hit( "Damage", attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon ); - } - - self [[maps/mp/gametypes/_globallogic_player::callback_playerdamage]]( eInflictor, attacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex ); -} - -Callback_PlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration) -{ - Process_Hit( "Kill", attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon ); - self [[maps/mp/gametypes/_globallogic_player::callback_playerkilled]]( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ); -} - -Callback_PlayerDisconnect() -{ - level notify( "disconnected", self ); - self [[maps/mp/gametypes/_globallogic_player::callback_playerdisconnect]](); -} \ No newline at end of file diff --git a/GameFiles/GameInterface/_integration_base.gsc b/GameFiles/GameInterface/_integration_base.gsc index ef16b1047..fac8a6688 100644 --- a/GameFiles/GameInterface/_integration_base.gsc +++ b/GameFiles/GameInterface/_integration_base.gsc @@ -1,6 +1,4 @@ #include common_scripts\utility; -#include maps\mp\_utility; -#include maps\mp\gametypes\_hud_util; Init() { @@ -19,14 +17,17 @@ Setup() level.eventBus.timeoutKey = "timeout"; level.eventBus.timeout = 30; - level.commonFunctions = spawnstruct(); - level.commonFunctions.setDvar = "SetDvarIfUninitialized"; - level.commonFunctions.isBot = "IsBot"; + level.commonFunctions = spawnstruct(); + level.commonFunctions.setDvar = "SetDvarIfUninitialized"; + level.commonFunctions.isBot = "IsBot"; + level.commonFunctions.getXuid = "GetXuid"; + level.commonFunctions.getPlayerFromClientNum = "GetPlayerFromClientNum"; level.commonKeys = spawnstruct(); level.notifyTypes = spawnstruct(); level.notifyTypes.gameFunctionsInitialized = "GameFunctionsInitialized"; + level.notifyTypes.sharedFunctionsInitialized = "SharedFunctionsInitialized"; level.notifyTypes.integrationBootstrapInitialized = "IntegrationBootstrapInitialized"; level.clientDataKey = "clientData"; @@ -102,9 +103,6 @@ OnPlayerConnect() } player thread OnPlayerSpawned(); - player thread OnPlayerJoinedTeam(); - player thread OnPlayerJoinedSpectators(); - player thread PlayerTrackingOnInterval(); } } @@ -119,30 +117,6 @@ OnPlayerSpawned() } } -OnPlayerJoinedTeam() -{ - self endon( "disconnect" ); - - for( ;; ) - { - self waittill( "joined_team" ); - // join spec and join team occur at the same moment - out of order logging would be problematic - wait( 0.25 ); - LogPrint( GenerateJoinTeamString( false ) ); - } -} - -OnPlayerJoinedSpectators() -{ - self endon( "disconnect" ); - - for( ;; ) - { - self waittill( "joined_spectators" ); - LogPrint( GenerateJoinTeamString( true ) ); - } -} - OnGameEnded() { for ( ;; ) @@ -187,20 +161,6 @@ PlayerSpawnEvents() self RequestClientBasicData(); } -PlayerTrackingOnInterval() -{ - self endon( "disconnect" ); - - for ( ;; ) - { - wait ( 120 ); - if ( IsAlive( self ) ) - { - self SaveTrackingMetrics(); - } - } -} - MonitorClientEvents() { level endon( "game_ended" ); @@ -344,37 +304,6 @@ DecrementClientMeta( metaKey, decrementValue, clientId ) SetClientMeta( metaKey, decrementValue, clientId, "decrement" ); } -GenerateJoinTeamString( isSpectator ) -{ - team = self.team; - - if ( IsDefined( self.joining_team ) ) - { - team = self.joining_team; - } - else - { - if ( isSpectator || !IsDefined( team ) ) - { - team = "spectator"; - } - } - - guid = self GetXuid(); - - if ( guid == "0" ) - { - guid = self.guid; - } - - if ( !IsDefined( guid ) || guid == "0" ) - { - guid = "undefined"; - } - - return "JT;" + guid + ";" + self getEntityNumber() + ";" + team + ";" + self.name + "\n"; -} - SetClientMeta( metaKey, metaValue, clientId, direction ) { data = "key=" + metaKey + "|value=" + metaValue; @@ -400,39 +329,6 @@ SetClientMeta( metaKey, metaValue, clientId, direction ) level thread QueueEvent( setClientMetaEvent, level.eventTypes.setClientDataRequested, self ); } -SaveTrackingMetrics() -{ - if ( !IsDefined( self.persistentClientId ) ) - { - return; - } - - LogDebug( "Saving tracking metrics for " + self.persistentClientId ); - - if ( !IsDefined( self.lastShotCount ) ) - { - self.lastShotCount = 0; - } - - currentShotCount = self [[level.overrideMethods["GetTotalShotsFired"]]](); - change = currentShotCount - self.lastShotCount; - self.lastShotCount = currentShotCount; - - LogDebug( "Total Shots Fired increased by " + change ); - - if ( !IsDefined( change ) ) - { - change = 0; - } - - if ( change == 0 ) - { - return; - } - - IncrementClientMeta( "TotalShotsFired", change, self.persistentClientId ); -} - BuildEventRequest( responseExpected, eventType, eventSubtype, entOrId, data ) { if ( !IsDefined( data ) ) @@ -565,8 +461,8 @@ NotifyClientEventTimeout( eventType ) NotifyClientEvent( eventInfo ) { - origin = getPlayerFromClientNum( int( eventInfo[3] ) ); - target = getPlayerFromClientNum( int( eventInfo[4] ) ); + origin = [[level.overrideMethods[level.commonFunctions.getPlayerFromClientNum]]]( int( eventInfo[3] ) ); + target = [[level.overrideMethods[level.commonFunctions.getPlayerFromClientNum]]]( int( eventInfo[4] ) ); event = spawnstruct(); event.type = eventInfo[1]; @@ -608,24 +504,6 @@ NotifyClientEvent( eventInfo ) level notify( level.eventTypes.localClientEvent, client ); } -GetPlayerFromClientNum( clientNum ) -{ - if ( clientNum < 0 ) - { - return undefined; - } - - for ( i = 0; i < level.players.size; i++ ) - { - if ( level.players[i] getEntityNumber() == clientNum ) - { - return level.players[i]; - } - } - - return undefined; -} - AddClientCommand( commandName, shouldRunAsTarget, callback, shouldOverwrite ) { if ( IsDefined( level.clientCommandCallbacks[commandName] ) && IsDefined( shouldOverwrite ) && !shouldOverwrite ) diff --git a/GameFiles/GameInterface/_integration_iw4x.gsc b/GameFiles/GameInterface/_integration_iw4x.gsc index 34970de19..a072e7347 100644 --- a/GameFiles/GameInterface/_integration_iw4x.gsc +++ b/GameFiles/GameInterface/_integration_iw4x.gsc @@ -2,8 +2,6 @@ Init() { - level.eventBus.gamename = "IW4"; - thread Setup(); } @@ -12,13 +10,15 @@ Setup() level endon( "game_ended" ); // it's possible that the notify type has not been defined yet so we have to hard code it - level waittill( "IntegrationBootstrapInitialized" ); + level waittill( "SharedFunctionsInitialized" ); + level.eventBus.gamename = "IW4"; scripts\_integration_base::RegisterLogger( ::Log2Console ); level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired; level.overrideMethods[level.commonFunctions.setDvar] = ::_SetDvarIfUninitialized; level.overrideMethods[level.commonFunctions.isBot] = ::IsTestClient; + level.overrideMethods[level.commonFunctions.getXuid] = ::_GetXUID; level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout; level.overrideMethods[level.commonFunctions.changeTeam] = ::ChangeTeam; level.overrideMethods[level.commonFunctions.getTeamCounts] = ::CountPlayers; @@ -31,6 +31,8 @@ Setup() RegisterClientCommands(); + _SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 ); + level notify( level.notifyTypes.gameFunctionsInitialized ); if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) @@ -199,6 +201,11 @@ Log2Console( logLevel, message ) PrintConsole( "[" + logLevel + "] " + message + "\n" ); } +_GetXUID() +{ + return self GetXUID(); +} + ////////////////////////////////// // GUID helpers ///////////////////////////////// diff --git a/GameFiles/GameInterface/_integration_iw5.gsc b/GameFiles/GameInterface/_integration_iw5.gsc index ed92e8c9b..75057e375 100644 --- a/GameFiles/GameInterface/_integration_iw5.gsc +++ b/GameFiles/GameInterface/_integration_iw5.gsc @@ -2,8 +2,6 @@ Init() { - level.eventBus.gamename = "IW5"; - thread Setup(); } @@ -12,17 +10,21 @@ Setup() level endon( "game_ended" ); // it's possible that the notify type has not been defined yet so we have to hard code it - level waittill( "IntegrationBootstrapInitialized" ); + level waittill( "SharedFunctionsInitialized" ); + level.eventBus.gamename = "IW5"; - scripts\mp\_integration_base::RegisterLogger( ::Log2Console ); + scripts\_integration_base::RegisterLogger( ::Log2Console ); level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired; level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized; level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout; level.overrideMethods[level.commonFunctions.isBot] = ::IsTestClient; + level.overrideMethods[level.commonFunctions.getXuid] = ::_GetXUID; RegisterClientCommands(); + _SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 ); + level notify( level.notifyTypes.gameFunctionsInitialized ); if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) @@ -54,17 +56,17 @@ OnPlayerConnect() RegisterClientCommands() { - scripts\mp\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl ); - scripts\mp\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl ); - scripts\mp\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl ); - scripts\mp\_integration_base::AddClientCommand( "Hide", false, ::HideImpl ); - scripts\mp\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl ); - scripts\mp\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl ); - scripts\mp\_integration_base::AddClientCommand( "Kill", true, ::KillImpl ); - scripts\mp\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl ); - scripts\mp\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl ); - scripts\mp\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl ); - scripts\mp\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl ); + scripts\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl ); + scripts\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl ); + scripts\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl ); + scripts\_integration_base::AddClientCommand( "Hide", false, ::HideImpl ); + scripts\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl ); + scripts\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl ); + scripts\_integration_base::AddClientCommand( "Kill", true, ::KillImpl ); + scripts\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl ); + scripts\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl ); + scripts\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl ); + scripts\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl ); } WaitForClientEvents() @@ -73,13 +75,13 @@ WaitForClientEvents() // example of requesting a meta value lastServerMetaKey = "LastServerPlayed"; - // self scripts\mp\_integration_base::RequestClientMeta( lastServerMetaKey ); + // self scripts\_integration_base::RequestClientMeta( lastServerMetaKey ); for ( ;; ) { self waittill( level.eventTypes.localClientEvent, event ); - scripts\mp\_integration_base::LogDebug( "Received client event " + event.type ); + scripts\_integration_base::LogDebug( "Received client event " + event.type ); if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey ) { @@ -109,6 +111,11 @@ Log2Console( logLevel, message ) Print( "[" + logLevel + "] " + message + "\n" ); } +_GetXUID() +{ + return self GetXUID(); +} + ////////////////////////////////// // GUID helpers ///////////////////////////////// @@ -126,14 +133,14 @@ SetPersistentData() { // give IW4MAdmin time to collect IP wait( 15 ); - scripts\mp\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid ); - scripts\mp\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid ); + scripts\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid ); + scripts\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid ); return; } guid = self SplitGuid(); - scripts\mp\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow ); + scripts\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow ); self SetPlayerData( "bests", "none", guid["high"] ); self SetPlayerData( "awards", "none", guid["low"] ); diff --git a/GameFiles/GameInterface/_integration_shared.gsc b/GameFiles/GameInterface/_integration_shared.gsc index 36a0ded01..2c0d87bd1 100644 --- a/GameFiles/GameInterface/_integration_shared.gsc +++ b/GameFiles/GameInterface/_integration_shared.gsc @@ -8,6 +8,9 @@ Setup() { level endon( "game_ended" ); + // it's possible that the notify type has not been defined yet so we have to hard code it + level waittill( "IntegrationBootstrapInitialized" ); + level.commonFunctions.changeTeam = "ChangeTeam"; level.commonFunctions.getTeamCounts = "GetTeamCounts"; level.commonFunctions.getMaxClients = "GetMaxClients"; @@ -25,6 +28,7 @@ Setup() level.overrideMethods[level.commonFunctions.getClientKillStreak] = scripts\_integration_base::NotImplementedFunction; level.overrideMethods[level.commonFunctions.backupRestoreClientKillStreakData] = scripts\_integration_base::NotImplementedFunction; level.overrideMethods[level.commonFunctions.waitTillAnyTimeout] = scripts\_integration_base::NotImplementedFunction; + level.overrideMethods["GetPlayerFromClientNum"] = ::GetPlayerFromClientNum; // these can be overridden per game if needed level.commonKeys.team1 = "allies"; @@ -39,15 +43,13 @@ Setup() level.iw4madminIntegrationDefaultPerformance = 200; + level notify( level.notifyTypes.sharedFunctionsInitialized ); + level waittill( level.notifyTypes.gameFunctionsInitialized ); + if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) { return; } - - if ( GetDvarInt( "sv_iw4madmin_autobalance" ) != 1 ) - { - return; - } level thread OnPlayerConnect(); } @@ -59,7 +61,22 @@ OnPlayerConnect() for ( ;; ) { level waittill( level.eventTypes.connect, player ); + + if ( scripts\_integration_base::_IsBot( player ) ) + { + // we don't want to track bots + continue; + } + + player thread OnPlayerJoinedTeam(); + player thread OnPlayerJoinedSpectators(); + player thread PlayerTrackingOnInterval(); + if ( GetDvarInt( "sv_iw4madmin_autobalance" ) != 1 || !IsDefined( [[level.overrideMethods[level.commonFunctions.getTeamBased]]]() ) ) + { + continue; + } + if ( ![[level.overrideMethods[level.commonFunctions.getTeamBased]]]() ) { continue; @@ -449,3 +466,123 @@ GetClientPerformanceOrDefault() return performance; } + +GetPlayerFromClientNum( clientNum ) +{ + if ( clientNum < 0 ) + { + return undefined; + } + + for ( i = 0; i < level.players.size; i++ ) + { + if ( level.players[i] getEntityNumber() == clientNum ) + { + return level.players[i]; + } + } + + return undefined; +} + +OnPlayerJoinedTeam() +{ + self endon( "disconnect" ); + + for( ;; ) + { + self waittill( "joined_team" ); + // join spec and join team occur at the same moment - out of order logging would be problematic + wait( 0.25 ); + LogPrint( GenerateJoinTeamString( false ) ); + } +} + +OnPlayerJoinedSpectators() +{ + self endon( "disconnect" ); + + for( ;; ) + { + self waittill( "joined_spectators" ); + LogPrint( GenerateJoinTeamString( true ) ); + } +} + +GenerateJoinTeamString( isSpectator ) +{ + team = self.team; + + if ( IsDefined( self.joining_team ) ) + { + team = self.joining_team; + } + else + { + if ( isSpectator || !IsDefined( team ) ) + { + team = "spectator"; + } + } + + guid = self [[level.overrideMethods[level.commonFunctions.getXuid]]](); + + if ( guid == "0" ) + { + guid = self.guid; + } + + if ( !IsDefined( guid ) || guid == "0" ) + { + guid = "undefined"; + } + + return "JT;" + guid + ";" + self getEntityNumber() + ";" + team + ";" + self.name + "\n"; +} + +PlayerTrackingOnInterval() +{ + self endon( "disconnect" ); + + for ( ;; ) + { + wait ( 120 ); + if ( IsAlive( self ) ) + { + self SaveTrackingMetrics(); + } + } +} + +SaveTrackingMetrics() +{ + if ( !IsDefined( self.persistentClientId ) ) + { + return; + } + + scripts\_integration_base::LogDebug( "Saving tracking metrics for " + self.persistentClientId ); + + if ( !IsDefined( self.lastShotCount ) ) + { + self.lastShotCount = 0; + } + + currentShotCount = self [[level.overrideMethods["GetTotalShotsFired"]]](); + change = currentShotCount - self.lastShotCount; + self.lastShotCount = currentShotCount; + + scripts\_integration_base::LogDebug( "Total Shots Fired increased by " + change ); + + if ( !IsDefined( change ) ) + { + change = 0; + } + + if ( change == 0 ) + { + return; + } + + scripts\_integration_base::IncrementClientMeta( "TotalShotsFired", change, self.persistentClientId ); +} \ No newline at end of file diff --git a/GameFiles/GameInterface/_integration_t5.gsc b/GameFiles/GameInterface/_integration_t5.gsc index 9d5e5f3f7..139847179 100644 --- a/GameFiles/GameInterface/_integration_t5.gsc +++ b/GameFiles/GameInterface/_integration_t5.gsc @@ -2,8 +2,6 @@ Init() { - level.eventBus.gamename = "T5"; - thread Setup(); } @@ -12,16 +10,20 @@ Setup() level endon( "game_ended" ); // it's possible that the notify type has not been defined yet so we have to hard code it - level waittill( "IntegrationBootstrapInitialized" ); + level waittill( "SharedFunctionsInitialized" ); + level.eventBus.gamename = "T5"; - scripts\mp\_integration_base::RegisterLogger( ::Log2Console ); + scripts\_integration_base::RegisterLogger( ::Log2Console ); level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired; level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized; level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout; + level.overrideMethods[level.commonFunctions.getXuid] = ::_GetXUID; RegisterClientCommands(); + _SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 ); + level notify( level.notifyTypes.gameFunctionsInitialized ); if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) @@ -40,7 +42,7 @@ OnPlayerConnect() { level waittill( "connected", player ); - if ( scripts\mp\_integration_base::_IsBot( player ) ) + if ( scripts\_integration_base::_IsBot( player ) ) { // we don't want to track bots continue; @@ -53,17 +55,17 @@ OnPlayerConnect() RegisterClientCommands() { - scripts\mp\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl ); - scripts\mp\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl ); - scripts\mp\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl ); - scripts\mp\_integration_base::AddClientCommand( "Hide", false, ::HideImpl ); - scripts\mp\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl ); - scripts\mp\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl ); - scripts\mp\_integration_base::AddClientCommand( "Kill", true, ::KillImpl ); - scripts\mp\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl ); - scripts\mp\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl ); - scripts\mp\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl ); - scripts\mp\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl ); + scripts\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl ); + scripts\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl ); + scripts\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl ); + scripts\_integration_base::AddClientCommand( "Hide", false, ::HideImpl ); + scripts\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl ); + scripts\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl ); + scripts\_integration_base::AddClientCommand( "Kill", true, ::KillImpl ); + scripts\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl ); + scripts\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl ); + scripts\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl ); + scripts\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl ); } WaitForClientEvents() @@ -72,13 +74,13 @@ WaitForClientEvents() // example of requesting a meta value lastServerMetaKey = "LastServerPlayed"; - // self scripts\mp\_integration_base::RequestClientMeta( lastServerMetaKey ); + // self scripts\_integration_base::RequestClientMeta( lastServerMetaKey ); for ( ;; ) { self waittill( level.eventTypes.localClientEvent, event ); - scripts\mp\_integration_base::LogDebug( "Received client event " + event.type ); + scripts\_integration_base::LogDebug( "Received client event " + event.type ); if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey ) { @@ -129,6 +131,11 @@ God() } } +_GetXUID() +{ + return self GetXUID(); +} + ////////////////////////////////// // GUID helpers ///////////////////////////////// @@ -146,14 +153,14 @@ God() { // give IW4MAdmin time to collect IP wait( 15 ); - scripts\mp\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid ); - scripts\mp\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid ); + scripts\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid ); + scripts\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid ); return; } guid = self SplitGuid(); - scripts\mp\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow ); + scripts\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow ); self SetPlayerData( "bests", "none", guid["high"] ); self SetPlayerData( "awards", "none", guid["low"] ); @@ -395,7 +402,7 @@ NoClipImpl( event, data ) self IPrintLnBold( "NoClip enabled" );*/ - scripts\mp\_integration_base::LogWarning( "NoClip is not supported on T5!" ); + scripts\_integration_base::LogWarning( "NoClip is not supported on T5!" ); } diff --git a/GameFiles/GameInterface/_integration_t5zm.gsc b/GameFiles/GameInterface/_integration_t5zm.gsc new file mode 100644 index 000000000..d01e9dc28 --- /dev/null +++ b/GameFiles/GameInterface/_integration_t5zm.gsc @@ -0,0 +1,552 @@ +#include common_scripts\utility; + +Init() +{ + thread Setup(); +} + +Setup() +{ + level endon( "game_ended" ); + + // it's possible that the notify type has not been defined yet so we have to hard code it + level waittill( "SharedFunctionsInitialized" ); + level.eventBus.gamename = "T5"; + + scripts\_integration_base::RegisterLogger( ::Log2Console ); + + level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired; + level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized; + level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout; + level.overrideMethods["GetPlayerFromClientNum"] = ::_GetPlayerFromClientNum; + + RegisterClientCommands(); + + _SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 ); + + level notify( level.notifyTypes.gameFunctionsInitialized ); + + if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) + { + return; + } + + level thread OnPlayerConnect(); +} + +OnPlayerConnect() +{ + level endon ( "game_ended" ); + + for ( ;; ) + { + level waittill( "connected", player ); + + if ( scripts\_integration_base::_IsBot( player ) ) + { + // we don't want to track bots + continue; + } + + //player thread SetPersistentData(); + player thread WaitForClientEvents(); + } +} + +RegisterClientCommands() +{ + scripts\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl ); + scripts\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl ); + scripts\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl ); + scripts\_integration_base::AddClientCommand( "Hide", false, ::HideImpl ); + scripts\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl ); + scripts\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl ); + scripts\_integration_base::AddClientCommand( "Kill", true, ::KillImpl ); + scripts\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl ); + scripts\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl ); + scripts\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl ); + scripts\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl ); +} + +WaitForClientEvents() +{ + self endon( "disconnect" ); + + // example of requesting a meta value + lastServerMetaKey = "LastServerPlayed"; + // self scripts\_integration_base::RequestClientMeta( lastServerMetaKey ); + + for ( ;; ) + { + self waittill( level.eventTypes.localClientEvent, event ); + + scripts\_integration_base::LogDebug( "Received client event " + event.type ); + + if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey ) + { + clientData = self.pers[level.clientDataKey]; + lastServerPlayed = clientData.meta[lastServerMetaKey]; + } + } +} + +GetTotalShotsFired() +{ + return 0; //ZM has no shot tracking. TODO: add tracking function for event weapon_fired +} + +_SetDvarIfUninitialized(dvar, value) +{ + if (GetDvar(dvar)=="" ) + { + SetDvar(dvar, value); + return value; + } + + return GetDvar(dvar); +} + +_waittill_notify_or_timeout( msg, timer ) +{ + self endon( msg ); + wait( timer ); +} + +Log2Console( logLevel, message ) +{ + Print( "[" + logLevel + "] " + message + "\n" ); +} + +God() +{ + + if ( !IsDefined( self.godmode ) ) + { + self.godmode = false; + } + + if (!self.godmode ) + { + self enableInvulnerability(); + self.godmode = true; + } + else + { + self.godmode = false; + self disableInvulnerability(); + } +} + +_GetPlayerFromClientNum( clientNum ) +{ + if ( clientNum < 0 ) + { + return undefined; + } + + players = GetPlayers("all"); + + for ( i = 0; i < players.size; i++ ) + { + scripts\_integration_base::LogDebug(i+"/"+players.size+ "=" + players[i].name); + if ( players[i] getEntityNumber() == clientNum ) + { + return players[i]; + } + } + + return undefined; +} + +////////////////////////////////// +// GUID helpers +///////////////////////////////// + +/*SetPersistentData() +{ + self endon( "disconnect" ); + + guidHigh = self GetPlayerData( "bests", "none" ); + guidLow = self GetPlayerData( "awards", "none" ); + persistentGuid = guidHigh + "," + guidLow; + guidIsStored = guidHigh != 0 && guidLow != 0; + + if ( guidIsStored ) + { + // give IW4MAdmin time to collect IP + wait( 15 ); + scripts\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid ); + scripts\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid ); + return; + } + + guid = self SplitGuid(); + + scripts\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow ); + + self SetPlayerData( "bests", "none", guid["high"] ); + self SetPlayerData( "awards", "none", guid["low"] ); +} + +SplitGuid() +{ + guid = self GetGuid(); + + if ( isDefined( self.guid ) ) + { + guid = self.guid; + } + + firstPart = 0; + secondPart = 0; + stringLength = 17; + firstPartExp = 0; + secondPartExp = 0; + + for ( i = stringLength - 1; i > 0; i-- ) + { + char = GetSubStr( guid, i - 1, i ); + if ( char == "" ) + { + char = "0"; + } + + if ( i > stringLength / 2 ) + { + value = GetIntForHexChar( char ); + power = Pow( 16, secondPartExp ); + secondPart = secondPart + ( value * power ); + secondPartExp++; + } + else + { + value = GetIntForHexChar( char ); + power = Pow( 16, firstPartExp ); + firstPart = firstPart + ( value * power ); + firstPartExp++; + } + } + + split = []; + split["low"] = int( secondPart ); + split["high"] = int( firstPart ); + + return split; +} + +Pow( num, exponent ) +{ + result = 1; + while( exponent != 0 ) + { + result = result * num; + exponent--; + } + + return result; +} + +GetIntForHexChar( char ) +{ + char = ToLower( char ); + // generated by co-pilot because I can't be bothered to make it more "elegant" + switch( char ) + { + case "0": + return 0; + case "1": + return 1; + case "2": + return 2; + case "3": + return 3; + case "4": + return 4; + case "5": + return 5; + case "6": + return 6; + case "7": + return 7; + case "8": + return 8; + case "9": + return 9; + case "a": + return 10; + case "b": + return 11; + case "c": + return 12; + case "d": + return 13; + case "e": + return 14; + case "f": + return 15; + default: + return 0; + } +}*/ + +////////////////////////////////// +// Command Implementations +///////////////////////////////// + +GiveWeaponImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + "^7 is not alive"; + } + + self IPrintLnBold( "You have been given a new weapon" ); + self GiveWeapon( data["weaponName"] ); + self SwitchToWeapon( data["weaponName"] ); + + return self.name + "^7 has been given ^5" + data["weaponName"]; +} + +TakeWeaponsImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + "^7 is not alive"; + } + + self TakeAllWeapons(); + self IPrintLnBold( "All your weapons have been taken" ); + + return "Took weapons from " + self.name; +} + +TeamSwitchImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self + "^7 is not alive"; + } + + team = level.allies; + + if ( self.team == "allies" ) + { + team = level.axis; + } + + self IPrintLnBold( "You are being team switched" ); + wait( 2 ); + self [[team]](); + + return self.name + "^7 switched to " + self.team; +} + +LockControlsImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + "^7 is not alive"; + } + + if ( !IsDefined ( self.isControlLocked ) ) + { + self.isControlLocked = false; + } + + if ( !self.isControlLocked ) + { + self freezeControls( true ); + self God(); + self Hide(); + + info = []; + info[ "alertType" ] = "Alert!"; + info[ "message" ] = "You have been frozen!"; + + self AlertImpl( undefined, info ); + + self.isControlLocked = true; + + return self.name + "\'s controls are locked"; + } + else + { + self freezeControls( false ); + self God(); + self Show(); + + self.isControlLocked = false; + + return self.name + "\'s controls are unlocked"; + } +} + +NoClipImpl( event, data ) +{ + /*if ( !IsAlive( self ) ) + { + self IPrintLnBold( "You are not alive" ); + } + + if ( !IsDefined ( self.isNoClipped ) ) + { + self.isNoClipped = false; + } + + if ( !self.isNoClipped ) + { + self SetClientDvar( "sv_cheats", 1 ); + self SetClientDvar( "cg_thirdperson", 1 ); + self SetClientDvar( "sv_cheats", 0 ); + + self God(); + self Noclip(); + self Hide(); + + self.isNoClipped = true; + + self IPrintLnBold( "NoClip enabled" ); + } + else + { + self SetClientDvar( "sv_cheats", 1 ); + self SetClientDvar( "cg_thirdperson", 1 ); + self SetClientDvar( "sv_cheats", 0 ); + + self God(); + self Noclip(); + self Hide(); + + self.isNoClipped = false; + + self IPrintLnBold( "NoClip disabled" ); + } + + self IPrintLnBold( "NoClip enabled" );*/ + + scripts\_integration_base::LogWarning( "NoClip is not supported on T5!" ); + +} + +HideImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + self IPrintLnBold( "You are not alive" ); + return; + } + + if ( !IsDefined ( self.isHidden ) ) + { + self.isHidden = false; + } + + if ( !self.isHidden ) + { + self SetClientDvar( "sv_cheats", 1 ); + self SetClientDvar( "cg_thirdperson", 1 ); + self SetClientDvar( "sv_cheats", 0 ); + + self God(); + self Hide(); + + self.isHidden = true; + + self IPrintLnBold( "Hide enabled" ); + } + else + { + self SetClientDvar( "sv_cheats", 1 ); + self SetClientDvar( "cg_thirdperson", 0 ); + self SetClientDvar( "sv_cheats", 0 ); + + self God(); + self Show(); + + self.isHidden = false; + + self IPrintLnBold( "Hide disabled" ); + } +} + +AlertImpl( event, data ) +{ + //self thread maps\mp\gametypes\_hud_message::oldNotifyMessage( data["alertType"], data["message"], undefined, ( 1, 0, 0 ), "mpl_sab_ui_suitcasebomb_timer", 7.5 ); + self IPrintLnBold(data["message"]); + + return "Sent alert to " + self.name; +} + +GotoImpl( event, data ) +{ + if ( IsDefined( event.target ) ) + { + return self GotoPlayerImpl( event.target ); + } + else + { + return self GotoCoordImpl( data ); + } +} + +GotoCoordImpl( data ) +{ + if ( !IsAlive( self ) ) + { + self IPrintLnBold( "You are not alive" ); + return; + } + + position = ( int( data["x"] ), int( data["y"] ), int( data["z"]) ); + self SetOrigin( position ); + self IPrintLnBold( "Moved to " + "("+ position[0] + "," + position[1] + "," + position[2] + ")" ); +} + +GotoPlayerImpl( target ) +{ + if ( !IsAlive( target ) ) + { + self IPrintLnBold( target.name + " is not alive" ); + return; + } + + self SetOrigin( target GetOrigin() ); + self IPrintLnBold( "Moved to " + target.name ); +} + +PlayerToMeImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + " is not alive"; + } + + self SetOrigin( event.origin GetOrigin() ); + return "Moved here " + self.name; +} + +KillImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + " is not alive"; + } + + self Suicide(); + self IPrintLnBold( "You were killed by " + self.name ); + + return "You killed " + self.name; +} + +SetSpectatorImpl( event, data ) +{ + if ( self.pers["team"] == "spectator" ) + { + return self.name + " is already spectating"; + } + + self [[level.spectator]](); + self IPrintLnBold( "You have been moved to spectator" ); + + return self.name + " has been moved to spectator"; +} diff --git a/GameFiles/GameInterface/_integration_t6.gsc b/GameFiles/GameInterface/_integration_t6.gsc new file mode 100644 index 000000000..07b67b649 --- /dev/null +++ b/GameFiles/GameInterface/_integration_t6.gsc @@ -0,0 +1,571 @@ +#include common_scripts\utility; +#include maps\mp\_utility; + +Init() +{ + thread Setup(); +} + +Setup() +{ + level endon( "game_ended" ); + + // it's possible that the notify type has not been defined yet so we have to hard code it + level waittill( "SharedFunctionsInitialized" ); + level.eventBus.gamename = "T6"; + + scripts\_integration_base::RegisterLogger( ::Log2Console ); + + level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired; + level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized; + level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout; + level.overrideMethods[level.commonFunctions.getXuid] = ::_GetXUID; + + RegisterClientCommands(); + + _SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 ); + + level notify( level.notifyTypes.gameFunctionsInitialized ); + + if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) + { + return; + } + + level thread OnPlayerConnect(); +} + +OnPlayerConnect() +{ + level endon ( "game_ended" ); + + for ( ;; ) + { + level waittill( "connected", player ); + + if ( scripts\_integration_base::_IsBot( player ) ) + { + // we don't want to track bots + continue; + } + + //player thread SetPersistentData(); + player thread WaitForClientEvents(); + } +} + +RegisterClientCommands() +{ + scripts\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl ); + scripts\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl ); + scripts\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl ); + scripts\_integration_base::AddClientCommand( "Hide", false, ::HideImpl ); + scripts\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl ); + scripts\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl ); + scripts\_integration_base::AddClientCommand( "Kill", true, ::KillImpl ); + scripts\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl ); + scripts\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl ); + scripts\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl ); + scripts\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl ); +} + +WaitForClientEvents() +{ + self endon( "disconnect" ); + + // example of requesting a meta value + lastServerMetaKey = "LastServerPlayed"; + // self scripts\_integration_base::RequestClientMeta( lastServerMetaKey ); + + for ( ;; ) + { + self waittill( level.eventTypes.localClientEvent, event ); + + scripts\_integration_base::LogDebug( "Received client event " + event.type ); + + if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey ) + { + clientData = self.pers[level.clientDataKey]; + lastServerPlayed = clientData.meta[lastServerMetaKey]; + } + } +} + +GetTotalShotsFired() +{ + return self.pers[ "total_shots" ]; +} + +_SetDvarIfUninitialized(dvar, value) +{ + maps\mp\_utility::set_dvar_if_unset(dvar, value); +} + +_waittill_notify_or_timeout( msg, timer ) +{ + self endon( msg ); + wait( timer ); +} + +Log2Console( logLevel, message ) +{ + Print( "[" + logLevel + "] " + message + "\n" ); +} + +God() +{ + + if ( !IsDefined( self.godmode ) ) + { + self.godmode = false; + } + + if (!self.godmode ) + { + self enableInvulnerability(); + self.godmode = true; + } + else + { + self.godmode = false; + self disableInvulnerability(); + } +} + +_GetXUID() +{ + return self GetXUID(); +} + +////////////////////////////////// +// GUID helpers +///////////////////////////////// + +/*SetPersistentData() +{ + self endon( "disconnect" ); + + guidHigh = self GetPlayerData( "bests", "none" ); + guidLow = self GetPlayerData( "awards", "none" ); + persistentGuid = guidHigh + "," + guidLow; + guidIsStored = guidHigh != 0 && guidLow != 0; + + if ( guidIsStored ) + { + // give IW4MAdmin time to collect IP + wait( 15 ); + scripts\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid ); + scripts\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid ); + return; + } + + guid = self SplitGuid(); + + scripts\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow ); + + self SetPlayerData( "bests", "none", guid["high"] ); + self SetPlayerData( "awards", "none", guid["low"] ); +} + +SplitGuid() +{ + guid = self GetGuid(); + + if ( isDefined( self.guid ) ) + { + guid = self.guid; + } + + firstPart = 0; + secondPart = 0; + stringLength = 17; + firstPartExp = 0; + secondPartExp = 0; + + for ( i = stringLength - 1; i > 0; i-- ) + { + char = GetSubStr( guid, i - 1, i ); + if ( char == "" ) + { + char = "0"; + } + + if ( i > stringLength / 2 ) + { + value = GetIntForHexChar( char ); + power = Pow( 16, secondPartExp ); + secondPart = secondPart + ( value * power ); + secondPartExp++; + } + else + { + value = GetIntForHexChar( char ); + power = Pow( 16, firstPartExp ); + firstPart = firstPart + ( value * power ); + firstPartExp++; + } + } + + split = []; + split["low"] = int( secondPart ); + split["high"] = int( firstPart ); + + return split; +} + +Pow( num, exponent ) +{ + result = 1; + while( exponent != 0 ) + { + result = result * num; + exponent--; + } + + return result; +} + +GetIntForHexChar( char ) +{ + char = ToLower( char ); + // generated by co-pilot because I can't be bothered to make it more "elegant" + switch( char ) + { + case "0": + return 0; + case "1": + return 1; + case "2": + return 2; + case "3": + return 3; + case "4": + return 4; + case "5": + return 5; + case "6": + return 6; + case "7": + return 7; + case "8": + return 8; + case "9": + return 9; + case "a": + return 10; + case "b": + return 11; + case "c": + return 12; + case "d": + return 13; + case "e": + return 14; + case "f": + return 15; + default: + return 0; + } +}*/ + +////////////////////////////////// +// Command Implementations +///////////////////////////////// + +GiveWeaponImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + "^7 is not alive"; + } + + if ( isDefined( level.player_too_many_weapons_monitor ) && level.player_too_many_weapons_monitor ) + { + level.player_too_many_weapons_monitor = false; + self notify( "stop_player_too_many_weapons_monitor" ); + } + + self IPrintLnBold( "You have been given a new weapon" ); + self GiveWeapon( data["weaponName"] ); + self SwitchToWeapon( data["weaponName"] ); + + return self.name + "^7 has been given ^5" + data["weaponName"]; +} + +TakeWeaponsImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + "^7 is not alive"; + } + + self TakeAllWeapons(); + self IPrintLnBold( "All your weapons have been taken" ); + + return "Took weapons from " + self.name; +} + +TeamSwitchImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self + "^7 is not alive"; + } + + team = level.allies; + + if ( self.team == "allies" ) + { + team = level.axis; + } + + self IPrintLnBold( "You are being team switched" ); + wait( 2 ); + self [[team]](); + + return self.name + "^7 switched to " + self.team; +} + +LockControlsImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + "^7 is not alive"; + } + + if ( !IsDefined ( self.isControlLocked ) ) + { + self.isControlLocked = false; + } + + if ( !self.isControlLocked ) + { + self freezeControls( true ); + self God(); + self Hide(); + + info = []; + info[ "alertType" ] = "Alert!"; + info[ "message" ] = "You have been frozen!"; + + self AlertImpl( undefined, info ); + + self.isControlLocked = true; + + return self.name + "\'s controls are locked"; + } + else + { + self freezeControls( false ); + self God(); + self Show(); + + self.isControlLocked = false; + + return self.name + "\'s controls are unlocked"; + } +} + +NoClipImpl( event, data ) +{ + /*if ( !IsAlive( self ) ) + { + self IPrintLnBold( "You are not alive" ); + } + + if ( !IsDefined ( self.isNoClipped ) ) + { + self.isNoClipped = false; + } + + if ( !self.isNoClipped ) + { + self SetClientDvar( "sv_cheats", 1 ); + self SetClientDvar( "cg_thirdperson", 1 ); + self SetClientDvar( "sv_cheats", 0 ); + + self God(); + self Noclip(); + self Hide(); + + self.isNoClipped = true; + + self IPrintLnBold( "NoClip enabled" ); + } + else + { + self SetClientDvar( "sv_cheats", 1 ); + self SetClientDvar( "cg_thirdperson", 1 ); + self SetClientDvar( "sv_cheats", 0 ); + + self God(); + self Noclip(); + self Hide(); + + self.isNoClipped = false; + + self IPrintLnBold( "NoClip disabled" ); + } + + self IPrintLnBold( "NoClip enabled" );*/ + + scripts\_integration_base::LogWarning( "NoClip is not supported on T6!" ); + +} + +HideImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + self IPrintLnBold( "You are not alive" ); + return; + } + + if ( !IsDefined ( self.isHidden ) ) + { + self.isHidden = false; + } + + if ( !self.isHidden ) + { + self SetClientDvar( "sv_cheats", 1 ); + self SetClientDvar( "cg_thirdperson", 1 ); + self SetClientDvar( "sv_cheats", 0 ); + + self God(); + self Hide(); + + self.isHidden = true; + + self IPrintLnBold( "Hide enabled" ); + } + else + { + self SetClientDvar( "sv_cheats", 1 ); + self SetClientDvar( "cg_thirdperson", 0 ); + self SetClientDvar( "sv_cheats", 0 ); + + self God(); + self Show(); + + self.isHidden = false; + + self IPrintLnBold( "Hide disabled" ); + } +} + +AlertImpl( event, data ) +{ + /*if ( !sessionmodeiszombiesgame() ) + {*/ + self thread oldNotifyMessage( data["alertType"], data["message"], undefined, ( 1, 0, 0 ), "mpl_sab_ui_suitcasebomb_timer", 7.5 ); + /*} + else + { + self IPrintLnBold( data["alertType"] ); + self IPrintLnBold( data["message"] ); + }*/ + + + return "Sent alert to " + self.name; +} + +GotoImpl( event, data ) +{ + if ( IsDefined( event.target ) ) + { + return self GotoPlayerImpl( event.target ); + } + else + { + return self GotoCoordImpl( data ); + } +} + +GotoCoordImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + self IPrintLnBold( "You are not alive" ); + return; + } + + position = ( int( data["x"] ), int( data["y"] ), int( data["z"]) ); + self SetOrigin( position ); + self IPrintLnBold( "Moved to " + "("+ position[0] + "," + position[1] + "," + position[2] + ")" ); +} + +GotoPlayerImpl( target ) +{ + if ( !IsAlive( target ) ) + { + self IPrintLnBold( target.name + " is not alive" ); + return; + } + + self SetOrigin( target GetOrigin() ); + self IPrintLnBold( "Moved to " + target.name ); +} + +PlayerToMeImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + " is not alive"; + } + + self SetOrigin( event.origin GetOrigin() ); + return "Moved here " + self.name; +} + +KillImpl( event, data ) +{ + if ( !IsAlive( self ) ) + { + return self.name + " is not alive"; + } + + self Suicide(); + self IPrintLnBold( "You were killed by " + self.name ); + + return "You killed " + self.name; +} + +SetSpectatorImpl( event, data ) +{ + if ( self.pers["team"] == "spectator" ) + { + return self.name + " is already spectating"; + } + + self [[level.spectator]](); + self IPrintLnBold( "You have been moved to spectator" ); + + return self.name + " has been moved to spectator"; +} + + +////////////////////////////////// +// T6 specific functions +///////////////////////////////// + +/* +1:1 the same on MP and ZM but in different includes. Since we probably want to be able to send Alerts on non teambased wagermatechs use our own copy. +*/ +oldnotifymessage( titletext, notifytext, iconname, glowcolor, sound, duration ) +{ + /*if ( level.wagermatch && !level.teambased ) + { + return; + }*/ + notifydata = spawnstruct(); + notifydata.titletext = titletext; + notifydata.notifytext = notifytext; + notifydata.iconname = iconname; + notifydata.sound = sound; + notifydata.duration = duration; + self.startmessagenotifyqueue[ self.startmessagenotifyqueue.size ] = notifydata; + self notify( "received award" ); +} + + diff --git a/GameFiles/GameInterface/_integration_t6zm_helper.gsc b/GameFiles/GameInterface/_integration_t6zm_helper.gsc new file mode 100644 index 000000000..69a26dbda --- /dev/null +++ b/GameFiles/GameInterface/_integration_t6zm_helper.gsc @@ -0,0 +1,86 @@ +init() +{ + + level.startmessagedefaultduration = 2; + level.regulargamemessages = spawnstruct(); + level.regulargamemessages.waittime = 6; + + + level thread onplayerconnect(); +} + +onplayerconnect() +{ + for ( ;; ) + { + level waittill( "connecting", player ); + player thread displaypopupswaiter(); + } +} + +displaypopupswaiter() +{ + self endon( "disconnect" ); + self.ranknotifyqueue = []; + if ( !isDefined( self.pers[ "challengeNotifyQueue" ] ) ) + { + self.pers[ "challengeNotifyQueue" ] = []; + } + if ( !isDefined( self.pers[ "contractNotifyQueue" ] ) ) + { + self.pers[ "contractNotifyQueue" ] = []; + } + self.messagenotifyqueue = []; + self.startmessagenotifyqueue = []; + self.wagernotifyqueue = []; + while ( !level.gameended ) + { + if ( self.startmessagenotifyqueue.size == 0 && self.messagenotifyqueue.size == 0 ) + { + self waittill( "received award" ); + } + waittillframeend; + if ( level.gameended ) + { + return; + } + else + { + if ( self.startmessagenotifyqueue.size > 0 ) + { + nextnotifydata = self.startmessagenotifyqueue[ 0 ]; + arrayremoveindex( self.startmessagenotifyqueue, 0, 0 ); + if ( isDefined( nextnotifydata.duration ) ) + { + duration = nextnotifydata.duration; + } + else + { + duration = level.startmessagedefaultduration; + } + self maps\mp\gametypes_zm\_hud_message::shownotifymessage( nextnotifydata, duration ); + wait duration; + continue; + } + else if ( self.messagenotifyqueue.size > 0 ) + { + nextnotifydata = self.messagenotifyqueue[ 0 ]; + arrayremoveindex( self.messagenotifyqueue, 0, 0 ); + if ( isDefined( nextnotifydata.duration ) ) + { + duration = nextnotifydata.duration; + } + else + { + duration = level.regulargamemessages.waittime; + } + self maps\mp\gametypes_zm\_hud_message::shownotifymessage( nextnotifydata, duration ); + continue; + } + else + { + wait 1; + } + } + } +} \ No newline at end of file diff --git a/GameFiles/deploy.bat b/GameFiles/deploy.bat index cbb7b1f60..7f9cd833d 100644 --- a/GameFiles/deploy.bat +++ b/GameFiles/deploy.bat @@ -1,14 +1,20 @@ @echo off ECHO "Pluto IW5" -xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts\mp" -xcopy /y .\GameInterface\_integration_iw5.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts\mp" +xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts" +xcopy /y .\GameInterface\_integration_shared.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts" +xcopy /y .\GameInterface\_integration_iw5.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts" xcopy /y .\AntiCheat\IW5\storage\iw5\scripts\_customcallbacks.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts\mp" ECHO "Pluto T5" -xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts\mp" +xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts" +xcopy /y .\GameInterface\_integration_shared.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts" xcopy /y .\GameInterface\_integration_t5.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts\mp" +xcopy /y .\GameInterface\_integration_t5zm.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts\sp\zom" ECHO "Pluto T6" xcopy /y .\AntiCheat\PT6\storage\t6\scripts\mp\_customcallbacks.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts\mp" -xcopy /y .\AntiCheat\PT6\storage\t6\scripts\mp\_customcallbacks.gsc.src "%LOCALAPPDATA%\Plutonium\storage\t6\scripts\mp" +xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts" +xcopy /y .\GameInterface\_integration_shared.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts" +xcopy /y .\GameInterface\_integration_t6.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts" +xcopy /y .\GameInterface\_integration_t6zm_helper.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts\zm" diff --git a/Plugins/ScriptPlugins/GameInterface.js b/Plugins/ScriptPlugins/GameInterface.js index 79f49409b..5fd82d993 100644 --- a/Plugins/ScriptPlugins/GameInterface.js +++ b/Plugins/ScriptPlugins/GameInterface.js @@ -385,7 +385,7 @@ const commands = [{ required: true } ], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -405,7 +405,7 @@ const commands = [{ name: 'player', required: true }], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -423,7 +423,7 @@ const commands = [{ name: 'player', required: true }], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -441,7 +441,7 @@ const commands = [{ name: 'player', required: true }], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -471,7 +471,7 @@ const commands = [{ permission: 'SeniorAdmin', targetRequired: false, arguments: [], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -494,7 +494,7 @@ const commands = [{ required: true } ], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -515,7 +515,7 @@ const commands = [{ name: 'player', required: true }], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -533,7 +533,7 @@ const commands = [{ name: 'player', required: true }], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -560,7 +560,7 @@ const commands = [{ required: true } ], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -584,7 +584,7 @@ const commands = [{ name: 'player', required: true }], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return; @@ -602,7 +602,7 @@ const commands = [{ name: 'player', required: true }], - supportedGames: ['IW4', 'IW5', 'T5'], + supportedGames: ['IW4', 'IW5', 'T5', 'T6'], execute: (gameEvent) => { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { return;