diff --git a/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc b/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc index 909b02921..133a6a59f 100644 Binary files a/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc and b/GameFiles/AntiCheat/PT6/storage/t6/scripts/mp/_customcallbacks.gsc differ 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;