fix: 修复CodeQL检测到的代码问题
This commit is contained in:
@@ -223,6 +223,7 @@ function copyEngineModulesPlugin(): Plugin {
|
|||||||
for (const pattern of includes) {
|
for (const pattern of includes) {
|
||||||
// Convert glob pattern to regex
|
// Convert glob pattern to regex
|
||||||
const regexPattern = pattern
|
const regexPattern = pattern
|
||||||
|
.replace(/\\/g, '\\\\')
|
||||||
.replace(/\./g, '\\.')
|
.replace(/\./g, '\\.')
|
||||||
.replace(/\*/g, '.*')
|
.replace(/\*/g, '.*')
|
||||||
.replace(/\?/g, '.');
|
.replace(/\?/g, '.');
|
||||||
|
|||||||
@@ -711,6 +711,7 @@ export class WebBuildPipeline implements IBuildPipeline {
|
|||||||
|
|
||||||
for (const pattern of includes) {
|
for (const pattern of includes) {
|
||||||
const regexPattern = pattern
|
const regexPattern = pattern
|
||||||
|
.replace(/\\/g, '\\\\')
|
||||||
.replace(/\./g, '\\.')
|
.replace(/\./g, '\\.')
|
||||||
.replace(/\*/g, '.*')
|
.replace(/\*/g, '.*')
|
||||||
.replace(/\?/g, '.');
|
.replace(/\?/g, '.');
|
||||||
@@ -1115,16 +1116,6 @@ export class WebBuildPipeline implements IBuildPipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const esEngineDir = `${context.outputDir}/libs/es-engine`;
|
|
||||||
const hasWasm = await fs.pathExists(esEngineDir);
|
|
||||||
let wasmFileName = 'es_engine_bg.wasm';
|
|
||||||
if (hasWasm) {
|
|
||||||
const wasmFiles = await fs.listFilesByExtension(esEngineDir, ['.wasm']);
|
|
||||||
if (wasmFiles.length > 0) {
|
|
||||||
wasmFileName = wasmFiles[0].split(/[/\\]/).pop() || wasmFileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const useBundledModules = webConfig.bundleModules !== false;
|
const useBundledModules = webConfig.bundleModules !== false;
|
||||||
let importMapScript = '';
|
let importMapScript = '';
|
||||||
let pluginImportCode = '';
|
let pluginImportCode = '';
|
||||||
|
|||||||
@@ -91,8 +91,9 @@ export class KinematicCharacterController {
|
|||||||
*/
|
*/
|
||||||
public setUp(vector: Vector) {
|
public setUp(vector: Vector) {
|
||||||
let rawVect = VectorOps.intoRaw(vector);
|
let rawVect = VectorOps.intoRaw(vector);
|
||||||
return this.raw.setUp(rawVect);
|
const result = this.raw.setUp(rawVect);
|
||||||
rawVect.free();
|
rawVect.free();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public applyImpulsesToDynamicBodies(): boolean {
|
public applyImpulsesToDynamicBodies(): boolean {
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ export class DynamicRayCastVehicleController {
|
|||||||
bodies: RigidBodySet,
|
bodies: RigidBodySet,
|
||||||
colliders: ColliderSet,
|
colliders: ColliderSet,
|
||||||
) {
|
) {
|
||||||
|
if (typeof RawDynamicRayCastVehicleController === 'undefined') {
|
||||||
|
throw new Error('DynamicRayCastVehicleController is not available in 2D mode');
|
||||||
|
}
|
||||||
this.raw = new RawDynamicRayCastVehicleController(chassis.handle);
|
this.raw = new RawDynamicRayCastVehicleController(chassis.handle);
|
||||||
this.broadPhase = broadPhase;
|
this.broadPhase = broadPhase;
|
||||||
this.narrowPhase = narrowPhase;
|
this.narrowPhase = narrowPhase;
|
||||||
|
|||||||
@@ -186,9 +186,9 @@ export class ShaderAnalyzer {
|
|||||||
* 从源代码中移除注释。
|
* 从源代码中移除注释。
|
||||||
*/
|
*/
|
||||||
private removeComments(source: string): string {
|
private removeComments(source: string): string {
|
||||||
// Remove single-line comments.
|
// Remove single-line comments (non-greedy, stop at newline).
|
||||||
// 移除单行注释。
|
// 移除单行注释(非贪婪,遇到换行停止)。
|
||||||
let result = source.replace(/\/\/.*$/gm, '');
|
let result = source.replace(/\/\/[^\n\r]*/g, '');
|
||||||
// Remove multi-line comments.
|
// Remove multi-line comments.
|
||||||
// 移除多行注释。
|
// 移除多行注释。
|
||||||
result = result.replace(/\/\*[\s\S]*?\*\//g, '');
|
result = result.replace(/\/\*[\s\S]*?\*\//g, '');
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function ShaderEditorPanel({ filePath: propFilePath }: ShaderEditorPanelP
|
|||||||
|
|
||||||
const [activeTab, setActiveTab] = useState<'vertex' | 'fragment'>('fragment');
|
const [activeTab, setActiveTab] = useState<'vertex' | 'fragment'>('fragment');
|
||||||
const [showAnalysis, setShowAnalysis] = useState(true);
|
const [showAnalysis, setShowAnalysis] = useState(true);
|
||||||
const [showPreview, setShowPreview] = useState(true);
|
const [_showPreview, _setShowPreview] = useState(true);
|
||||||
const [vertexAnalysis, setVertexAnalysis] = useState<ShaderAnalysis | null>(null);
|
const [vertexAnalysis, setVertexAnalysis] = useState<ShaderAnalysis | null>(null);
|
||||||
const [fragmentAnalysis, setFragmentAnalysis] = useState<ShaderAnalysis | null>(null);
|
const [fragmentAnalysis, setFragmentAnalysis] = useState<ShaderAnalysis | null>(null);
|
||||||
const [compileError, setCompileError] = useState<string | null>(null);
|
const [compileError, setCompileError] = useState<string | null>(null);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
import React, { useState, useEffect, useMemo, useCallback } from 'react';
|
import React, { useState, useEffect, useMemo, useCallback } from 'react';
|
||||||
import { Component, Core, getComponentInstanceTypeName } from '@esengine/ecs-framework';
|
import { Component, Core, getComponentInstanceTypeName } from '@esengine/ecs-framework';
|
||||||
import { IComponentInspector, ComponentInspectorContext, MessageHub, IFileSystemService, IFileSystem, ProjectService } from '@esengine/editor-core';
|
import { IComponentInspector, ComponentInspectorContext, MessageHub, IFileSystemService, IFileSystem, ProjectService } from '@esengine/editor-core';
|
||||||
import { SpriteComponent, MaterialOverrides, MaterialPropertyOverride } from '@esengine/sprite';
|
import { SpriteComponent, MaterialPropertyOverride } from '@esengine/sprite';
|
||||||
import { getMaterialManager, Material, BlendMode, BuiltInShaders, UniformType } from '@esengine/material-system';
|
import { getMaterialManager, Material, BlendMode, BuiltInShaders, UniformType } from '@esengine/material-system';
|
||||||
import { ChevronDown, ChevronRight, X, Plus, Save, ExternalLink, RefreshCw } from 'lucide-react';
|
import { ChevronDown, ChevronRight, X, Plus, Save, ExternalLink, RefreshCw } from 'lucide-react';
|
||||||
import './SpriteComponentInspector.css';
|
import './SpriteComponentInspector.css';
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export const TilemapViewport: React.FC<TilemapViewportProps> = ({
|
|||||||
panX,
|
panX,
|
||||||
panY,
|
panY,
|
||||||
showGrid,
|
showGrid,
|
||||||
showCollision,
|
showCollision: _showCollision,
|
||||||
selectedTiles,
|
selectedTiles,
|
||||||
brushSize,
|
brushSize,
|
||||||
currentLayer,
|
currentLayer,
|
||||||
@@ -63,12 +63,12 @@ export const TilemapViewport: React.FC<TilemapViewportProps> = ({
|
|||||||
|
|
||||||
const [isPanning, setIsPanning] = useState(false);
|
const [isPanning, setIsPanning] = useState(false);
|
||||||
const [lastPanPos, setLastPanPos] = useState({ x: 0, y: 0 });
|
const [lastPanPos, setLastPanPos] = useState({ x: 0, y: 0 });
|
||||||
const [mousePos, setMousePos] = useState<{ tileX: number; tileY: number } | null>(null);
|
const [_mousePos, setMousePos] = useState<{ tileX: number; tileY: number } | null>(null);
|
||||||
const [spacePressed, setSpacePressed] = useState(false);
|
const [spacePressed, setSpacePressed] = useState(false);
|
||||||
|
|
||||||
// Get canvas size
|
// Get canvas size (reserved for future virtual scrolling)
|
||||||
const canvasWidth = tilemap.width * tileWidth;
|
const _canvasWidth = tilemap.width * tileWidth;
|
||||||
const canvasHeight = tilemap.height * tileHeight;
|
const _canvasHeight = tilemap.height * tileHeight;
|
||||||
|
|
||||||
// Initialize viewport service
|
// Initialize viewport service
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ export const TilesetPreview: React.FC<TilesetPreviewProps> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseContextMenu = () => {
|
const _handleCloseContextMenu = () => {
|
||||||
setContextMenu(null);
|
setContextMenu(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export const TileSetSelectorPanel: React.FC<TileSetSelectorPanelProps> = ({
|
|||||||
} = useTilemapEditorStore();
|
} = useTilemapEditorStore();
|
||||||
|
|
||||||
const [showTilesetDropdown, setShowTilesetDropdown] = useState(false);
|
const [showTilesetDropdown, setShowTilesetDropdown] = useState(false);
|
||||||
const [previewZoom, setPreviewZoom] = useState(1);
|
const [_previewZoom, _setPreviewZoom] = useState(1);
|
||||||
const [editingAnimationTileId, setEditingAnimationTileId] = useState<number | null>(null);
|
const [editingAnimationTileId, setEditingAnimationTileId] = useState<number | null>(null);
|
||||||
|
|
||||||
// Get animated tile IDs from tileset
|
// Get animated tile IDs from tileset
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* Tilemap 详情面板 - 右侧分组属性面板
|
* Tilemap 详情面板 - 右侧分组属性面板
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useCallback, useRef, useEffect } from 'react';
|
import React, { useState, useCallback, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
@@ -412,7 +412,7 @@ export const TilemapDetailsPanel: React.FC<TilemapDetailsPanelProps> = ({
|
|||||||
// Colors for grid (editor settings, not layer properties)
|
// Colors for grid (editor settings, not layer properties)
|
||||||
const [tileGridColor, setTileGridColor] = useState('#333333');
|
const [tileGridColor, setTileGridColor] = useState('#333333');
|
||||||
const [multiTileGridColor, setMultiTileGridColor] = useState('#ff0000');
|
const [multiTileGridColor, setMultiTileGridColor] = useState('#ff0000');
|
||||||
const [layerGridColor, setLayerGridColor] = useState('#00ff00');
|
const [_layerGridColor, _setLayerGridColor] = useState('#00ff00');
|
||||||
|
|
||||||
const handleLayerSelect = useCallback((index: number) => {
|
const handleLayerSelect = useCallback((index: number) => {
|
||||||
setCurrentLayer(index);
|
setCurrentLayer(index);
|
||||||
|
|||||||
@@ -18,13 +18,12 @@ import {
|
|||||||
FolderOpen,
|
FolderOpen,
|
||||||
File,
|
File,
|
||||||
Image as ImageIcon,
|
Image as ImageIcon,
|
||||||
ChevronDown,
|
|
||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
Box,
|
Box,
|
||||||
Map
|
Map
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Core, Entity } from '@esengine/ecs-framework';
|
import { Core } from '@esengine/ecs-framework';
|
||||||
import { MessageHub, ProjectService, IFileSystemService, type IFileSystem, IDialogService, type IDialog } from '@esengine/editor-core';
|
import { MessageHub, ProjectService, IFileSystemService, type IFileSystem, type IDialog } from '@esengine/editor-core';
|
||||||
import { TilemapComponent, type ITilesetData, type ResizeAnchor } from '@esengine/tilemap';
|
import { TilemapComponent, type ITilesetData, type ResizeAnchor } from '@esengine/tilemap';
|
||||||
import { useTilemapEditorStore, type TilemapToolType, type LayerState } from '../../stores/TilemapEditorStore';
|
import { useTilemapEditorStore, type TilemapToolType, type LayerState } from '../../stores/TilemapEditorStore';
|
||||||
import { TilemapCanvas } from '../TilemapCanvas';
|
import { TilemapCanvas } from '../TilemapCanvas';
|
||||||
@@ -567,7 +566,7 @@ const PanelDivider: React.FC<PanelDividerProps> = ({ onDrag, direction }) => {
|
|||||||
|
|
||||||
export const TilemapEditorPanel: React.FC<TilemapEditorPanelProps> = ({ messageHub: propMessageHub }) => {
|
export const TilemapEditorPanel: React.FC<TilemapEditorPanelProps> = ({ messageHub: propMessageHub }) => {
|
||||||
const [tilemap, setTilemap] = useState<TilemapComponent | null>(null);
|
const [tilemap, setTilemap] = useState<TilemapComponent | null>(null);
|
||||||
const [entity, setEntity] = useState<Entity | null>(null);
|
const [_entity, setEntity] = useState<unknown>(null);
|
||||||
|
|
||||||
// Panel widths for resizable layout - smaller defaults to give viewport more space
|
// Panel widths for resizable layout - smaller defaults to give viewport more space
|
||||||
const [leftPanelWidth, setLeftPanelWidth] = useState(180);
|
const [leftPanelWidth, setLeftPanelWidth] = useState(180);
|
||||||
@@ -595,12 +594,12 @@ export const TilemapEditorPanel: React.FC<TilemapEditorPanelProps> = ({ messageH
|
|||||||
entityId,
|
entityId,
|
||||||
pendingFilePath,
|
pendingFilePath,
|
||||||
currentFilePath,
|
currentFilePath,
|
||||||
currentTool,
|
currentTool: _currentTool,
|
||||||
zoom,
|
zoom,
|
||||||
showGrid,
|
showGrid,
|
||||||
showCollision,
|
showCollision: _showCollision,
|
||||||
editingCollision,
|
editingCollision: _editingCollision,
|
||||||
tileWidth,
|
tileWidth: _tileWidth,
|
||||||
tileHeight,
|
tileHeight,
|
||||||
tilesetImageUrl,
|
tilesetImageUrl,
|
||||||
tilesetColumns,
|
tilesetColumns,
|
||||||
@@ -608,11 +607,11 @@ export const TilemapEditorPanel: React.FC<TilemapEditorPanelProps> = ({ messageH
|
|||||||
setEntityId,
|
setEntityId,
|
||||||
setPendingFilePath,
|
setPendingFilePath,
|
||||||
setCurrentFilePath,
|
setCurrentFilePath,
|
||||||
setCurrentTool,
|
setCurrentTool: _setCurrentTool,
|
||||||
setZoom,
|
setZoom,
|
||||||
setShowGrid,
|
setShowGrid,
|
||||||
setShowCollision,
|
setShowCollision,
|
||||||
setEditingCollision,
|
setEditingCollision: _setEditingCollision,
|
||||||
setPan,
|
setPan,
|
||||||
setTileset,
|
setTileset,
|
||||||
setLayers,
|
setLayers,
|
||||||
@@ -989,8 +988,8 @@ export const TilemapEditorPanel: React.FC<TilemapEditorPanelProps> = ({ messageH
|
|||||||
setPan(0, 0);
|
setPan(0, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 退出全屏模式
|
// 退出全屏模式 (reserved for future use)
|
||||||
const handleExitFullscreen = useCallback(() => {
|
const _handleExitFullscreen = useCallback(() => {
|
||||||
messageHub?.publish('editor:fullscreen', { fullscreen: false });
|
messageHub?.publish('editor:fullscreen', { fullscreen: false });
|
||||||
}, [messageHub]);
|
}, [messageHub]);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
* Tilemap Editor Module Entry
|
* Tilemap Editor Module Entry
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import type { ServiceContainer, Entity } from '@esengine/ecs-framework';
|
import type { ServiceContainer, Entity } from '@esengine/ecs-framework';
|
||||||
import { Core } from '@esengine/ecs-framework';
|
import { Core } from '@esengine/ecs-framework';
|
||||||
import type {
|
import type {
|
||||||
@@ -24,7 +23,6 @@ import {
|
|||||||
ComponentRegistry,
|
ComponentRegistry,
|
||||||
IDialogService,
|
IDialogService,
|
||||||
IFileSystemService,
|
IFileSystemService,
|
||||||
UIRegistry,
|
|
||||||
FileActionRegistry
|
FileActionRegistry
|
||||||
} from '@esengine/editor-core';
|
} from '@esengine/editor-core';
|
||||||
import type { IDialog, IFileSystem } from '@esengine/editor-core';
|
import type { IDialog, IFileSystem } from '@esengine/editor-core';
|
||||||
|
|||||||
@@ -1025,8 +1025,8 @@ export class TilemapComponent extends Component implements IResourceComponent {
|
|||||||
|
|
||||||
// Parse anchor to get X and Y alignment
|
// Parse anchor to get X and Y alignment
|
||||||
// 解析锚点获取X和Y方向的对齐方式
|
// 解析锚点获取X和Y方向的对齐方式
|
||||||
let xAnchor: 'start' | 'center' | 'end' = 'start';
|
let xAnchor: 'start' | 'center' | 'end';
|
||||||
let yAnchor: 'start' | 'center' | 'end' = 'end'; // 'end' means bottom in Y-up system
|
let yAnchor: 'start' | 'center' | 'end';
|
||||||
|
|
||||||
if (anchor.includes('left')) xAnchor = 'start';
|
if (anchor.includes('left')) xAnchor = 'start';
|
||||||
else if (anchor.includes('right')) xAnchor = 'end';
|
else if (anchor.includes('right')) xAnchor = 'end';
|
||||||
|
|||||||
@@ -263,20 +263,8 @@ export class UICanvasScalerSystem extends EntitySystem {
|
|||||||
const safeArea = entity.getComponent(UISafeAreaComponent);
|
const safeArea = entity.getComponent(UISafeAreaComponent);
|
||||||
if (safeArea) {
|
if (safeArea) {
|
||||||
safeArea.update();
|
safeArea.update();
|
||||||
|
// 安全区域已更新,UI 元素通过锚点适配
|
||||||
// 将安全区域转换为设计单位
|
// Safe area updated, UI elements adapt via anchors
|
||||||
// Convert safe area to design units
|
|
||||||
const scaledInsets = {
|
|
||||||
top: safeArea.appliedInsets.top / finalScale,
|
|
||||||
right: safeArea.appliedInsets.right / finalScale,
|
|
||||||
bottom: safeArea.appliedInsets.bottom / finalScale,
|
|
||||||
left: safeArea.appliedInsets.left / finalScale
|
|
||||||
};
|
|
||||||
|
|
||||||
// 调整画布有效尺寸(可选,取决于使用方式)
|
|
||||||
// 这里不直接修改画布尺寸,而是让 UI 元素通过锚点适配
|
|
||||||
// Adjust effective canvas size (optional, depends on usage)
|
|
||||||
// Here we don't modify canvas size directly, let UI elements adapt via anchors
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,18 +40,26 @@ function updateModuleSizes() {
|
|||||||
const stat = fs.statSync(distIndexPath);
|
const stat = fs.statSync(distIndexPath);
|
||||||
const actualSize = stat.size;
|
const actualSize = stat.size;
|
||||||
|
|
||||||
// Read module.json
|
// Read module.json - use file descriptor to avoid race condition
|
||||||
const moduleJson = JSON.parse(fs.readFileSync(moduleJsonPath, 'utf-8'));
|
const fd = fs.openSync(moduleJsonPath, 'r+');
|
||||||
const oldSize = moduleJson.estimatedSize;
|
try {
|
||||||
|
const content = fs.readFileSync(fd, 'utf-8');
|
||||||
|
const moduleJson = JSON.parse(content);
|
||||||
|
const oldSize = moduleJson.estimatedSize;
|
||||||
|
|
||||||
// Update if different
|
// Update if different
|
||||||
if (oldSize !== actualSize) {
|
if (oldSize !== actualSize) {
|
||||||
moduleJson.estimatedSize = actualSize;
|
moduleJson.estimatedSize = actualSize;
|
||||||
fs.writeFileSync(moduleJsonPath, JSON.stringify(moduleJson, null, 2) + '\n');
|
const newContent = JSON.stringify(moduleJson, null, 2) + '\n';
|
||||||
const oldKB = oldSize ? (oldSize / 1024).toFixed(1) : 'N/A';
|
fs.ftruncateSync(fd, 0);
|
||||||
const newKB = (actualSize / 1024).toFixed(1);
|
fs.writeSync(fd, newContent, 0, 'utf-8');
|
||||||
console.log(` ${pkg}: ${oldKB} KB -> ${newKB} KB`);
|
const oldKB = oldSize ? (oldSize / 1024).toFixed(1) : 'N/A';
|
||||||
updated++;
|
const newKB = (actualSize / 1024).toFixed(1);
|
||||||
|
console.log(` ${pkg}: ${oldKB} KB -> ${newKB} KB`);
|
||||||
|
updated++;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
fs.closeSync(fd);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(` Error processing ${pkg}:`, err.message);
|
console.error(` Error processing ${pkg}:`, err.message);
|
||||||
|
|||||||
@@ -91,8 +91,9 @@ export class KinematicCharacterController {
|
|||||||
*/
|
*/
|
||||||
public setUp(vector: Vector) {
|
public setUp(vector: Vector) {
|
||||||
let rawVect = VectorOps.intoRaw(vector);
|
let rawVect = VectorOps.intoRaw(vector);
|
||||||
return this.raw.setUp(rawVect);
|
const result = this.raw.setUp(rawVect);
|
||||||
rawVect.free();
|
rawVect.free();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public applyImpulsesToDynamicBodies(): boolean {
|
public applyImpulsesToDynamicBodies(): boolean {
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ export class DynamicRayCastVehicleController {
|
|||||||
bodies: RigidBodySet,
|
bodies: RigidBodySet,
|
||||||
colliders: ColliderSet,
|
colliders: ColliderSet,
|
||||||
) {
|
) {
|
||||||
|
if (typeof RawDynamicRayCastVehicleController === 'undefined') {
|
||||||
|
throw new Error('DynamicRayCastVehicleController is not available in 2D mode');
|
||||||
|
}
|
||||||
this.raw = new RawDynamicRayCastVehicleController(chassis.handle);
|
this.raw = new RawDynamicRayCastVehicleController(chassis.handle);
|
||||||
this.broadPhase = broadPhase;
|
this.broadPhase = broadPhase;
|
||||||
this.narrowPhase = narrowPhase;
|
this.narrowPhase = narrowPhase;
|
||||||
|
|||||||
Reference in New Issue
Block a user