Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions PlayTools/PlayLoader.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// PlayTools
//

#include <Foundation/Foundation.h>
#include <errno.h>
#include <sys/sysctl.h>

Expand Down Expand Up @@ -230,11 +231,62 @@ static int pt_unlink(char const* path) {
return unlink(ue_fix_filename(path));
}

static NSMutableDictionary *thread_sleep_counters = nil;
static NSMutableDictionary *last_sleep_attempts = nil;
static dispatch_once_t thread_sleep_once;
static NSLock *thread_sleep_lock = nil;

static int pt_usleep(useconds_t time) {
dispatch_once(&thread_sleep_once, ^{
thread_sleep_counters = [NSMutableDictionary dictionary];
last_sleep_attempts = [NSMutableDictionary dictionary];
thread_sleep_lock = [[NSLock alloc] init];
[thread_sleep_lock lock];
});

if ([[PlaySettings shared] blockSleepSpamming]) {
int thread_id = pthread_mach_thread_np(pthread_self());
NSNumber *threadKey = @(thread_id);

int thread_sleep_counter = [thread_sleep_counters[threadKey] intValue];
int last_sleep_attempt = [last_sleep_attempts[threadKey] intValue];

if (time == 100000) {
int timestamp = (int)[[NSDate date] timeIntervalSince1970];
// If it sleeps too fast, increase counter
if (timestamp - last_sleep_attempt < 2) {
thread_sleep_counter++;
} else {
thread_sleep_counter = 1;
}
last_sleep_attempt = timestamp;
thread_sleep_counters[threadKey] = @(thread_sleep_counter);
last_sleep_attempts[threadKey] = @(last_sleep_attempt);

}

if (thread_sleep_counter > 100) {
// Stop this thread from spamming usleep calls
NSLog(@"[PC] Thread %i exceeded usleep limit. Seem sus, stopping this "
@"thread FOREVER",
thread_id);

[thread_sleep_lock lock];
[thread_sleep_lock unlock];

return 0;
}
}

return usleep(time);
}

DYLD_INTERPOSE(pt_open, open)
DYLD_INTERPOSE(pt_stat, stat)
DYLD_INTERPOSE(pt_access, access)
DYLD_INTERPOSE(pt_rename, rename)
DYLD_INTERPOSE(pt_unlink, unlink)
DYLD_INTERPOSE(pt_usleep, usleep)

@implementation PlayLoader

Expand All @@ -250,6 +302,16 @@ static void __attribute__((constructor)) initialize(void) {
if (ue_status == 2) {
[PlayKeychain debugLogger: [NSString stringWithFormat:@"UnrealEngine Hooked"]];
}

if ([[PlaySettings shared] blockSleepSpamming]) {
// Add an observer so we can unlock threads on app termination
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * _Nonnull note) {
[thread_sleep_lock unlock];
}];
}
}

@end
3 changes: 3 additions & 0 deletions PlayTools/PlaySettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ let settings = PlaySettings.shared
@objc lazy var limitMotionUpdateFrequency = settingsData.limitMotionUpdateFrequency

@objc lazy var disableBuiltinMouse = settingsData.disableBuiltinMouse

@objc lazy var blockSleepSpamming = settingsData.blockSleepSpamming
}

struct AppSettingsData: Codable {
Expand Down Expand Up @@ -125,4 +127,5 @@ struct AppSettingsData: Codable {
var resizableAspectRatioType = 0
var resizableAspectRatioWidth = 0
var resizableAspectRatioHeight = 0
var blockSleepSpamming = false
}