备份CatanBuilding瘦身独立工程
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e629251785524cfbbb3397293417874
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@interface NSObject (TDSwizzle)
|
||||
|
||||
+ (BOOL)td_swizzleMethod:(SEL)origSel withMethod:(SEL)altSel error:(NSError **)error;
|
||||
+ (BOOL)td_swizzleClassMethod:(SEL)origSel withClassMethod:(SEL)altSel error:(NSError **)error;
|
||||
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72eee1f705cf140559b12462d0d8cc9c
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
#import "NSObject+TDSwizzle.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#else
|
||||
#import <objc/objc-class.h>
|
||||
#endif
|
||||
|
||||
@implementation NSObject (TDSwizzle)
|
||||
|
||||
+ (BOOL)td_swizzleMethod:(SEL)origSel withMethod:(SEL)altSel error:(NSError **)error {
|
||||
Method origMethod = class_getInstanceMethod(self, origSel);
|
||||
if (!origMethod) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
Method altMethod = class_getInstanceMethod(self, altSel);
|
||||
if (!altMethod) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
class_addMethod(self,
|
||||
origSel,
|
||||
class_getMethodImplementation(self, origSel),
|
||||
method_getTypeEncoding(origMethod));
|
||||
class_addMethod(self,
|
||||
altSel,
|
||||
class_getMethodImplementation(self, altSel),
|
||||
method_getTypeEncoding(altMethod));
|
||||
|
||||
method_exchangeImplementations(class_getInstanceMethod(self, origSel), class_getInstanceMethod(self, altSel));
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)td_swizzleClassMethod:(SEL)origSel withClassMethod:(SEL)altSel error:(NSError **)error {
|
||||
return [object_getClass((id)self) td_swizzleMethod:origSel withMethod:altSel error:error];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c12a2223933c43b39244660c43cae9c
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wstrict-prototypes"
|
||||
typedef void (^swizzleBlock)();
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@interface TDSwizzler : NSObject
|
||||
|
||||
+ (void)swizzleSelector:(SEL)aSelector onClass:(Class)aClass withBlock:(swizzleBlock)block named:(NSString *)aName;
|
||||
+ (void)unswizzleSelector:(SEL)aSelector onClass:(Class)aClass named:(NSString *)aName;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33ad60578ee5c4d2c9c842ea9ca3d6bf
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,241 @@
|
||||
#import "TDSwizzler.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import "TDLogging.h"
|
||||
|
||||
#define MAPTABLE_ID(x) (__bridge id)((void *)x)
|
||||
|
||||
#define MIN_ARGS 2
|
||||
#define MAX_ARGS 4
|
||||
|
||||
@interface TDSwizzle : NSObject
|
||||
|
||||
@property (nonatomic, assign) Class class;
|
||||
@property (nonatomic, assign) SEL selector;
|
||||
@property (nonatomic, assign) IMP originalMethod;
|
||||
@property (nonatomic, assign) uint numArgs;
|
||||
@property (nonatomic, copy) NSMapTable *blocks;
|
||||
|
||||
- (instancetype)initWithBlock:(swizzleBlock)aBlock
|
||||
named:(NSString *)aName
|
||||
forClass:(Class)aClass
|
||||
selector:(SEL)aSelector
|
||||
originalMethod:(IMP)aMethod;
|
||||
|
||||
@end
|
||||
|
||||
static NSMapTable *swizzles;
|
||||
|
||||
static void td_swizzledMethod_2(id self, SEL _cmd) {
|
||||
Method aMethod = class_getInstanceMethod([self class], _cmd);
|
||||
TDSwizzle *swizzle = (TDSwizzle *)[swizzles objectForKey:MAPTABLE_ID(aMethod)];
|
||||
if (swizzle) {
|
||||
((void(*)(id, SEL))swizzle.originalMethod)(self, _cmd);
|
||||
|
||||
NSEnumerator *blocks = [swizzle.blocks objectEnumerator];
|
||||
swizzleBlock block;
|
||||
while((block = [blocks nextObject])) {
|
||||
|
||||
block(self, _cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void td_swizzledMethod_3(id self, SEL _cmd, id arg) {
|
||||
Method aMethod = class_getInstanceMethod([self class], _cmd);
|
||||
TDSwizzle *swizzle = (TDSwizzle *)[swizzles objectForKey:MAPTABLE_ID(aMethod)];
|
||||
if (swizzle) {
|
||||
((void(*)(id, SEL, id))swizzle.originalMethod)(self, _cmd, arg);
|
||||
|
||||
NSEnumerator *blocks = [swizzle.blocks objectEnumerator];
|
||||
swizzleBlock block;
|
||||
while((block = [blocks nextObject])) {
|
||||
block(self, _cmd, arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void td_swizzledMethod_4(id self, SEL _cmd, id arg, id arg2) {
|
||||
Method aMethod = class_getInstanceMethod([self class], _cmd);
|
||||
TDSwizzle *swizzle = (TDSwizzle *)[swizzles objectForKey:(__bridge id)((void *)aMethod)];
|
||||
if (swizzle) {
|
||||
((void(*)(id, SEL, id, id))swizzle.originalMethod)(self, _cmd, arg, arg2);
|
||||
|
||||
NSEnumerator *blocks = [swizzle.blocks objectEnumerator];
|
||||
swizzleBlock block;
|
||||
while((block = [blocks nextObject])) {
|
||||
block(self, _cmd, arg, arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wstrict-prototypes"
|
||||
static void (*td_swizzledMethods[MAX_ARGS - MIN_ARGS + 1])() = {td_swizzledMethod_2, td_swizzledMethod_3, td_swizzledMethod_4};
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@implementation TDSwizzler
|
||||
|
||||
+ (void)load {
|
||||
swizzles = [NSMapTable mapTableWithKeyOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality)
|
||||
valueOptions:(NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPointerPersonality)];
|
||||
}
|
||||
|
||||
+ (TDSwizzle *)swizzleForMethod:(Method)aMethod {
|
||||
return (TDSwizzle *)[swizzles objectForKey:MAPTABLE_ID(aMethod)];
|
||||
}
|
||||
|
||||
+ (void)removeSwizzleForMethod:(Method)aMethod {
|
||||
[swizzles removeObjectForKey:MAPTABLE_ID(aMethod)];
|
||||
}
|
||||
|
||||
+ (void)setSwizzle:(TDSwizzle *)swizzle forMethod:(Method)aMethod {
|
||||
[swizzles setObject:swizzle forKey:MAPTABLE_ID(aMethod)];
|
||||
}
|
||||
|
||||
+ (BOOL)isLocallyDefinedMethod:(Method)aMethod onClass:(Class)aClass {
|
||||
uint count;
|
||||
BOOL isLocal = NO;
|
||||
Method *methods = class_copyMethodList(aClass, &count);
|
||||
for (NSUInteger i = 0; i < count; i++) {
|
||||
if (aMethod == methods[i]) {
|
||||
isLocal = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(methods);
|
||||
return isLocal;
|
||||
}
|
||||
|
||||
+ (void)swizzleSelector:(SEL)aSelector
|
||||
onClass:(Class)aClass
|
||||
withBlock:(swizzleBlock)aBlock
|
||||
named:(NSString *)aName {
|
||||
Method aMethod = class_getInstanceMethod(aClass, aSelector);
|
||||
if (!aMethod) {
|
||||
TDLogInfo(@"SwizzleException:Cannot find method for %@ on %@",NSStringFromSelector(aSelector), NSStringFromClass(aClass));
|
||||
return;
|
||||
}
|
||||
|
||||
uint numArgs = method_getNumberOfArguments(aMethod);
|
||||
if (numArgs < MIN_ARGS || numArgs > MAX_ARGS) {
|
||||
TDLogError(@"Cannot swizzle method with %d args", numArgs);
|
||||
}
|
||||
|
||||
IMP swizzledMethod = (IMP)td_swizzledMethods[numArgs - 2];
|
||||
[TDSwizzler swizzleSelector:aSelector onClass:aClass withBlock:aBlock andSwizzleMethod:swizzledMethod named:aName];
|
||||
}
|
||||
|
||||
+ (void)swizzleSelector:(SEL)aSelector
|
||||
onClass:(Class)aClass
|
||||
withBlock:(swizzleBlock)aBlock
|
||||
andSwizzleMethod:(IMP)aSwizzleMethod
|
||||
named:(NSString *)aName {
|
||||
Method aMethod = class_getInstanceMethod(aClass, aSelector);
|
||||
if (!aMethod) {
|
||||
TDLogError(@"Cannot find method for %@ on %@", NSStringFromSelector(aSelector), NSStringFromClass(aClass));
|
||||
}
|
||||
|
||||
BOOL isLocal = [self isLocallyDefinedMethod:aMethod onClass:aClass];
|
||||
TDSwizzle *swizzle = [self swizzleForMethod:aMethod];
|
||||
|
||||
if (isLocal) {
|
||||
if (!swizzle) {
|
||||
IMP originalMethod = method_getImplementation(aMethod);
|
||||
|
||||
// Replace the local implementation of this method with the swizzled one
|
||||
method_setImplementation(aMethod, aSwizzleMethod);
|
||||
|
||||
// Create and add the swizzle
|
||||
@try {
|
||||
swizzle = [[TDSwizzle alloc] initWithBlock:aBlock named:aName forClass:aClass selector:aSelector originalMethod:originalMethod];
|
||||
} @catch (NSException *exception) {
|
||||
TDLogError(@"%@ error: %@", self, exception);
|
||||
}
|
||||
[self setSwizzle:swizzle forMethod:aMethod];
|
||||
} else {
|
||||
[swizzle.blocks setObject:aBlock forKey:aName];
|
||||
}
|
||||
} else {
|
||||
IMP originalMethod = swizzle ? swizzle.originalMethod : method_getImplementation(aMethod);
|
||||
|
||||
// Add the swizzle as a new local method on the class.
|
||||
if (!class_addMethod(aClass, aSelector, aSwizzleMethod, method_getTypeEncoding(aMethod))) {
|
||||
TDLogError(@"Could not add swizzled for %@::%@, even though it didn't already exist locally", NSStringFromClass(aClass), NSStringFromSelector(aSelector));
|
||||
}
|
||||
// Now re-get the Method, it should be the one we just added.
|
||||
Method newMethod = class_getInstanceMethod(aClass, aSelector);
|
||||
if (aMethod == newMethod) {
|
||||
TDLogError(@"Newly added method for %@::%@ was the same as the old method", NSStringFromClass(aClass), NSStringFromSelector(aSelector));
|
||||
}
|
||||
|
||||
TDSwizzle *newSwizzle = [[TDSwizzle alloc] initWithBlock:aBlock named:aName forClass:aClass selector:aSelector originalMethod:originalMethod];
|
||||
[self setSwizzle:newSwizzle forMethod:newMethod];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)unswizzleSelector:(SEL)aSelector onClass:(Class)aClass {
|
||||
Method aMethod = class_getInstanceMethod(aClass, aSelector);
|
||||
TDSwizzle *swizzle = [self swizzleForMethod:aMethod];
|
||||
if (swizzle) {
|
||||
method_setImplementation(aMethod, swizzle.originalMethod);
|
||||
[self removeSwizzleForMethod:aMethod];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Remove the named swizzle from the given class/selector. If aName is nil, remove all
|
||||
swizzles for this class/selector
|
||||
*/
|
||||
+ (void)unswizzleSelector:(SEL)aSelector onClass:(Class)aClass named:(NSString *)aName {
|
||||
Method aMethod = class_getInstanceMethod(aClass, aSelector);
|
||||
TDSwizzle *swizzle = [self swizzleForMethod:aMethod];
|
||||
if (swizzle) {
|
||||
if (aName) {
|
||||
[swizzle.blocks removeObjectForKey:aName];
|
||||
}
|
||||
if (!aName || [swizzle.blocks count] == 0) {
|
||||
method_setImplementation(aMethod, swizzle.originalMethod);
|
||||
[self removeSwizzleForMethod:aMethod];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation TDSwizzle
|
||||
|
||||
- (instancetype)init {
|
||||
if ((self = [super init])) {
|
||||
self.blocks = [NSMapTable mapTableWithKeyOptions:(NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality)
|
||||
valueOptions:(NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPointerPersonality)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithBlock:(swizzleBlock)aBlock
|
||||
named:(NSString *)aName
|
||||
forClass:(Class)aClass
|
||||
selector:(SEL)aSelector
|
||||
originalMethod:(IMP)aMethod {
|
||||
if ((self = [self init])) {
|
||||
self.class = aClass;
|
||||
self.selector = aSelector;
|
||||
self.originalMethod = aMethod;
|
||||
[self.blocks setObject:aBlock forKey:aName];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
NSString *descriptors = @"";
|
||||
NSString *key;
|
||||
NSEnumerator *keys = [self.blocks keyEnumerator];
|
||||
while ((key = [keys nextObject])) {
|
||||
descriptors = [descriptors stringByAppendingFormat:@"\t%@ : %@\n", key, [self.blocks objectForKey:key]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"Swizzle on %@::%@ [\n%@]", NSStringFromClass(self.class), NSStringFromSelector(self.selector), descriptors];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e89ff6f66840d4d93bc0daf780c702cd
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// TDRunTime.h
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by wwango on 2021/12/30.
|
||||
// When used for plug-in, get the class name and parameters through reflection
|
||||
// This class is not thread-safe, pay attention to multi-threading issues when using it
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TDRunTime : NSObject
|
||||
|
||||
// start reason
|
||||
+ (NSString *)getAppLaunchReason;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c588a4c82821e47059a09450a1a60e46
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// TDRunTime.m
|
||||
// ThinkingSDK
|
||||
//
|
||||
// Created by wwango on 2021/12/30.
|
||||
//
|
||||
|
||||
#import "TDRunTime.h"
|
||||
#import "TDJSONUtil.h"
|
||||
#import "TDPresetProperties+TDDisProperties.h"
|
||||
|
||||
@implementation TDRunTime
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
||||
|
||||
+ (NSString *)getAppLaunchReason {
|
||||
// start reason
|
||||
Class cls = NSClassFromString(@"TDAppLaunchReason");
|
||||
id appLaunch = [cls performSelector:@selector(sharedInstance)];
|
||||
|
||||
if (appLaunch &&
|
||||
[appLaunch respondsToSelector:@selector(appLaunchParams)] &&
|
||||
!TDPresetProperties.disableStartReason)
|
||||
{
|
||||
NSDictionary *startReason = [appLaunch performSelector:@selector(appLaunchParams)];
|
||||
NSString *url = startReason[@"url"];
|
||||
NSDictionary *data = startReason[@"data"];
|
||||
if (url.length == 0 && data.allKeys.count == 0) {
|
||||
return @"";
|
||||
} else {
|
||||
if (data.allKeys.count == 0) {
|
||||
startReason = @{@"url":url, @"data":@""};
|
||||
}
|
||||
NSString *startReasonString = [TDJSONUtil JSONStringForObject:startReason];
|
||||
if (startReasonString && startReasonString.length) {
|
||||
return startReasonString;
|
||||
}
|
||||
}
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c8f9c55d29814f058c83973709b59d9
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
iPhone: iOS
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
AddToEmbeddedBinaries: false
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user