Changes on Attachment Manager.
Removed attachment due to failure in attachment manager. Changed Database to Live Database -> will be changed after Master merge Add to enteties.ts RageObject and RageObjectPool for Attachment Manager
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
import { IEntity, IPlayer, IEntityAttachments, IEntityAttachmentPool, IPlayerPool, IVehicle, IVehiclePool, VehicleSeat, EntityType } from "../../game";
|
import { IEntity, IPlayer, IEntityAttachments, IEntityAttachmentPool, IPlayerPool, IVehicle, IVehiclePool, VehicleSeat, EntityType, IObjectPool, IObject } from "../../game";
|
||||||
import { parseJson } from "../../util";
|
import { parseJson } from "../../util";
|
||||||
import game from "../..";
|
import game from "../..";
|
||||||
|
|
||||||
class RageEntity implements IEntity {
|
class RageEntity implements IEntity {
|
||||||
private entity: EntityMp;
|
private entity: EntityMp;
|
||||||
|
public __attachments: any[];
|
||||||
|
public __attachmentObjects: any[];
|
||||||
|
|
||||||
get id(): number {
|
get id(): number {
|
||||||
if (!this.entity) {
|
if (!this.entity) {
|
||||||
@@ -57,8 +59,6 @@ class RageEntity implements IEntity {
|
|||||||
|
|
||||||
class RagePlayer extends RageEntity implements IPlayer {
|
class RagePlayer extends RageEntity implements IPlayer {
|
||||||
private player: PlayerMp;
|
private player: PlayerMp;
|
||||||
public __attachments: any[];
|
|
||||||
public __attachmentObjects: any[];
|
|
||||||
|
|
||||||
get name(): string {
|
get name(): string {
|
||||||
return this.player.name;
|
return this.player.name;
|
||||||
@@ -176,6 +176,20 @@ class RagePlayerPool implements IPlayerPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RageObject extends RageEntity implements IObject {
|
||||||
|
public object: ObjectMp;
|
||||||
|
public __attachmentData: object;
|
||||||
|
|
||||||
|
constructor(object: ObjectMp, attachmentData: object) {
|
||||||
|
if (!object) {
|
||||||
|
throw "Object is undefined"
|
||||||
|
}
|
||||||
|
super(object);
|
||||||
|
this.object = object;
|
||||||
|
this.__attachmentData = attachmentData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class RageVehicle extends RageEntity implements IVehicle {
|
class RageVehicle extends RageEntity implements IVehicle {
|
||||||
private vehicle: VehicleMp;
|
private vehicle: VehicleMp;
|
||||||
|
|
||||||
@@ -212,6 +226,38 @@ class RageVehicle extends RageEntity implements IVehicle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RageObjectPool implements IObjectPool {
|
||||||
|
public attachmentDataMap: Map<ObjectMp, object>;
|
||||||
|
|
||||||
|
|
||||||
|
setData(entity: ObjectMp, attachmentData: object): void {
|
||||||
|
if (!this.attachmentDataMap)
|
||||||
|
this.attachmentDataMap = new Map<ObjectMp, object>();
|
||||||
|
|
||||||
|
this.attachmentDataMap.set(entity, attachmentData);
|
||||||
|
}
|
||||||
|
|
||||||
|
at(id: number): IObject {
|
||||||
|
var object = mp.objects.atRemoteId(Number(id));
|
||||||
|
|
||||||
|
if (!object)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new RageObject(object, this.attachmentDataMap.get(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
forEach(fn: (entity: IObject) => void): void {
|
||||||
|
mp.objects.forEach(e => {
|
||||||
|
if (!e) {
|
||||||
|
game.ui.sendChatMessage("forEach - e is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fn(new RageObject(e, this.attachmentDataMap.get(e)));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class RageVehiclePool implements IVehiclePool {
|
class RageVehiclePool implements IVehiclePool {
|
||||||
at(id: number): IVehicle {
|
at(id: number): IVehicle {
|
||||||
var veh = mp.vehicles.atRemoteId(Number(id));
|
var veh = mp.vehicles.atRemoteId(Number(id));
|
||||||
@@ -242,4 +288,6 @@ export {
|
|||||||
RageEntityAttachmentPool,
|
RageEntityAttachmentPool,
|
||||||
RageVehicle,
|
RageVehicle,
|
||||||
RageVehiclePool,
|
RageVehiclePool,
|
||||||
|
RageObject,
|
||||||
|
RageObjectPool,
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
import { IGame, IUi, IEvents, IPlayerPool, IVehiclePool, IEntityAttachmentPool } from "../../game";
|
import { IGame, IUi, IEvents, IPlayerPool, IVehiclePool, IEntityAttachmentPool, IObjectPool } from "../../game";
|
||||||
import RageEvents from "./events";
|
import RageEvents from "./events";
|
||||||
import RageUi from "./ui";
|
import RageUi from "./ui";
|
||||||
import { RagePlayerPool, RageVehiclePool, RageEntityAttachmentPool } from "./entities";
|
import { RagePlayerPool, RageVehiclePool, RageEntityAttachmentPool, RageObjectPool } from "./entities";
|
||||||
|
|
||||||
export default class RageGame implements IGame {
|
export default class RageGame implements IGame {
|
||||||
players: IPlayerPool = new RagePlayerPool();
|
players: IPlayerPool = new RagePlayerPool();
|
||||||
vehicles: IVehiclePool = new RageVehiclePool();
|
vehicles: IVehiclePool = new RageVehiclePool();
|
||||||
attachments: IEntityAttachmentPool = new RageEntityAttachmentPool();
|
attachments: IEntityAttachmentPool = new RageEntityAttachmentPool();
|
||||||
|
objects: IObjectPool = new RageObjectPool();
|
||||||
events: IEvents = new RageEvents;
|
events: IEvents = new RageEvents;
|
||||||
ui: IUi = new RageUi;
|
ui: IUi = new RageUi;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
players: IPlayerPool;
|
players: IPlayerPool;
|
||||||
vehicles: IVehiclePool;
|
vehicles: IVehiclePool;
|
||||||
attachments: IEntityAttachmentPool;
|
attachments: IEntityAttachmentPool;
|
||||||
|
objects: IObjectPool;
|
||||||
|
|
||||||
disableDefaultEngineBehaviour(): void;
|
disableDefaultEngineBehaviour(): void;
|
||||||
}
|
}
|
||||||
@@ -54,6 +55,10 @@ interface IPlayer extends IEntity {
|
|||||||
vehicle: IVehicle;
|
vehicle: IVehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IObject extends IEntity {
|
||||||
|
__attachmentData: object;
|
||||||
|
}
|
||||||
|
|
||||||
interface IEntityAttachments {
|
interface IEntityAttachments {
|
||||||
remoteId: any;
|
remoteId: any;
|
||||||
__attachments: any[];
|
__attachments: any[];
|
||||||
@@ -74,6 +79,10 @@ interface IEntityPool<TEntity> {
|
|||||||
forEach(fn: (entity: TEntity) => void): void;
|
forEach(fn: (entity: TEntity) => void): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IObjectPool extends IEntityPool<IObject> {
|
||||||
|
setData(entity: ObjectMp, attachmentData: object): void;
|
||||||
|
}
|
||||||
|
|
||||||
interface IPlayerPool extends IEntityPool<IPlayer> {
|
interface IPlayerPool extends IEntityPool<IPlayer> {
|
||||||
local: IPlayer;
|
local: IPlayer;
|
||||||
}
|
}
|
||||||
@@ -149,6 +158,7 @@ export {
|
|||||||
IBrowser,
|
IBrowser,
|
||||||
|
|
||||||
IPlayer,
|
IPlayer,
|
||||||
|
IObject,
|
||||||
IEntityAttachments,
|
IEntityAttachments,
|
||||||
IEntityAttachmentPool,
|
IEntityAttachmentPool,
|
||||||
IVehicle,
|
IVehicle,
|
||||||
@@ -156,6 +166,7 @@ export {
|
|||||||
IEntityPool,
|
IEntityPool,
|
||||||
IPlayerPool,
|
IPlayerPool,
|
||||||
IVehiclePool,
|
IVehiclePool,
|
||||||
|
IObjectPool,
|
||||||
|
|
||||||
EventName,
|
EventName,
|
||||||
Key,
|
Key,
|
||||||
|
|||||||
@@ -23,40 +23,62 @@ export default function attachmentManager(game: IGame) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
++attachId;
|
|
||||||
|
|
||||||
let entity: IEntity;
|
let entity: IEntity;
|
||||||
if (entityRage.type === "player") {
|
if (entityRage.type === "player") {
|
||||||
var player = game.players.at(entityRage.remoteId);
|
var player = game.players.at(entityRage.remoteId);
|
||||||
entity = player;
|
entity = player;
|
||||||
mp.gui.chat.push(`ATTACH: ${attachId} - Player: ${player.name}`);
|
|
||||||
|
|
||||||
} else if (entityRage.type === "vehicle") {
|
} else if (entityRage.type === "vehicle") {
|
||||||
var vehicle = game.vehicles.at(entityRage.remoteId);
|
var vehicle = game.vehicles.at(entityRage.remoteId);
|
||||||
entity = vehicle;
|
entity = vehicle;
|
||||||
var realName = mp.game.ui.getLabelText(mp.game.vehicle.getDisplayNameFromVehicleModel(entityRage.model));
|
var realName = mp.game.ui.getLabelText(mp.game.vehicle.getDisplayNameFromVehicleModel(entityRage.model));
|
||||||
mp.gui.chat.push(`ATTACH: ${attachId} - Vehicle: ${vehicle.remoteId}, ${realName}`);
|
} else if (entityRage.type === "object") {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let e = game.attachments.get(entity);
|
let e = game.attachments.get(entity);
|
||||||
|
|
||||||
if (this.attachments.hasOwnProperty(id)) {
|
if (this.attachments.hasOwnProperty(id)) {
|
||||||
if (e.__attachmentObjects == undefined) { e.__attachmentObjects = []; }
|
|
||||||
|
|
||||||
|
if (!e.__attachmentObjects) { e.__attachmentObjects = []; }
|
||||||
|
|
||||||
|
|
||||||
if (!e.__attachmentObjects.hasOwnProperty(id)) {
|
if (!e.__attachmentObjects.hasOwnProperty(id)) {
|
||||||
|
|
||||||
|
|
||||||
let attInfo = this.attachments[id];
|
let attInfo = this.attachments[id];
|
||||||
let object = mp.objects.new(attInfo.model, entityRage.position);
|
let rageObject = mp.objects.new(attInfo.model, entityRage.position);
|
||||||
|
|
||||||
|
|
||||||
var bone = (typeof (attInfo.boneName) === 'string') ? entityRage.getBoneIndexByName(attInfo.boneName) : entityRage.getBoneIndex(attInfo.boneName)
|
var bone = (typeof (attInfo.boneName) === 'string') ? entityRage.getBoneIndexByName(attInfo.boneName) : entityRage.getBoneIndex(attInfo.boneName)
|
||||||
|
|
||||||
|
let attachmentData = {
|
||||||
|
targetEntity: entity.id,
|
||||||
|
bone: bone,
|
||||||
|
offset: attInfo.offset,
|
||||||
|
rotation: attInfo.rotation
|
||||||
|
};
|
||||||
|
|
||||||
|
game.objects.setData(rageObject, attachmentData); // hier hakt es mein freund
|
||||||
|
|
||||||
|
let object = game.objects.at(rageObject.remoteId);
|
||||||
|
|
||||||
|
//DEBUG MSG
|
||||||
mp.gui.chat.push(`ATTACH: ${attachId} - bone = ${bone}`)
|
mp.gui.chat.push(`ATTACH: ${attachId} - bone = ${bone}`)
|
||||||
|
|
||||||
object.attachTo(entity.id,
|
rageObject.notifyStreaming = true;
|
||||||
bone,
|
mp.gui.chat.push("Notified Stream.");
|
||||||
attInfo.offset.x, attInfo.offset.y, attInfo.offset.z,
|
game.wait(200);
|
||||||
attInfo.rotation.x, attInfo.rotation.y, attInfo.rotation.z,
|
|
||||||
false, false, false, false, 2, true);
|
//DEBUG MSG
|
||||||
mp.gui.chat.push(`ATTACH: ${attachId} - Attaching ${JSON.stringify(attInfo)}`);
|
mp.gui.chat.push(`ATTACH: ${attachId} - Attaching ${JSON.stringify(attInfo)}`);
|
||||||
e.__attachmentObjects[id] = object;
|
e.__attachmentObjects[id] = rageObject;;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* else {
|
/* else {
|
||||||
@@ -187,15 +209,46 @@ export default function attachmentManager(game: IGame) {
|
|||||||
mp.events.add("entityStreamIn", (entityRage) => {
|
mp.events.add("entityStreamIn", (entityRage) => {
|
||||||
if (entityRage.type === "player" || entityRage.type === "vehicle") {
|
if (entityRage.type === "player" || entityRage.type === "vehicle") {
|
||||||
let entity;
|
let entity;
|
||||||
|
|
||||||
if (entityRage.type === "player") {
|
if (entityRage.type === "player") {
|
||||||
entity = game.players.at(entityRage.remoteId);
|
entity = game.players.at(entityRage.remoteId);
|
||||||
} else if (entityRage.type === "vehicle") {
|
} else if (entityRage.type === "vehicle") {
|
||||||
entity = game.vehicles.at(entityRage.remoteId);
|
entity = game.vehicles.at(entityRage.remoteId);
|
||||||
}
|
}
|
||||||
let e = game.attachments.get(entity);
|
|
||||||
|
if (entityRage.tye === "object") { //if is object
|
||||||
|
game.wait(200);
|
||||||
|
|
||||||
|
mp.gui.chat.push("object streamed");
|
||||||
|
entity = game.objects.at(entityRage.remoteId);
|
||||||
|
|
||||||
|
game.wait(200);
|
||||||
|
mp.gui.chat.push("object try get data");
|
||||||
|
game.wait(200);
|
||||||
|
|
||||||
|
|
||||||
|
const { targetEntity, bone, offset, rotation } = entity.__attachmentData;
|
||||||
|
game.wait(200);
|
||||||
|
|
||||||
|
+
|
||||||
|
mp.gui.chat.push(targetEntity + "," + bone + "," + offset + "," + rotation);
|
||||||
|
game.wait(200);
|
||||||
|
|
||||||
|
|
||||||
|
entity.attachTo(
|
||||||
|
targetEntity, bone,
|
||||||
|
offset.x, offset.y, offset.z,
|
||||||
|
rotation.x, rotation.y, rotation.z,
|
||||||
|
false, false, false, false, 2, true
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let e = game.attachments.get(entity); //if player or vehicle
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
if (e.__attachments) {
|
if (e.__attachments) {
|
||||||
game.wait(5000);
|
|
||||||
attachmentMngr.initFor(entityRage);
|
attachmentMngr.initFor(entityRage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,7 +335,7 @@ export default function attachmentManager(game: IGame) {
|
|||||||
e.__attachmentObjects = [];
|
e.__attachmentObjects = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
game.vehicles.forEach(_veh => {
|
game.vehicles.forEach(_veh => {
|
||||||
let vehicle = mp.vehicles.at(_veh.remoteId);
|
let vehicle = mp.vehicles.at(_veh.remoteId);
|
||||||
|
|
||||||
@@ -304,7 +357,9 @@ export default function attachmentManager(game: IGame) {
|
|||||||
e.__attachmentObjects = [];
|
e.__attachmentObjects = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
mp.events.add("playerReady", () => { //player finished doenloading assets from server.
|
||||||
InitAttachmentsOnJoin();
|
InitAttachmentsOnJoin();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -30,7 +30,7 @@ namespace ReallifeGamemode.Database.Models
|
|||||||
optionsBuilder.UseLoggerFactory(LoggerFactory);
|
optionsBuilder.UseLoggerFactory(LoggerFactory);
|
||||||
}
|
}
|
||||||
optionsBuilder.EnableSensitiveDataLogging();
|
optionsBuilder.EnableSensitiveDataLogging();
|
||||||
optionsBuilder.UseMySql("Host=localhost;Port=3306;Database=gtav-devdb;Username=gtav-dev;Password=Test123");
|
optionsBuilder.UseMySql("Host=localhost;Port=3306;Database=gta-livedb;Username=gtav-live;Password=u8vbCADW--TY6iTsDycB88i&WsITj&o2");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace ReallifeGamemode.Server.Events
|
|||||||
{
|
{
|
||||||
ChatService.BroadcastAdmin("!{#FFFF00}*** " + player.Name + " hat den Server verlassen", AdminLevel.MAPPING);
|
ChatService.BroadcastAdmin("!{#FFFF00}*** " + player.Name + " hat den Server verlassen", AdminLevel.MAPPING);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
TaxiDriverJob taxiJob = JobManager.GetJob<TaxiDriverJob>();
|
TaxiDriverJob taxiJob = JobManager.GetJob<TaxiDriverJob>();
|
||||||
TaxiContract taxiContract = taxiJob.TaxiContracts.Where(t => t.Name == player.Name).FirstOrDefault();
|
TaxiContract taxiContract = taxiJob.TaxiContracts.Where(t => t.Name == player.Name).FirstOrDefault();
|
||||||
|
|
||||||
@@ -64,6 +64,7 @@ namespace ReallifeGamemode.Server.Events
|
|||||||
taxiJob.TaxiContracts.Remove(taxiContract);
|
taxiJob.TaxiContracts.Remove(taxiContract);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
var listReports = Report.Report.listReports;
|
var listReports = Report.Report.listReports;
|
||||||
ReportManage temp;
|
ReportManage temp;
|
||||||
for (int a = 0; a < listReports.Count; a++)
|
for (int a = 0; a < listReports.Count; a++)
|
||||||
|
|||||||
@@ -358,12 +358,13 @@ namespace ReallifeGamemode.Server.Events
|
|||||||
|
|
||||||
using (var context = new DatabaseContext())
|
using (var context = new DatabaseContext())
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
if (player.HasAttachment("ammobox"))
|
if (player.HasAttachment("ammobox"))
|
||||||
{
|
{
|
||||||
player.AddAttachment("ammobox", true);
|
player.AddAttachment("ammobox", true);
|
||||||
player.StopAnimation();
|
player.StopAnimation();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
bool unloadedWeaponPackage = false;
|
bool unloadedWeaponPackage = false;
|
||||||
|
|
||||||
List<UserItem> fItem = context.UserItems.Where(u => u.UserId == user.Id).ToList();
|
List<UserItem> fItem = context.UserItems.Where(u => u.UserId == user.Id).ToList();
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ namespace ReallifeGamemode.Server.Inventory
|
|||||||
if (!player.HasAttachment("ammobox"))
|
if (!player.HasAttachment("ammobox"))
|
||||||
{
|
{
|
||||||
player.PlayAnimation("anim@heists@box_carry@", "idle", 49);
|
player.PlayAnimation("anim@heists@box_carry@", "idle", 49);
|
||||||
player.AddAttachment("ammobox", false);
|
//player.AddAttachment("ammobox", false);
|
||||||
NAPI.Player.SetPlayerCurrentWeapon(player, WeaponHash.Unarmed);
|
NAPI.Player.SetPlayerCurrentWeapon(player, WeaponHash.Unarmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ namespace ReallifeGamemode.Server.Job
|
|||||||
Player target = data.getPartnerClient(player);
|
Player target = data.getPartnerClient(player);
|
||||||
if (target != null) target.TriggerEvent("MuellmannUpdateColshape", colshapeIndex);
|
if (target != null) target.TriggerEvent("MuellmannUpdateColshape", colshapeIndex);
|
||||||
player.TriggerEvent("renderTextOnScreen", "Wirf den Müllsack in den Müllwagen.");
|
player.TriggerEvent("renderTextOnScreen", "Wirf den Müllsack in den Müllwagen.");
|
||||||
player.AddAttachment("binbag", false);
|
//player.AddAttachment("binbag", false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,7 +277,7 @@ namespace ReallifeGamemode.Server.Job
|
|||||||
}
|
}
|
||||||
dbContext.SaveChanges();
|
dbContext.SaveChanges();
|
||||||
}
|
}
|
||||||
player.AddAttachment("binbag", true);
|
// player.AddAttachment("binbag", true);
|
||||||
|
|
||||||
if (player.GetUser(dbContext).trashcount >= 20)
|
if (player.GetUser(dbContext).trashcount >= 20)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ public class BehindVehiclePoint
|
|||||||
if (!player.HasAttachment("ammobox"))
|
if (!player.HasAttachment("ammobox"))
|
||||||
{
|
{
|
||||||
player.PlayAnimation("anim@heists@box_carry@", "idle", 49);
|
player.PlayAnimation("anim@heists@box_carry@", "idle", 49);
|
||||||
player.AddAttachment("ammobox", false);
|
//player.AddAttachment("ammobox", false);
|
||||||
NAPI.Player.SetPlayerCurrentWeapon(player, WeaponHash.Unarmed);
|
NAPI.Player.SetPlayerCurrentWeapon(player, WeaponHash.Unarmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ public class AttachmentSyncExample : Script
|
|||||||
player.AddAttachment(Base36Extensions.FromBase36(hash), true);
|
player.AddAttachment(Base36Extensions.FromBase36(hash), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* [Command("xdd")]
|
//[Command("xdd")]
|
||||||
public void attachment(Player player)
|
public void attachment(Player player)
|
||||||
{
|
{
|
||||||
Vehicle veh = player.Vehicle;
|
Vehicle veh = player.Vehicle;
|
||||||
@@ -152,7 +152,7 @@ public class AttachmentSyncExample : Script
|
|||||||
veh.ClearAttachments();
|
veh.ClearAttachments();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user