mirror of
				https://github.com/unanmed/HumanBreak.git
				synced 2025-11-04 07:02:58 +08:00 
			
		
		
		
	传送门绘制
This commit is contained in:
		
							parent
							
								
									f7c3f008d5
								
							
						
					
					
						commit
						af38d2e47e
					
				
							
								
								
									
										223
									
								
								src/core/fx/canvas2d.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								src/core/fx/canvas2d.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,223 @@
 | 
			
		||||
import { parseCss } from '@/plugin/utils';
 | 
			
		||||
import { EmitableEvent, EventEmitter } from '../common/eventEmitter';
 | 
			
		||||
import { CSSObj } from '../interface';
 | 
			
		||||
 | 
			
		||||
interface OffscreenCanvasEvent extends EmitableEvent {
 | 
			
		||||
    resize: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class MotaOffscreenCanvas2D extends EventEmitter<OffscreenCanvasEvent> {
 | 
			
		||||
    static list: Set<MotaOffscreenCanvas2D> = new Set();
 | 
			
		||||
 | 
			
		||||
    canvas: HTMLCanvasElement;
 | 
			
		||||
    ctx: CanvasRenderingContext2D;
 | 
			
		||||
 | 
			
		||||
    width: number;
 | 
			
		||||
    height: number;
 | 
			
		||||
 | 
			
		||||
    /** 是否自动跟随样板的core.domStyle.scale进行缩放 */
 | 
			
		||||
    autoScale: boolean = false;
 | 
			
		||||
    /** 是否是高清画布 */
 | 
			
		||||
    highResolution: boolean = true;
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.canvas = document.createElement('canvas');
 | 
			
		||||
        this.ctx = this.canvas.getContext('2d')!;
 | 
			
		||||
        this.width = this.canvas.width / devicePixelRatio;
 | 
			
		||||
        this.height = this.canvas.height / devicePixelRatio;
 | 
			
		||||
 | 
			
		||||
        this.canvas.style.position = 'absolute';
 | 
			
		||||
 | 
			
		||||
        MotaOffscreenCanvas2D.list.add(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置画布的大小
 | 
			
		||||
     */
 | 
			
		||||
    size(width: number, height: number) {
 | 
			
		||||
        let ratio = this.highResolution ? devicePixelRatio : 1;
 | 
			
		||||
        if (this.autoScale && this.highResolution) {
 | 
			
		||||
            ratio *= core.domStyle.scale;
 | 
			
		||||
        }
 | 
			
		||||
        this.canvas.width = width * ratio;
 | 
			
		||||
        this.canvas.height = height * ratio;
 | 
			
		||||
        this.width = width;
 | 
			
		||||
        this.height = height;
 | 
			
		||||
        this.ctx.setTransform(1, 0, 0, 1, 0, 0);
 | 
			
		||||
        this.ctx.scale(ratio, ratio);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置当前画布是否跟随样板的 core.domStyle.scale 一同进行缩放
 | 
			
		||||
     */
 | 
			
		||||
    withGameScale(auto: boolean) {
 | 
			
		||||
        this.autoScale = auto;
 | 
			
		||||
        this.size(this.width, this.height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置当前画布是否为高清画布
 | 
			
		||||
     */
 | 
			
		||||
    setHD(hd: boolean) {
 | 
			
		||||
        this.highResolution = hd;
 | 
			
		||||
        this.size(this.width, this.height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除这个画布
 | 
			
		||||
     */
 | 
			
		||||
    delete() {
 | 
			
		||||
        MotaCanvas2D.list.delete(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 复制一个离屏Canvas2D对象或Canvas2D对象,一般用于缓存等操作
 | 
			
		||||
     * @param canvas 被复制的MotaOffscreenCanvas2D对象
 | 
			
		||||
     * @returns 复制结果
 | 
			
		||||
     */
 | 
			
		||||
    static clone(canvas: MotaOffscreenCanvas2D): MotaOffscreenCanvas2D {
 | 
			
		||||
        const newCanvas = new MotaOffscreenCanvas2D();
 | 
			
		||||
        newCanvas.setHD(canvas.highResolution);
 | 
			
		||||
        newCanvas.withGameScale(canvas.autoScale);
 | 
			
		||||
        newCanvas.size(canvas.width, canvas.height);
 | 
			
		||||
        newCanvas.ctx.drawImage(canvas.canvas, 0, 0);
 | 
			
		||||
        return newCanvas;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class MotaCanvas2D extends MotaOffscreenCanvas2D {
 | 
			
		||||
    static map: Map<string, MotaCanvas2D> = new Map();
 | 
			
		||||
 | 
			
		||||
    id: string = '';
 | 
			
		||||
 | 
			
		||||
    x: number = 0;
 | 
			
		||||
    y: number = 0;
 | 
			
		||||
 | 
			
		||||
    private mounted: boolean = false;
 | 
			
		||||
    private target!: HTMLElement;
 | 
			
		||||
    /** 是否自动跟随样板的core.domStyle.scale进行缩放 */
 | 
			
		||||
    autoScale: boolean = false;
 | 
			
		||||
    /** 是否是高清画布 */
 | 
			
		||||
    highResolution: boolean = true;
 | 
			
		||||
 | 
			
		||||
    constructor(id: string = '', setTarget: boolean = true) {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.id = id;
 | 
			
		||||
        if (setTarget) this.target = core.dom.gameDraw;
 | 
			
		||||
        this.canvas = document.createElement('canvas');
 | 
			
		||||
        this.canvas.id = id;
 | 
			
		||||
        this.ctx = this.canvas.getContext('2d')!;
 | 
			
		||||
        this.width = this.canvas.width / devicePixelRatio;
 | 
			
		||||
        this.height = this.canvas.height / devicePixelRatio;
 | 
			
		||||
 | 
			
		||||
        this.canvas.style.position = 'absolute';
 | 
			
		||||
 | 
			
		||||
        MotaCanvas2D.map.set(this.id, this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 修改画布的挂载目标,如果已经被挂载,那么会被重新挂载至新的目标元素
 | 
			
		||||
     * @param target 画布将被挂载的目标
 | 
			
		||||
     */
 | 
			
		||||
    setTarget(target: HTMLElement) {
 | 
			
		||||
        this.target = target;
 | 
			
		||||
        if (this.mounted) {
 | 
			
		||||
            this.unmount();
 | 
			
		||||
            this.mount();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置画布的大小
 | 
			
		||||
     */
 | 
			
		||||
    size(width: number, height: number) {
 | 
			
		||||
        let ratio = this.highResolution ? devicePixelRatio : 1;
 | 
			
		||||
        if (this.autoScale) {
 | 
			
		||||
            const scale = core.domStyle.scale;
 | 
			
		||||
            if (this.highResolution) ratio *= scale;
 | 
			
		||||
            this.canvas.style.width = `${width * scale}px`;
 | 
			
		||||
            this.canvas.style.height = `${height * scale}px`;
 | 
			
		||||
        } else {
 | 
			
		||||
            this.canvas.style.width = `${width}px`;
 | 
			
		||||
            this.canvas.style.height = `${height}px`;
 | 
			
		||||
        }
 | 
			
		||||
        this.canvas.width = width * ratio;
 | 
			
		||||
        this.canvas.height = height * ratio;
 | 
			
		||||
        this.width = width;
 | 
			
		||||
        this.height = height;
 | 
			
		||||
        this.ctx.setTransform(1, 0, 0, 1, 0, 0);
 | 
			
		||||
        this.ctx.scale(ratio, ratio);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置画布的位置
 | 
			
		||||
     */
 | 
			
		||||
    pos(x: number, y: number) {
 | 
			
		||||
        this.canvas.style.left = `${x}px`;
 | 
			
		||||
        this.canvas.style.top = `${y}px`;
 | 
			
		||||
        this.x = x;
 | 
			
		||||
        this.y = y;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 设置画布的css
 | 
			
		||||
     * @param css 要设置成的css
 | 
			
		||||
     */
 | 
			
		||||
    css(css: string | CSSObj) {
 | 
			
		||||
        const s = typeof css === 'string' ? parseCss(css) : css;
 | 
			
		||||
        for (const [key, value] of Object.entries(s)) {
 | 
			
		||||
            this.canvas.style[key as CanParseCss] = value;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除这个画布
 | 
			
		||||
     */
 | 
			
		||||
    delete() {
 | 
			
		||||
        super.delete();
 | 
			
		||||
        this.unmount();
 | 
			
		||||
        MotaCanvas2D.map.delete(this.id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 将这个画布添加至游戏画布
 | 
			
		||||
     */
 | 
			
		||||
    mount() {
 | 
			
		||||
        if (!this.mounted) {
 | 
			
		||||
            this.mounted = true;
 | 
			
		||||
            this.target.appendChild(this.canvas);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 将这个画布从页面上移除
 | 
			
		||||
     */
 | 
			
		||||
    unmount() {
 | 
			
		||||
        if (this.mounted) {
 | 
			
		||||
            this.mounted = false;
 | 
			
		||||
            this.canvas.remove();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 类似于 Symbol.for
 | 
			
		||||
     */
 | 
			
		||||
    static for(id: string, setTarget?: boolean) {
 | 
			
		||||
        const canvas = this.map.get(id);
 | 
			
		||||
        return canvas ?? new MotaCanvas2D(id, setTarget);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
window.addEventListener('resize', () => {
 | 
			
		||||
    requestAnimationFrame(() => {
 | 
			
		||||
        MotaOffscreenCanvas2D.list.forEach(v => {
 | 
			
		||||
            if (v.autoScale) {
 | 
			
		||||
                v.size(v.width, v.height);
 | 
			
		||||
                v.emit('resize');
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										241
									
								
								src/core/fx/portal.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								src/core/fx/portal.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,241 @@
 | 
			
		||||
import { Ticker } from 'mutate-animate';
 | 
			
		||||
import { MotaCanvas2D } from '@/core/fx/canvas2d';
 | 
			
		||||
import { MotaSettingItem, mainSetting } from '@/core/main/setting';
 | 
			
		||||
 | 
			
		||||
// 苍蓝殿左上角区域的传送门机制的绘制部分,传送部分看 src/game/machanism/misc.ts
 | 
			
		||||
 | 
			
		||||
interface DrawingPortal {
 | 
			
		||||
    color: string;
 | 
			
		||||
    x: number;
 | 
			
		||||
    y: number;
 | 
			
		||||
    particles: PortalParticle[];
 | 
			
		||||
    /** v表示竖向,h表示横向 */
 | 
			
		||||
    type: 'v' | 'h';
 | 
			
		||||
    /** 上一次新增粒子的时间 */
 | 
			
		||||
    lastParticle: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface PortalParticle {
 | 
			
		||||
    fx: number;
 | 
			
		||||
    fy: number;
 | 
			
		||||
    totalTime: number;
 | 
			
		||||
    time: number;
 | 
			
		||||
    tx: number;
 | 
			
		||||
    ty: number;
 | 
			
		||||
    r: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MAX_PARTICLES = 10;
 | 
			
		||||
const PARTICLE_LAST = 2000;
 | 
			
		||||
const PARTICLE_INTERVAL = PARTICLE_LAST / MAX_PARTICLES;
 | 
			
		||||
 | 
			
		||||
const color: string[] = ['#0f0', '#ff0', '#0ff', '#fff', '#f0f'];
 | 
			
		||||
 | 
			
		||||
const drawing: DrawingPortal[] = [];
 | 
			
		||||
const ticker = new Ticker();
 | 
			
		||||
 | 
			
		||||
let canvas: MotaCanvas2D;
 | 
			
		||||
let ctx: CanvasRenderingContext2D;
 | 
			
		||||
let particleSetting: MotaSettingItem;
 | 
			
		||||
 | 
			
		||||
let lastTime = 0;
 | 
			
		||||
Mota.require('var', 'loading').once('coreInit', () => {
 | 
			
		||||
    canvas = MotaCanvas2D.for('@portal');
 | 
			
		||||
    ctx = canvas.ctx;
 | 
			
		||||
    canvas.mount();
 | 
			
		||||
    canvas.css(`z-index: 51`);
 | 
			
		||||
    canvas.withGameScale(true);
 | 
			
		||||
    canvas.pos(0, 0);
 | 
			
		||||
    canvas.size(480, 480);
 | 
			
		||||
    canvas.on('resize', () => {
 | 
			
		||||
        canvas.css(`z-index: 51`);
 | 
			
		||||
    });
 | 
			
		||||
    particleSetting = mainSetting.getSetting('fx.portalParticle')!;
 | 
			
		||||
    ticker.add(tickPortal);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Mota.require('var', 'hook').on('changingFloor', id => {
 | 
			
		||||
    drawPortals(id);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
let needDraw = false;
 | 
			
		||||
function tickPortal(time: number) {
 | 
			
		||||
    const last = lastTime;
 | 
			
		||||
    lastTime = time;
 | 
			
		||||
    const p = particleSetting.value;
 | 
			
		||||
 | 
			
		||||
    if (!core.isPlaying() || drawing.length === 0) return;
 | 
			
		||||
    if (!p && !needDraw) return;
 | 
			
		||||
 | 
			
		||||
    needDraw = false;
 | 
			
		||||
 | 
			
		||||
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
 | 
			
		||||
    ctx.lineCap = 'round';
 | 
			
		||||
    ctx.lineWidth = 3;
 | 
			
		||||
    ctx.shadowOffsetX = 0;
 | 
			
		||||
    ctx.shadowOffsetY = 0;
 | 
			
		||||
    if (p) {
 | 
			
		||||
        ctx.shadowBlur = 8;
 | 
			
		||||
    } else {
 | 
			
		||||
        ctx.shadowBlur = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    drawing.forEach(v => {
 | 
			
		||||
        const { color, x, y, type, lastParticle, particles } = v;
 | 
			
		||||
 | 
			
		||||
        ctx.strokeStyle = color;
 | 
			
		||||
        ctx.fillStyle = color;
 | 
			
		||||
        ctx.globalAlpha = 1;
 | 
			
		||||
        ctx.shadowColor = color;
 | 
			
		||||
        if (type === 'v') {
 | 
			
		||||
            ctx.beginPath();
 | 
			
		||||
            ctx.moveTo(x, y - 14);
 | 
			
		||||
            ctx.lineTo(x, y + 30);
 | 
			
		||||
            ctx.stroke();
 | 
			
		||||
        } else {
 | 
			
		||||
            ctx.beginPath();
 | 
			
		||||
            ctx.moveTo(x + 2, y);
 | 
			
		||||
            ctx.lineTo(x + 30, y);
 | 
			
		||||
            ctx.stroke();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (p) {
 | 
			
		||||
            // 绘制粒子效果
 | 
			
		||||
            let needDelete = false;
 | 
			
		||||
            const dt = time - last;
 | 
			
		||||
 | 
			
		||||
            particles.forEach(v => {
 | 
			
		||||
                const { fx, fy, tx, ty, time: t, totalTime, r } = v;
 | 
			
		||||
                const progress = t / totalTime;
 | 
			
		||||
                const nx = (tx - fx) * progress + fx;
 | 
			
		||||
                const ny = (ty - fy) * progress + fy;
 | 
			
		||||
                v.time += dt;
 | 
			
		||||
 | 
			
		||||
                if (progress > 1) {
 | 
			
		||||
                    needDelete = true;
 | 
			
		||||
                    return;
 | 
			
		||||
                } else if (progress > 0.75) {
 | 
			
		||||
                    ctx.globalAlpha = (1 - progress) * 4;
 | 
			
		||||
                } else if (progress < 0.25) {
 | 
			
		||||
                    ctx.globalAlpha = progress * 4;
 | 
			
		||||
                } else {
 | 
			
		||||
                    ctx.globalAlpha = 1;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ctx.beginPath();
 | 
			
		||||
                ctx.arc(nx, ny, r, 0, Math.PI * 2);
 | 
			
		||||
                ctx.closePath();
 | 
			
		||||
                ctx.fill();
 | 
			
		||||
            });
 | 
			
		||||
            if (needDelete) {
 | 
			
		||||
                particles.shift();
 | 
			
		||||
            }
 | 
			
		||||
            if (
 | 
			
		||||
                time - lastParticle >= PARTICLE_INTERVAL &&
 | 
			
		||||
                particles.length < MAX_PARTICLES
 | 
			
		||||
            ) {
 | 
			
		||||
                // 添加新粒子
 | 
			
		||||
                const direction = Math.random();
 | 
			
		||||
                const k = Math.random() / 2 - 0.3;
 | 
			
		||||
                const verticle = Math.floor(Math.random() * 8 + 8);
 | 
			
		||||
                const r = Math.random() * 2;
 | 
			
		||||
                v.lastParticle = time;
 | 
			
		||||
                if (direction > 0.5) {
 | 
			
		||||
                    // 左边 | 上边
 | 
			
		||||
                    if (type === 'h') {
 | 
			
		||||
                        const fx = Math.floor(Math.random() * 24 + x + 4);
 | 
			
		||||
                        particles.push({
 | 
			
		||||
                            fx: fx,
 | 
			
		||||
                            fy: y - 1,
 | 
			
		||||
                            tx: verticle * k + fx + 4,
 | 
			
		||||
                            ty: -verticle + y - 1,
 | 
			
		||||
                            r: r,
 | 
			
		||||
                            time: 0,
 | 
			
		||||
                            totalTime: PARTICLE_LAST
 | 
			
		||||
                        });
 | 
			
		||||
                    } else {
 | 
			
		||||
                        const fy = Math.floor(Math.random() * 44 + y - 14);
 | 
			
		||||
                        particles.push({
 | 
			
		||||
                            fy: fy,
 | 
			
		||||
                            fx: x - 1,
 | 
			
		||||
                            ty: verticle * k + fy + 4,
 | 
			
		||||
                            tx: -verticle + x - 1,
 | 
			
		||||
                            r: r,
 | 
			
		||||
                            time: 0,
 | 
			
		||||
                            totalTime: PARTICLE_LAST
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    // 右边 | 下边
 | 
			
		||||
                    if (type === 'h') {
 | 
			
		||||
                        const fx = Math.floor(Math.random() * 24 + x + 4);
 | 
			
		||||
                        particles.push({
 | 
			
		||||
                            fx: fx,
 | 
			
		||||
                            fy: y + 1,
 | 
			
		||||
                            tx: verticle * k + fx + 4,
 | 
			
		||||
                            ty: verticle + y - 1,
 | 
			
		||||
                            r: r,
 | 
			
		||||
                            time: 0,
 | 
			
		||||
                            totalTime: PARTICLE_LAST
 | 
			
		||||
                        });
 | 
			
		||||
                    } else {
 | 
			
		||||
                        const fy = Math.floor(Math.random() * 44 + y - 14);
 | 
			
		||||
                        particles.push({
 | 
			
		||||
                            fy: fy,
 | 
			
		||||
                            fx: x + 1,
 | 
			
		||||
                            ty: verticle * k + fy + 4,
 | 
			
		||||
                            tx: verticle + x + 1,
 | 
			
		||||
                            r: r,
 | 
			
		||||
                            time: 0,
 | 
			
		||||
                            totalTime: PARTICLE_LAST
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 绘制传送门
 | 
			
		||||
 * @param floorId 要绘制传送门的楼层
 | 
			
		||||
 */
 | 
			
		||||
export function drawPortals(floorId: FloorIds) {
 | 
			
		||||
    drawing.splice(0);
 | 
			
		||||
    const p = Mota.require('module', 'Mechanism').BluePalace.portals[floorId];
 | 
			
		||||
    if (!p) return;
 | 
			
		||||
    p.forEach((v, i) => {
 | 
			
		||||
        const c = color[i % color.length];
 | 
			
		||||
        const { fx, fy, tx, ty, dir, toDir } = v;
 | 
			
		||||
 | 
			
		||||
        let x1 = fx * 32;
 | 
			
		||||
        let y1 = fy * 32;
 | 
			
		||||
        let x2 = tx * 32;
 | 
			
		||||
        let y2 = ty * 32;
 | 
			
		||||
 | 
			
		||||
        if (dir === 'down') y1 += 32;
 | 
			
		||||
        else if (dir === 'right') x1 += 32;
 | 
			
		||||
 | 
			
		||||
        if (toDir === 'down') y2 += 32;
 | 
			
		||||
        else if (toDir === 'right') x2 += 32;
 | 
			
		||||
 | 
			
		||||
        drawing.push({
 | 
			
		||||
            x: x1,
 | 
			
		||||
            y: y1,
 | 
			
		||||
            type: dir === 'left' || dir === 'right' ? 'v' : 'h',
 | 
			
		||||
            color: c,
 | 
			
		||||
            particles: [],
 | 
			
		||||
            lastParticle: lastTime
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        drawing.push({
 | 
			
		||||
            x: x2,
 | 
			
		||||
            y: y2,
 | 
			
		||||
            type: toDir === 'left' || toDir === 'right' ? 'v' : 'h',
 | 
			
		||||
            color: c,
 | 
			
		||||
            particles: [],
 | 
			
		||||
            lastParticle: lastTime
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    needDraw = true;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user