Compare commits
6 Commits
b033912633
...
9556d13791
Author | SHA1 | Date | |
---|---|---|---|
9556d13791 | |||
|
f8bd6d380b | ||
|
5d57253d56 | ||
|
6ac808919f | ||
|
5353bc188d | ||
|
f57c0a6190 |
2
dependencies/symbol-processor/src
vendored
2
dependencies/symbol-processor/src
vendored
@ -1 +1 @@
|
||||
Subproject commit 8bca4b7ec6aa28ef6fbc894d1f358468bcc4b321
|
||||
Subproject commit 225eb259fe00348044b7b9008a810204004701df
|
@ -60,3 +60,4 @@ FALSE Food Overlay
|
||||
TRUE Add Splashes
|
||||
TRUE Display Date In Select World Screen
|
||||
TRUE Optimized Chunk Sorting
|
||||
TRUE Disable Buggy Held Item Caching
|
||||
|
@ -132,7 +132,7 @@ static void safe_mprotect(void *addr, size_t len, int prot) {
|
||||
}
|
||||
void _patch(const char *file, int line, void *start, unsigned char patch[4]) {
|
||||
if (((uint32_t) start) % 4 != 0) {
|
||||
ERR("Invalid Address");
|
||||
ERR("Invalid Address: %p", start);
|
||||
}
|
||||
|
||||
// Get Current Permissions
|
||||
|
@ -464,21 +464,22 @@ static int32_t Tile_getColor_injection() {
|
||||
}
|
||||
|
||||
// Disable Hostile AI In Creative Mode
|
||||
#define has_vtable(obj, type) (((void *) obj->vtable) == type##_vtable_base)
|
||||
static Entity *PathfinderMob_findAttackTarget_injection(PathfinderMob *mob) {
|
||||
// Call Original Method
|
||||
Entity *target = mob->vtable->findAttackTarget(mob);
|
||||
|
||||
// Only modify the AI of monsters
|
||||
if (mob->vtable->getCreatureBaseType(mob) != 1) {
|
||||
return target;
|
||||
}
|
||||
|
||||
// Check If Creative Mode
|
||||
if (target != NULL) {
|
||||
bool is_player = has_vtable(target, Player) || has_vtable(target, LocalPlayer) || has_vtable(target, ServerPlayer) || has_vtable(target, RemotePlayer);
|
||||
if (is_player) {
|
||||
Player *player = (Player *) target;
|
||||
Inventory *inventory = player->inventory;
|
||||
bool is_creative = inventory->is_creative;
|
||||
if (is_creative) {
|
||||
target = NULL;
|
||||
}
|
||||
if (target != NULL && target->vtable->isPlayer(target)) {
|
||||
Player *player = (Player *) target;
|
||||
Inventory *inventory = player->inventory;
|
||||
bool is_creative = inventory->is_creative;
|
||||
if (is_creative) {
|
||||
target = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -832,6 +833,16 @@ void init_misc() {
|
||||
overwrite_calls((void *) Player_startUsingItem, (void *) Player_startUsingItem_injection);
|
||||
overwrite_calls((void *) Player_stopUsingItem, (void *) Player_stopUsingItem_injection);
|
||||
|
||||
// Fix invalid ItemInHandRenderer texture cache
|
||||
if (feature_has("Disable Buggy Held Item Caching", server_disabled)) {
|
||||
// This works by forcing MCPI to always use the branch that enables using the
|
||||
// cache, but then patches that as well to do the opposite
|
||||
uchar ensure_equal_patch[] = {0x07, 0x00, 0x57, 0xe1}; // "cmp r7, r7"
|
||||
patch((void *) 0x4b938, ensure_equal_patch);
|
||||
uchar set_true_patch[] = {0x01, 0x30, 0xa0, 0x03}; // "moveq r3, #0x1"
|
||||
patch((void *) 0x4b93c, set_true_patch);
|
||||
}
|
||||
|
||||
// Init C++ And Logging
|
||||
_init_misc_cpp();
|
||||
_init_misc_logging();
|
||||
|
@ -31,7 +31,7 @@ static int32_t sdl_key_to_minecraft_key_injection(int32_t sdl_key) {
|
||||
|
||||
// Open Sign Screen
|
||||
static void LocalPlayer_openTextEdit_injection(LocalPlayer *local_player, TileEntity *sign) {
|
||||
if (sign->id == 4) {
|
||||
if (sign->type == 4) {
|
||||
Minecraft *minecraft = local_player->minecraft;
|
||||
TextEditScreen *screen = alloc_TextEditScreen();
|
||||
ALLOC_CHECK(screen);
|
||||
|
@ -33,7 +33,6 @@ set(SRC
|
||||
src/entity/CameraEntity.def
|
||||
src/entity/EntityRenderer.def
|
||||
src/entity/ItemSpriteRenderer.def
|
||||
src/entity/Sheep.def
|
||||
src/entity/PathfinderMob.def
|
||||
src/entity/HumanoidModel.def
|
||||
src/entity/TripodCameraRenderer.def
|
||||
@ -43,6 +42,15 @@ set(SRC
|
||||
src/entity/animal/AgableMob.def
|
||||
src/entity/animal/Animal.def
|
||||
src/entity/animal/Cow.def
|
||||
src/entity/animal/Chicken.def
|
||||
src/entity/animal/Pig.def
|
||||
src/entity/animal/Sheep.def
|
||||
src/entity/monster/Creeper.def
|
||||
src/entity/monster/Monster.def
|
||||
src/entity/monster/PigZombie.def
|
||||
src/entity/monster/Skeleton.def
|
||||
src/entity/monster/Spider.def
|
||||
src/entity/monster/Zombie.def
|
||||
src/entity/Mob.def
|
||||
src/entity/player/ServerPlayer.def
|
||||
src/entity/player/Player.def
|
||||
@ -122,18 +130,23 @@ set(SRC
|
||||
src/app-platform/AppPlatform_linux.def
|
||||
src/app-platform/AppPlatform_readAssetFile_return_value.def
|
||||
src/tile/LeafTile.def
|
||||
src/tile/DoorTile.def
|
||||
src/tile/Tile.def
|
||||
src/tile/LiquidTile.def
|
||||
src/tile/TallGrass.def
|
||||
src/tile/entity/ChestTileEntity.def
|
||||
src/tile/entity/TileEntity.def
|
||||
src/tile/entity/ChestTileEntity.def
|
||||
src/tile/entity/FurnaceTileEntity.def
|
||||
src/tile/entity/SignTileEntity.def
|
||||
src/tile/entity/TileEntityFactory.def
|
||||
src/tile/entity/TileEntityRenderer.def
|
||||
src/tile/entity/TileEntityRenderDispatcher.def
|
||||
src/tile/StemTile.def
|
||||
src/tile/Tile_SoundType.def
|
||||
src/tile/TileRenderer.def
|
||||
src/tile/GrassTile.def
|
||||
src/tile/HeavyTile.def
|
||||
src/tile/EntityTile.def
|
||||
src/misc/Strings.def
|
||||
src/misc/I18n.def
|
||||
src/misc/SimpleFoodData.def
|
||||
@ -152,6 +165,8 @@ set(SRC
|
||||
src/misc/Random.def
|
||||
src/misc/Mth.def
|
||||
src/misc/Util.def
|
||||
src/misc/Tag.def
|
||||
src/misc/CompoundTag.def
|
||||
src/input/IMoveInput.def
|
||||
src/input/IBuildInput.def
|
||||
src/input/MouseBuildInput.def
|
||||
|
@ -1,6 +1,7 @@
|
||||
virtual-method void remove() = 0x10;
|
||||
virtual-method void tick() = 0x34;
|
||||
virtual-method bool interact(Player *with) = 0x6c;
|
||||
virtual-method void playerTouch(Player *player) = 0x70;
|
||||
virtual-method bool isPlayer() = 0x94;
|
||||
virtual-method bool hurt(Entity *attacker, int damage) = 0xa4;
|
||||
// See https://mcpirevival.miraheze.org/wiki/Minecraft:_Pi_Edition_Complete_Entity_List for these two
|
||||
@ -30,9 +31,9 @@ property float yaw = 0x40;
|
||||
property float pitch = 0x44;
|
||||
property float old_yaw = 0x48;
|
||||
property float old_pitch = 0x4c;
|
||||
property float head_height = 0x68;
|
||||
property float hitbox_width = 0x6c;
|
||||
property float hitbox_height = 0x70;
|
||||
property AABB hitbox = 0x50;
|
||||
property float height_offset = 0x68;
|
||||
property int fire_timer = 0xa0;
|
||||
property int renderer_id = 0xa8;
|
||||
property bool on_ground = 0xb2;
|
||||
property bool freeze_physics = 0xb9;
|
||||
|
@ -1,3 +1,5 @@
|
||||
constructor () = 0x6096c;
|
||||
|
||||
method void assign(uchar entity_id, EntityRenderer *renderer) = 0x6094c;
|
||||
method void render(Entity *entity, float x, float y, float z, float rot, float unknown) = 0x60674;
|
||||
static-method EntityRenderDispatcher *getInstance() = 0x60e90;
|
||||
|
@ -1 +1,7 @@
|
||||
virtual-method void render(Entity *entity, float param_2, float param_3, float param_4, float param_5, float param_6) = 0x8;
|
||||
|
||||
// Can be called without an EntityRenderer, just do EntityRenderer_bindTexture(NULL, &file);
|
||||
method void bindTexture(std::string *file) = 0x62540;
|
||||
|
||||
// Globals
|
||||
static-property EntityRenderDispatcher *entityRenderDispatcher = 0x137bc0;
|
||||
|
@ -1,3 +1,7 @@
|
||||
extends Item;
|
||||
extends Entity;
|
||||
|
||||
vtable 0x10c5b0;
|
||||
constructor (Level *level, float x, float y, float z, ItemInstance *item) = 0x86d70;
|
||||
|
||||
property ItemInstance item = 0xd0;
|
||||
property int age = 0xdc;
|
||||
|
@ -7,6 +7,7 @@ constructor (Level *level) = 0x81b80;
|
||||
virtual-method void actuallyHurt(int damage) = 0x16c;
|
||||
virtual-method void die(Entity *cause) = 0x130;
|
||||
virtual-method ItemInstance *getCarriedItem() = 0x1ac;
|
||||
virtual-method void updateAi() = 0x1cc;
|
||||
virtual-method float getWalkingSpeedModifier() = 0x1e8;
|
||||
|
||||
property int health = 0xec;
|
||||
|
@ -1,3 +1,8 @@
|
||||
extends Mob;
|
||||
|
||||
vtable 0x10b218;
|
||||
|
||||
virtual-method Entity *findAttackTarget() = 0x204;
|
||||
|
||||
property int target_id = 0xbe0;
|
||||
property int running_away_timer = 0xbe8;
|
||||
|
@ -1,3 +1,5 @@
|
||||
extends Entity;
|
||||
|
||||
vtable 0x10c718;
|
||||
|
||||
property int fuse = 0xd0;
|
||||
|
@ -1 +1,7 @@
|
||||
extends AgableMob;
|
||||
|
||||
vtable 0x10b588;
|
||||
|
||||
// This int seems to be unused, and changing it doesn't effect anything
|
||||
// I've called it love_timer because it matches where the love timer is on older java
|
||||
property int love_timer = 0xc00;
|
||||
|
4
symbols/src/entity/animal/Chicken.def
Normal file
4
symbols/src/entity/animal/Chicken.def
Normal file
@ -0,0 +1,4 @@
|
||||
extends Animal;
|
||||
|
||||
vtable 0x10b7d0;
|
||||
constructor (Level *level) = 0x855a0;
|
@ -1,3 +1,4 @@
|
||||
extends Animal;
|
||||
|
||||
vtable 0x10ba38;
|
||||
constructor (Level *level) = 0x857f4;
|
4
symbols/src/entity/animal/Pig.def
Normal file
4
symbols/src/entity/animal/Pig.def
Normal file
@ -0,0 +1,4 @@
|
||||
extends Animal;
|
||||
|
||||
vtable 0x10bc90;
|
||||
constructor (Level *level) = 0x85948;
|
@ -1,3 +1,6 @@
|
||||
extends Animal;
|
||||
|
||||
vtable 0x10bef0;
|
||||
constructor (Level *level) = 0x85da0;
|
||||
|
||||
method void setColor(int color) = 0x86274;
|
4
symbols/src/entity/monster/Creeper.def
Normal file
4
symbols/src/entity/monster/Creeper.def
Normal file
@ -0,0 +1,4 @@
|
||||
extends Monster;
|
||||
|
||||
vtable 0x10ca90;
|
||||
constructor (Level *level) = 0x87fe8;
|
4
symbols/src/entity/monster/Monster.def
Normal file
4
symbols/src/entity/monster/Monster.def
Normal file
@ -0,0 +1,4 @@
|
||||
extends PathfinderMob;
|
||||
|
||||
vtable 0x10cd10;
|
||||
constructor (Level *level) = 0x885c0;
|
4
symbols/src/entity/monster/PigZombie.def
Normal file
4
symbols/src/entity/monster/PigZombie.def
Normal file
@ -0,0 +1,4 @@
|
||||
extends Monster;
|
||||
|
||||
vtable 0x10cf50;
|
||||
constructor (Level *level) = 0x88b4c;
|
4
symbols/src/entity/monster/Skeleton.def
Normal file
4
symbols/src/entity/monster/Skeleton.def
Normal file
@ -0,0 +1,4 @@
|
||||
extends Monster;
|
||||
|
||||
vtable 0x10d208;
|
||||
constructor (Level *level) = 0x89350;
|
4
symbols/src/entity/monster/Spider.def
Normal file
4
symbols/src/entity/monster/Spider.def
Normal file
@ -0,0 +1,4 @@
|
||||
extends Monster;
|
||||
|
||||
vtable 0x10d490;
|
||||
constructor (Level *level) = 0x89618;
|
4
symbols/src/entity/monster/Zombie.def
Normal file
4
symbols/src/entity/monster/Zombie.def
Normal file
@ -0,0 +1,4 @@
|
||||
extends Monster;
|
||||
|
||||
vtable 0x10d8a0;
|
||||
constructor (Level *level) = 0x89cc8;
|
@ -1 +1,5 @@
|
||||
vtable 0x102e58;
|
||||
vtable-size 0x60;
|
||||
|
||||
virtual-method void attack(Player *player, Entity *target) = 0x44;
|
||||
virtual-method void releaseUsingItem(Player *player) = 0x5c;
|
||||
|
@ -14,7 +14,10 @@ virtual-method int getUseDuration(ItemInstance *item_instance) = 0x24;
|
||||
virtual-method ItemInstance useTimeDepleted(ItemInstance *item_instance, Level *level, Player *player) = 0x28;
|
||||
virtual-method int getDestorySpeed(ItemInstance *item_instance, Tile *tile) = 0x2c;
|
||||
virtual-method ItemInstance *use(ItemInstance *item_instance, Level *level, Player *player) = 0x30;
|
||||
virtual-method void hurtEnemy(ItemInstance *itemInstance, Mob *mob) = 0x44;
|
||||
virtual-method bool mineBlock(ItemInstance *instance, int tile_id, int x, int y, int z) = 0x48;
|
||||
// Not just enemy, but any entity
|
||||
virtual-method void interactEnemy(ItemInstance *item_instance, Mob *mob) = 0x54;
|
||||
virtual-method bool isFood() = 0x64;
|
||||
virtual-method bool isArmor() = 0x68;
|
||||
virtual-method void setDescriptionId(std::string *name) = 0x6c;
|
||||
|
@ -5,7 +5,11 @@ constructor tile(Tile *item) = 0x998e4;
|
||||
constructor tile_extra(Tile *item, int count, int auxiliary) = 0x99918;
|
||||
constructor item_extra(Item *item, int count, int auxiliary) = 0x99960;
|
||||
|
||||
static-method ItemInstance *fromTag(CompoundTag *tag) = 0x9a124;
|
||||
|
||||
method void save(CompoundTag *tag) = 0x9a31c;
|
||||
method int getMaxStackSize() = 0x99ac8;
|
||||
method bool isNull() = 0x999b0;
|
||||
|
||||
property int count = 0x0;
|
||||
property int id = 0x4;
|
||||
|
@ -11,10 +11,17 @@ method Entity *getEntity(int id) = 0xa45a4;
|
||||
method bool addEntity(Entity *entity) = 0xa7cbc;
|
||||
method int getBrightness2(LightLayer *layer, int x, int y, int z) = 0xa3c70;
|
||||
method void playSound(Entity *entity, std::string *name, float volume, float pitch) = 0xa42a8;
|
||||
// Searches aabb for entities of type type_id, adds then to buff, returns the number of entities added
|
||||
method int getEntitiesOfType(int type_id, AABB *aabb, std::vector<Entity*> *buff) = 0xa612c;
|
||||
// Searches aabb for entities of base type base_type, adds then to buff, returns the number of entities added
|
||||
method int getEntitiesOfClass(int base_type, AABB *aabb, std::vector<Entity*> *buff) = 0xa6240;
|
||||
// This will implicitly make the tile entity if the tile at x, y, z doesn't have one and is an EntityTile
|
||||
method TileEntity *getTileEntity(int x, int y, int z) = 0xa55d4;
|
||||
|
||||
virtual-method void tick() = 0x28;
|
||||
virtual-method void updateSleepingPlayerList() = 0x2c;
|
||||
virtual-method ChunkCache *createChunkSource() = 0x30;
|
||||
|
||||
property std::vector<Entity *> entities = 0x20;
|
||||
property std::vector<TileEntity *> tileentities = 0x50;
|
||||
property std::vector<Player *> players = 0x60;
|
||||
|
@ -2,3 +2,5 @@ virtual-method void startOpen() = 0x24;
|
||||
virtual-method void stopOpen() = 0x28;
|
||||
virtual-method ItemInstance *getItem(int slot) = 0x8;
|
||||
virtual-method void setItem(int slot, ItemInstance *item_instance) = 0xc;
|
||||
virtual-method int getContainerSize() = 0x18;
|
||||
virtual-method std::vector<ItemInstance> getSlotCopies() = 0x2c;
|
||||
|
@ -5,5 +5,6 @@ method void selectSlot(int slot) = 0x8d13c;
|
||||
method ItemInstance *getSelected() = 0x8d134;
|
||||
// It's just FillingContainer_linkSlot with selectedSlot as linked_slot
|
||||
method bool moveToSelectedSlot(int unlinked_slot, bool push_aside) = 0x8d148;
|
||||
method void setupDefault() = 0x8d164;
|
||||
|
||||
property int selectedSlot = 0x28;
|
||||
|
10
symbols/src/misc/CompoundTag.def
Normal file
10
symbols/src/misc/CompoundTag.def
Normal file
@ -0,0 +1,10 @@
|
||||
extends Tag;
|
||||
|
||||
vtable-size 0x34;
|
||||
size 0x24;
|
||||
constructor (std::string name) = 0x69740;
|
||||
|
||||
method bool getBoolean(std::string *name) = 0xd1b28;
|
||||
method short getShort(std::string *name) = 0x459c0;
|
||||
method bool contains(std::string *name, int type) = 0x7d130;
|
||||
method void put(std::string *name, Tag *tag) = 0x6a040;
|
1
symbols/src/misc/Tag.def
Normal file
1
symbols/src/misc/Tag.def
Normal file
@ -0,0 +1 @@
|
||||
constructor () = 0x684e0;
|
@ -2,6 +2,7 @@ vtable 0x109ae8;
|
||||
|
||||
constructor () = 0x73b20;
|
||||
|
||||
virtual-method void sendTo(RakNet_RakNetGUID *guid, Packet *packet) = 0x3c;
|
||||
virtual-method void send(Packet *packet) = 0x38;
|
||||
virtual-method uint isServer() = 0x48;
|
||||
virtual-method void pingForHosts(int base_port) = 0x14;
|
||||
|
5
symbols/src/tile/DoorTile.def
Normal file
5
symbols/src/tile/DoorTile.def
Normal file
@ -0,0 +1,5 @@
|
||||
extends Tile;
|
||||
|
||||
vtable 0x111220;
|
||||
|
||||
static-method uint getCompositeData(LevelSource *level, int x, int y, int z) = 0xbde40;
|
7
symbols/src/tile/EntityTile.def
Normal file
7
symbols/src/tile/EntityTile.def
Normal file
@ -0,0 +1,7 @@
|
||||
extends Tile;
|
||||
|
||||
vtable 0x111348;
|
||||
vtable-size 0x108;
|
||||
size 0x5c;
|
||||
|
||||
virtual-method TileEntity *newTileEntity() = 0x104;
|
@ -26,6 +26,7 @@ virtual-method void onRemove(Level *level, int x, int y, int z) = 0x6c;
|
||||
virtual-method int getRenderLayer() = 0x94;
|
||||
virtual-method int use(Level *level, int x, int y, int z, Player *player) = 0x98;
|
||||
virtual-method void setPlacedBy(Level *level, int x, int y, int z, Mob *placer) = 0xa8;
|
||||
virtual-method void handleEntityInside(Level *level, int x, int y, int z, Entity *entity, Vec3 *speed) = 0xb4;
|
||||
virtual-method int getColor(LevelSource *level_source, int x, int y, int z) = 0xb8;
|
||||
virtual-method void entityInside(Level *level, int x, int y, int z, Entity *entity) = 0xcc;
|
||||
virtual-method std::string getDescriptionId() = 0xdc;
|
||||
@ -40,8 +41,10 @@ property int id = 0x8;
|
||||
property int category = 0x3c;
|
||||
property AABB aabb = 0x40;
|
||||
|
||||
// Globals
|
||||
// Globals, all of theses are 256 elements long
|
||||
static-property-array Tile *tiles = 0x180e08;
|
||||
static-property-array float lightEmission = 0x181214;
|
||||
static-property-array bool isEntityTile = 0x181f20;
|
||||
|
||||
// Tiles
|
||||
static-property Tile *chest = 0x181d60;
|
||||
@ -70,6 +73,3 @@ static-property Tile *grass_carried = 0x181dd4;
|
||||
|
||||
// Sounds
|
||||
static-property Tile_SoundType SOUND_STONE = 0x181c80;
|
||||
|
||||
// Light
|
||||
static-property float *lightEmission = 0x181214;
|
||||
|
@ -1,5 +1,24 @@
|
||||
property int id = 0x18;
|
||||
property int renderer_id = 0x24;
|
||||
size 0x30;
|
||||
vtable-size 0x28;
|
||||
vtable 0x115d78;
|
||||
constructor (int type) = 0xd2308;
|
||||
|
||||
static-method void setId(int id, std::string *name) = 0xd26fc;
|
||||
static-method void initTileEntities() = 0xd2834;
|
||||
|
||||
virtual-method bool shouldSave() = 0x8;
|
||||
virtual-method void load(CompoundTag *tag) = 0xc;
|
||||
virtual-method bool save(CompoundTag *tag) = 0x10;
|
||||
virtual-method void tick() = 0x14;
|
||||
|
||||
property Level *level = 0x4;
|
||||
property int x = 0x8;
|
||||
property int y = 0xc;
|
||||
property int z = 0x10;
|
||||
property int tile_data = 0x14;
|
||||
property int type = 0x18;
|
||||
property int id = 0x1c;
|
||||
property bool is_client = 0x20;
|
||||
property int tile = 0xd0;
|
||||
property int lifetime = 0xd8;
|
||||
property int renderer_id = 0x24;
|
||||
property Tile *tile = 0x28;
|
||||
property bool pending_removal = 0x2c;
|
||||
|
1
symbols/src/tile/entity/TileEntityFactory.def
Normal file
1
symbols/src/tile/entity/TileEntityFactory.def
Normal file
@ -0,0 +1 @@
|
||||
static-method TileEntity *createTileEntity(int type) = 0xd226c;
|
4
symbols/src/tile/entity/TileEntityRenderDispatcher.def
Normal file
4
symbols/src/tile/entity/TileEntityRenderDispatcher.def
Normal file
@ -0,0 +1,4 @@
|
||||
constructor () = 0x66f18;
|
||||
|
||||
property Level *level = 0x4;
|
||||
property std::map<int, TileEntityRenderer *> renderer_map = 0x24;
|
11
symbols/src/tile/entity/TileEntityRenderer.def
Normal file
11
symbols/src/tile/entity/TileEntityRenderer.def
Normal file
@ -0,0 +1,11 @@
|
||||
size 0x8;
|
||||
|
||||
vtable 0x1081c0;
|
||||
vtable-size 0x14;
|
||||
constructor () = 0x67620;
|
||||
|
||||
virtual-method void render(TileEntity *tileentity, float x, float y, float z, float unknown) = 0x8;
|
||||
virtual-method void onGraphicsReset() = 0xc;
|
||||
virtual-method void onNewLevel(Level *level) = 0x10;
|
||||
|
||||
property TileEntityRenderDispatcher *tileEntityRenderDispatcher = 0x4;
|
Loading…
Reference in New Issue
Block a user