mirror of
https://github.com/kirikayakazuto/CocosCreator_ECS
synced 2024-12-25 11:19:17 +00:00
feat: 修复了找不到comTrans的问题
This commit is contained in:
parent
8a2274fb5b
commit
fdb002d00a
@ -85,18 +85,24 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 26
|
"__id__": 26
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 34
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__id__": 36
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_active": true,
|
"_active": true,
|
||||||
"_components": [
|
"_components": [
|
||||||
{
|
{
|
||||||
"__id__": 34
|
"__id__": 38
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 35
|
"__id__": 39
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"__id__": 36
|
"__id__": 40
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"_prefab": null,
|
"_prefab": null,
|
||||||
@ -1644,6 +1650,196 @@
|
|||||||
"handler": "onClick3",
|
"handler": "onClick3",
|
||||||
"customEventData": ""
|
"customEventData": ""
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "a_role_count",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 35
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_opacity": 255,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 255,
|
||||||
|
"g": 255,
|
||||||
|
"b": 255,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 97.87,
|
||||||
|
"height": 50.4
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_trs": {
|
||||||
|
"__type__": "TypedArray",
|
||||||
|
"ctor": "Float64Array",
|
||||||
|
"array": [
|
||||||
|
-504.601,
|
||||||
|
294.479,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"_eulerAngles": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_skewX": 0,
|
||||||
|
"_skewY": 0,
|
||||||
|
"_is3DNode": false,
|
||||||
|
"_groupIndex": 0,
|
||||||
|
"groupIndex": 0,
|
||||||
|
"_id": "a4JCp5+xFOA4s8fngj8szD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Label",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"node": {
|
||||||
|
"__id__": 34
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"_materials": [
|
||||||
|
{
|
||||||
|
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_srcBlendFactor": 770,
|
||||||
|
"_dstBlendFactor": 771,
|
||||||
|
"_string": "Label",
|
||||||
|
"_N$string": "Label",
|
||||||
|
"_fontSize": 40,
|
||||||
|
"_lineHeight": 40,
|
||||||
|
"_enableWrapText": true,
|
||||||
|
"_N$file": null,
|
||||||
|
"_isSystemFontUsed": true,
|
||||||
|
"_spacingX": 0,
|
||||||
|
"_batchAsBitmap": false,
|
||||||
|
"_styleFlags": 0,
|
||||||
|
"_underlineHeight": 0,
|
||||||
|
"_N$horizontalAlign": 1,
|
||||||
|
"_N$verticalAlign": 1,
|
||||||
|
"_N$fontFamily": "Arial",
|
||||||
|
"_N$overflow": 0,
|
||||||
|
"_N$cacheMode": 0,
|
||||||
|
"_id": "4417a7mtlNhbcCkscLMkuR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Node",
|
||||||
|
"_name": "b_role_count",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"_parent": {
|
||||||
|
"__id__": 2
|
||||||
|
},
|
||||||
|
"_children": [],
|
||||||
|
"_active": true,
|
||||||
|
"_components": [
|
||||||
|
{
|
||||||
|
"__id__": 37
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_prefab": null,
|
||||||
|
"_opacity": 255,
|
||||||
|
"_color": {
|
||||||
|
"__type__": "cc.Color",
|
||||||
|
"r": 255,
|
||||||
|
"g": 255,
|
||||||
|
"b": 255,
|
||||||
|
"a": 255
|
||||||
|
},
|
||||||
|
"_contentSize": {
|
||||||
|
"__type__": "cc.Size",
|
||||||
|
"width": 97.87,
|
||||||
|
"height": 50.4
|
||||||
|
},
|
||||||
|
"_anchorPoint": {
|
||||||
|
"__type__": "cc.Vec2",
|
||||||
|
"x": 0.5,
|
||||||
|
"y": 0.5
|
||||||
|
},
|
||||||
|
"_trs": {
|
||||||
|
"__type__": "TypedArray",
|
||||||
|
"ctor": "Float64Array",
|
||||||
|
"array": [
|
||||||
|
-349.693,
|
||||||
|
294.479,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"_eulerAngles": {
|
||||||
|
"__type__": "cc.Vec3",
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"_skewX": 0,
|
||||||
|
"_skewY": 0,
|
||||||
|
"_is3DNode": false,
|
||||||
|
"_groupIndex": 0,
|
||||||
|
"groupIndex": 0,
|
||||||
|
"_id": "80NAtDFhBOxrIjst58bHAy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"__type__": "cc.Label",
|
||||||
|
"_name": "",
|
||||||
|
"_objFlags": 0,
|
||||||
|
"node": {
|
||||||
|
"__id__": 36
|
||||||
|
},
|
||||||
|
"_enabled": true,
|
||||||
|
"_materials": [
|
||||||
|
{
|
||||||
|
"__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"_srcBlendFactor": 770,
|
||||||
|
"_dstBlendFactor": 771,
|
||||||
|
"_string": "Label",
|
||||||
|
"_N$string": "Label",
|
||||||
|
"_fontSize": 40,
|
||||||
|
"_lineHeight": 40,
|
||||||
|
"_enableWrapText": true,
|
||||||
|
"_N$file": null,
|
||||||
|
"_isSystemFontUsed": true,
|
||||||
|
"_spacingX": 0,
|
||||||
|
"_batchAsBitmap": false,
|
||||||
|
"_styleFlags": 0,
|
||||||
|
"_underlineHeight": 0,
|
||||||
|
"_N$horizontalAlign": 1,
|
||||||
|
"_N$verticalAlign": 1,
|
||||||
|
"_N$fontFamily": "Arial",
|
||||||
|
"_N$overflow": 0,
|
||||||
|
"_N$cacheMode": 0,
|
||||||
|
"_id": "7a9iiLwS1KqqiX/+3BS+Bg"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"__type__": "cc.Canvas",
|
"__type__": "cc.Canvas",
|
||||||
"_name": "",
|
"_name": "",
|
||||||
|
@ -627,6 +627,10 @@ export namespace BT {
|
|||||||
let comTrans = context.world.getComponent(context.entity, ComTransform);
|
let comTrans = context.world.getComponent(context.entity, ComTransform);
|
||||||
let comMonitor = context.world.getComponent(context.entity, ComMonitor);
|
let comMonitor = context.world.getComponent(context.entity, ComMonitor);
|
||||||
let comMovable = context.world.getComponent(context.entity, ComMovable);
|
let comMovable = context.world.getComponent(context.entity, ComMovable);
|
||||||
|
if(comMonitor.others.length <=0){
|
||||||
|
node.state = BT.NodeState.Fail;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
if(comMovable.points.length == 0 || comMovable.pointIdx < 0 || comMovable.pointIdx >= comMovable.points.length) {
|
if(comMovable.points.length == 0 || comMovable.pointIdx < 0 || comMovable.pointIdx >= comMovable.points.length) {
|
||||||
let target = context.world.getComponent(comMonitor.others[0], ComTransform);
|
let target = context.world.getComponent(comMonitor.others[0], ComTransform);
|
||||||
|
|
||||||
|
@ -59,11 +59,11 @@ export default class RoleEventProcess extends EventProcess {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EventType.GraphicsDraw:
|
case EventType.GraphicsDraw:
|
||||||
if(cc.debug.isDisplayStats()) {
|
// if(cc.debug.isDisplayStats()) {
|
||||||
this._graphicsDraw(event as EventGraphicsDraw);
|
// this._graphicsDraw(event as EventGraphicsDraw);
|
||||||
}else {
|
// }else {
|
||||||
this._graphicsDraw(null);
|
// this._graphicsDraw(null);
|
||||||
}
|
// }
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -4,16 +4,14 @@ import { ECSSystem } from "./ECSSystem";
|
|||||||
import { ComPoolIndex, ComType, EntityIndex } from "./Const";
|
import { ComPoolIndex, ComType, EntityIndex } from "./Const";
|
||||||
import { ECSComponentPool } from "./ECSComponentPool";
|
import { ECSComponentPool } from "./ECSComponentPool";
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export class ECSWorld {
|
export class ECSWorld {
|
||||||
private _systems: ECSSystem[] = []; // world内所有的system
|
private _systems: ECSSystem[] = []; // world内所有的system
|
||||||
private _reservedIds: number[] = []; // 缓存
|
private _entityIdxPools: number[] = []; // 回收entity
|
||||||
private _entityToComponents: number[][] = [];
|
private _entityToComponents: number[][] = []; // entity component 二维表
|
||||||
private _componentPools: ECSComponentPool<any>[] = [];
|
private _entitiesToDelete: Set<EntityIndex> = new Set(); // 统一删除entity
|
||||||
private _fillters = new Map<string, ECSFilter>();
|
private _componentPools: ECSComponentPool<any>[] = []; // component pools
|
||||||
private _entitiesToDelete: Set<EntityIndex> = new Set();
|
private _filters = new Map<string, ECSFilter>(); // filter
|
||||||
|
|
||||||
/** 获取ComponentPool */
|
/** 获取ComponentPool */
|
||||||
public getComponentPool<T>(typeOrFunc: ComType | {prototype: T}): ECSComponentPool<T> {
|
public getComponentPool<T>(typeOrFunc: ComType | {prototype: T}): ECSComponentPool<T> {
|
||||||
@ -49,8 +47,8 @@ export class ECSWorld {
|
|||||||
/** 创建实体 */
|
/** 创建实体 */
|
||||||
public createEntity(): number {
|
public createEntity(): number {
|
||||||
let index = -1;
|
let index = -1;
|
||||||
if(this._reservedIds.length > 0) {
|
if(this._entityIdxPools.length > 0) {
|
||||||
index = this._reservedIds.pop();
|
index = this._entityIdxPools.pop();
|
||||||
this._entityToComponents[index].fill(-1);
|
this._entityToComponents[index].fill(-1);
|
||||||
}else {
|
}else {
|
||||||
index = this._entityToComponents.length;
|
index = this._entityToComponents.length;
|
||||||
@ -70,7 +68,7 @@ export class ECSWorld {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._fillters.forEach((fillter, key) => {
|
this._filters.forEach((fillter, key) => {
|
||||||
fillter.isContains(entityIndex) && fillter.onEntityLeave(entityIndex);
|
fillter.isContains(entityIndex) && fillter.onEntityLeave(entityIndex);
|
||||||
});
|
});
|
||||||
for(let system of this._systems) {
|
for(let system of this._systems) {
|
||||||
@ -81,7 +79,7 @@ export class ECSWorld {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getComponentPoolIdx<T>(entityIndex: EntityIndex, com: {prototype: T} | ComType) {
|
public getComponentPoolIdx<T>(entityIndex: EntityIndex, com: {prototype: T} | ComType): ComPoolIndex {
|
||||||
let entity = this._entityToComponents[entityIndex];
|
let entity = this._entityToComponents[entityIndex];
|
||||||
if(!entity) return -1;
|
if(!entity) return -1;
|
||||||
let type = typeof com == 'number' ? com : GetComConstructorType(com);
|
let type = typeof com == 'number' ? com : GetComConstructorType(com);
|
||||||
@ -125,12 +123,11 @@ export class ECSWorld {
|
|||||||
for(let i=0; i<entity.length; i++) {
|
for(let i=0; i<entity.length; i++) {
|
||||||
if(entity[i] == -1) continue;
|
if(entity[i] == -1) continue;
|
||||||
this.getComponentPool(i).free(entity[i]);
|
this.getComponentPool(i).free(entity[i]);
|
||||||
|
entity[i] = -1;
|
||||||
}
|
}
|
||||||
entity.fill(-1);
|
|
||||||
dirty && this.setEntityDirty(entityIndex);
|
dirty && this.setEntityDirty(entityIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public getSingletonComponent<T>(com: {prototype: T}): T {
|
public getSingletonComponent<T>(com: {prototype: T}): T {
|
||||||
let component = this.getComponent(0, com);
|
let component = this.getComponent(0, com);
|
||||||
if(!component) {
|
if(!component) {
|
||||||
@ -140,7 +137,7 @@ export class ECSWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setEntityDirty(entityIndex: EntityIndex): void {
|
public setEntityDirty(entityIndex: EntityIndex): void {
|
||||||
this._fillters.forEach((fillter, key) => {
|
this._filters.forEach((fillter, key) => {
|
||||||
let accept = !this._entitiesToDelete.has(entityIndex) && fillter.isAccept(entityIndex);
|
let accept = !this._entitiesToDelete.has(entityIndex) && fillter.isAccept(entityIndex);
|
||||||
if(accept != fillter.isContains(entityIndex)) {
|
if(accept != fillter.isContains(entityIndex)) {
|
||||||
accept ? fillter.onEntityEnter(entityIndex) : fillter.onEntityLeave(entityIndex);
|
accept ? fillter.onEntityEnter(entityIndex) : fillter.onEntityLeave(entityIndex);
|
||||||
@ -150,14 +147,14 @@ export class ECSWorld {
|
|||||||
|
|
||||||
|
|
||||||
public getFilter(fillterKey: string): ECSFilter {
|
public getFilter(fillterKey: string): ECSFilter {
|
||||||
if(this._fillters.has(fillterKey)) {
|
if(this._filters.has(fillterKey)) {
|
||||||
return this._fillters.get(fillterKey);
|
return this._filters.get(fillterKey);
|
||||||
}
|
}
|
||||||
let [acceptStr, rejectStr] = fillterKey.split("-");
|
let [acceptStr, rejectStr] = fillterKey.split("-");
|
||||||
let accept = acceptStr && acceptStr.length > 0 ? acceptStr.split(',').map(Number) : null;
|
let accept = acceptStr && acceptStr.length > 0 ? acceptStr.split(',').map(Number) : null;
|
||||||
let reject = rejectStr && rejectStr.length > 0 ? rejectStr.split(',').map(Number) : null;
|
let reject = rejectStr && rejectStr.length > 0 ? rejectStr.split(',').map(Number) : null;
|
||||||
let fillter = new ECSFilter(this, accept, reject);
|
let fillter = new ECSFilter(this, accept, reject);
|
||||||
this._fillters.set(fillterKey, fillter);
|
this._filters.set(fillterKey, fillter);
|
||||||
// 将当期的entity放入fillter
|
// 将当期的entity放入fillter
|
||||||
for(let i=1; i<this._entityToComponents.length; i++) {
|
for(let i=1; i<this._entityToComponents.length; i++) {
|
||||||
if(fillter.isAccept(i)) {
|
if(fillter.isAccept(i)) {
|
||||||
@ -179,11 +176,10 @@ export class ECSWorld {
|
|||||||
private _realRemoveEntity() {
|
private _realRemoveEntity() {
|
||||||
this._entitiesToDelete.forEach((value) => {
|
this._entitiesToDelete.forEach((value) => {
|
||||||
this.removeAllComponents(value);
|
this.removeAllComponents(value);
|
||||||
this._reservedIds.push(value);
|
this._entityIdxPools.push(value);
|
||||||
});
|
});
|
||||||
this._entitiesToDelete.clear();
|
this._entitiesToDelete.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GenFillterKey(accepts: ECSComConstructor[], rejects?: ECSComConstructor[]) {
|
export function GenFillterKey(accepts: ECSComConstructor[], rejects?: ECSComConstructor[]) {
|
||||||
|
@ -6,7 +6,7 @@ import { ComTransform } from "../components/ComTransform";
|
|||||||
import { ECSSystem } from "../lib/ECSSystem";
|
import { ECSSystem } from "../lib/ECSSystem";
|
||||||
import { ECSWorld, GenFillterKey } from "../lib/ECSWorld";
|
import { ECSWorld, GenFillterKey } from "../lib/ECSWorld";
|
||||||
|
|
||||||
const FILTER_ATTACKABLE = GenFillterKey([ComAttackable]);
|
const FILTER_ATTACKABLE = GenFillterKey([ComTransform, ComAttackable, ComRoleConfig]);
|
||||||
const FILTER_BEATTACKED = GenFillterKey([ComBeAttacked]);
|
const FILTER_BEATTACKED = GenFillterKey([ComBeAttacked]);
|
||||||
export class SysAttack extends ECSSystem {
|
export class SysAttack extends ECSSystem {
|
||||||
/** 连接 */
|
/** 连接 */
|
||||||
|
@ -54,8 +54,7 @@ export class SysCocosView extends ECSSystem implements ITouchProcessor {
|
|||||||
|
|
||||||
let comRoleConfig = world.getComponent(entity, ComRoleConfig);
|
let comRoleConfig = world.getComponent(entity, ComRoleConfig);
|
||||||
this._loadView(world, entity, comNodeConfig).then((node: cc.Node) => {
|
this._loadView(world, entity, comNodeConfig).then((node: cc.Node) => {
|
||||||
console.log('load view success');
|
console.log('load view success',comNodeConfig.prefabUrl);
|
||||||
|
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@ -75,6 +74,15 @@ export class SysCocosView extends ECSSystem implements ITouchProcessor {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
let layer = cc.find('Canvas/Layers/0');
|
||||||
|
let count1 = 0, count2 = 0;
|
||||||
|
for(const node of layer.children) {
|
||||||
|
node.zIndex = node.y * -1;
|
||||||
|
if(node.name == 'Biker') count1++;
|
||||||
|
if(node.name == 'Cyborg') count2++;
|
||||||
|
}
|
||||||
|
cc.find('Canvas/a_role_count').getComponent(cc.Label).string = '' + count1;
|
||||||
|
cc.find('Canvas/b_role_count').getComponent(cc.Label).string = '' + count2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,6 +16,11 @@ export default class Main extends cc.Component {
|
|||||||
private _touchHandler: ITouchProcessor[] = [];
|
private _touchHandler: ITouchProcessor[] = [];
|
||||||
|
|
||||||
private ecsController = new ECSController();
|
private ecsController = new ECSController();
|
||||||
|
|
||||||
|
protected onLoad(): void {
|
||||||
|
cc.dynamicAtlasManager.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
start () {
|
start () {
|
||||||
this.ecsController.world = this._world = new WorldCocosView();
|
this.ecsController.world = this._world = new WorldCocosView();
|
||||||
this._world.createEntity(); // 创建0号实体
|
this._world.createEntity(); // 创建0号实体
|
||||||
@ -30,15 +35,21 @@ export default class Main extends cc.Component {
|
|||||||
|
|
||||||
//this.regiestTouchHandler();
|
//this.regiestTouchHandler();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick1() {
|
onClick1() {
|
||||||
|
for(let i=0; i<10; i++) {
|
||||||
this.ecsController.createRoleEntity("Biker");
|
this.ecsController.createRoleEntity("Biker");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClick2() {
|
onClick2() {
|
||||||
|
for(let i=0; i<10; i++) {
|
||||||
this.ecsController.createRoleEntity("Cyborg");
|
this.ecsController.createRoleEntity("Cyborg");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClick3() {
|
onClick3() {
|
||||||
cc.debug.setDisplayStats(!cc.debug.isDisplayStats());
|
cc.debug.setDisplayStats(!cc.debug.isDisplayStats());
|
||||||
|
@ -488,7 +488,7 @@
|
|||||||
"node": {
|
"node": {
|
||||||
"__id__": 1
|
"__id__": 1
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": false,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
{
|
{
|
||||||
"__uuid__": "a153945d-2511-4c14-be7b-05d242f47d57"
|
"__uuid__": "a153945d-2511-4c14-be7b-05d242f47d57"
|
||||||
|
@ -488,7 +488,7 @@
|
|||||||
"node": {
|
"node": {
|
||||||
"__id__": 1
|
"__id__": 1
|
||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": false,
|
||||||
"_materials": [
|
"_materials": [
|
||||||
{
|
{
|
||||||
"__uuid__": "a153945d-2511-4c14-be7b-05d242f47d57"
|
"__uuid__": "a153945d-2511-4c14-be7b-05d242f47d57"
|
||||||
|
Loading…
Reference in New Issue
Block a user