跳转至

网页版

1. 环境要求

  • Node.js 18+
  • npm 或 yarn
  • 现代浏览器(支持ES2020+、WebGL 2.0、Web Audio API)
  • 支持File System Access API的浏览器(推荐Chrome/Edge)
  • 网页版地址是 ra2web.com,下面的项目是源码

2. 安装步骤

  1. 克隆项目

    Bash
    git clone https://github.com/huangkaoya/redalert2.git
    cd redalert2
    

  2. 安装依赖

    Bash
    npm install
    

  3. 启动开发服务器

    Bash
    npm run dev 
    

  4. 访问应用 打开浏览器访问 http://localhost:3000

  5. 调试模式:
    • http://localhost:3000?test=glsl - GLSL着色器测试
    • http://localhost:3000?debug=true - 启用调试模式

3. 问题解决

3.1 网页打开报错

使用以下patch,以下内容复制成patch文件,然后patch -p1 < ~/diff.patch

Diff
diff --git a/src/data/vfs/VirtualFileSystem.ts b/src/data/vfs/VirtualFileSystem.ts
index 8215b89..6c8b8fd 100644
--- a/src/data/vfs/VirtualFileSystem.ts
+++ b/src/data/vfs/VirtualFileSystem.ts
@@ -7,7 +7,7 @@ import { pad } from "../../util/string";
 import { FileNotFoundError } from "./FileNotFoundError";
 import { MemArchive } from "./MemArchive";
 import type { VirtualFile } from "./VirtualFile";
-import AppLogger from "../../util/Logger"; // Import the default export
+import AppLogger from "../../util/logger"; // Import the default export
 import type { RealFileSystem } from "./RealFileSystem"; // Assuming RFS interface/type

 // Define a generic interface for archive types for better type safety
diff --git a/src/engine/Engine.ts b/src/engine/Engine.ts
index 0e45e88..e998139 100644
--- a/src/engine/Engine.ts
+++ b/src/engine/Engine.ts
@@ -20,7 +20,7 @@ import * as stringUtils from '../util/string';
 import { MapList } from './MapList';
 import { HvaFile } from '../data/HvaFile';
 import { MixinRulesType } from '../game/ini/MixinRulesType';
-import type { AppLogger as AppLoggerType } from '../util/Logger'; // Changed to lowercase, aliased for clarity
+import type { AppLogger as AppLoggerType } from '../util/logger'; // Changed to lowercase, aliased for clarity
 import type { DataStream } from '../data/DataStream'; // For VFS openFile result stream

 export enum EngineType {
diff --git a/src/engine/gameRes/GameRes.ts b/src/engine/gameRes/GameRes.ts
index 83f8cc4..ecd2582 100644
--- a/src/engine/gameRes/GameRes.ts
+++ b/src/engine/gameRes/GameRes.ts
@@ -5,7 +5,7 @@ import { VirtualFileSystem } from '../../data/vfs/VirtualFileSystem';
 import { Engine, EngineType } from '../Engine';
 import { ResourceLoader, LoaderResult } from '../ResourceLoader';
 import { DownloadError } from '../../network/HttpRequest';
-import { AppLogger } from '../../util/Logger'; // Assuming AppLogger is exported or can be typed
+import { AppLogger } from '../../util/logger'; // Assuming AppLogger is exported or can be typed
 import { GameResConfig } from './GameResConfig';
 import { ChecksumError } from './importError/ChecksumError';
 import { FileNotFoundError as GameResFileNotFoundError } from './importError/FileNotFoundError'; // Alias to avoid clash
diff --git a/src/engine/gfx/batch/MergedSpriteMesh.ts b/src/engine/gfx/batch/MergedSpriteMesh.ts
index 386e432..7137c2c 100644
--- a/src/engine/gfx/batch/MergedSpriteMesh.ts
+++ b/src/engine/gfx/batch/MergedSpriteMesh.ts
@@ -1,5 +1,5 @@
 import * as THREE from 'three';
-import * as arrayUtils from '../../../util/Array';
+import * as arrayUtils from '../../../util/array';
 import { PaletteBasicMaterial } from '../material/PaletteBasicMaterial';

 // 临时向量,用于位置计算
diff --git a/src/engine/renderable/entity/WaypointLines.ts b/src/engine/renderable/entity/WaypointLines.ts
index 27271fb..f3344dc 100644
--- a/src/engine/renderable/entity/WaypointLines.ts
+++ b/src/engine/renderable/entity/WaypointLines.ts
@@ -1,6 +1,6 @@
 import { Coords } from "@/game/Coords";
 import { TargetLinesConfig, configHasTarget } from "@/game/gameobject/task/system/TargetLinesConfig";
-import { equals } from "@/util/Array";
+import { equals } from "@/util/array";
 import { WaypointLine } from "@/engine/renderable/entity/WaypointLine";
 import * as THREE from "three";

diff --git a/src/game/BotManager.ts b/src/game/BotManager.ts
index 18a528c..42c4f7b 100644
--- a/src/game/BotManager.ts
+++ b/src/game/BotManager.ts
@@ -1,5 +1,5 @@
 import { CompositeDisposable } from '../util/disposable/CompositeDisposable';
-import { AppLogger } from '@/util/Logger';
+import { AppLogger } from '@/util/logger';
 import { ActionQueue } from './action/ActionQueue';
 import { ActionsApi } from './api/ActionsApi';
 import { EventsApi } from './api/EventsApi';
diff --git a/src/game/api/LoggerApi.ts b/src/game/api/LoggerApi.ts
index 637ac1b..701001f 100644
--- a/src/game/api/LoggerApi.ts
+++ b/src/game/api/LoggerApi.ts
@@ -1,5 +1,5 @@
 import { formatTimeDuration } from '@/util/format';
-import { AppLogger } from '@/util/Logger';
+import { AppLogger } from '@/util/logger';

 export class LoggerApi {
   private logger: typeof AppLogger;
diff --git a/src/game/gameobject/task/move/MoveTask.ts b/src/game/gameobject/task/move/MoveTask.ts
index f1a470b..ada6eb3 100644
--- a/src/game/gameobject/task/move/MoveTask.ts
+++ b/src/game/gameobject/task/move/MoveTask.ts
@@ -1,7 +1,7 @@
 import { Task } from "@/game/gameobject/task/system/Task";
 import { Infantry } from "@/game/gameobject/Infantry";
 import { MovementZone } from "@/game/type/MovementZone";
-import { findIndexReverse, findReverse } from "@/util/Array";
+import { findIndexReverse, findReverse } from "@/util/array";
 import { SpeedType } from "@/game/type/SpeedType";
 import { MoveState, CollisionState, MoveResult, MoveTrait } from "@/game/gameobject/trait/MoveTrait";
 import { WaitTicksTask } from "@/game/gameobject/task/system/WaitTicksTask";
@@ -9,7 +9,8 @@ import { MoveAsideTask } from "@/game/gameobject/task/move/MoveAsideTask";
 import { MovePositionHelper } from "@/game/gameobject/unit/MovePositionHelper";
 import { RadialTileFinder } from "@/game/map/tileFinder/RadialTileFinder";
 import { RangeHelper } from "@/game/gameobject/unit/RangeHelper";
-import { AppLogger, Logger } from "@/util/Logger";
+import { AppLogger } from "@/util/logger";
+import type { ILogger } from 'js-logger';
 import { Coords } from "@/game/Coords";
 import { TaskStatus } from "@/game/gameobject/task/system/TaskStatus";
 import { ZoneType } from "@/game/gameobject/unit/ZoneType";
@@ -80,7 +81,7 @@ export class MoveTask extends Task {
   private toBridge: boolean;
   private options?: MoveOptions;
   public preventOpportunityFire = false;
-  private logger: Logger;
+  private logger: ILogger;
   private destinationLeptons: Vector2;
   private currentWaypointLeptons: Vector2;
   private needsPathUpdate = false;
diff --git a/src/gui/PointerEvents.ts b/src/gui/PointerEvents.ts
index 19d94bb..65afd79 100644
--- a/src/gui/PointerEvents.ts
+++ b/src/gui/PointerEvents.ts
@@ -1,6 +1,6 @@
-import { CompositeDisposable } from '../util/disposable/CompositeDisposable';
-import { equals } from '../util/Array';
-import { clamp } from '../util/math';
+import { CompositeDisposable } from "../util/disposable/CompositeDisposable";
+import { equals } from '../util/array';
+import { clamp } from "../util/math";
 import * as THREE from 'three';

 // 类型定义
diff --git a/src/gui/component/GameResourcesViewer.tsx b/src/gui/component/GameResourcesViewer.tsx
index 887e22c..d09a13b 100644
--- a/src/gui/component/GameResourcesViewer.tsx
+++ b/src/gui/component/GameResourcesViewer.tsx
@@ -1,6 +1,6 @@
 import React, { useEffect, useRef, useState } from 'react';
 import { Engine } from '../../engine/Engine';
-import AppLogger from '../../util/Logger';
+import AppLogger from '../../util/logger';

 // Global types are defined in src/types/global.d.ts

diff --git a/src/gui/screen/game/component/hud/SidebarPower.ts b/src/gui/screen/game/component/hud/SidebarPower.ts
index c314a1d..bda041d 100644
--- a/src/gui/screen/game/component/hud/SidebarPower.ts
+++ b/src/gui/screen/game/component/hud/SidebarPower.ts
@@ -9,7 +9,7 @@ import { clamp } from "@/util/math";
 import { TextureUtils } from "@/engine/gfx/TextureUtils";
 import { HighlightAnimRunner } from "@/engine/renderable/entity/HighlightAnimRunner";
 import { BoxedVar } from "@/util/BoxedVar";
-import { findReverse } from "@/util/Array";
+import { findReverse } from "@/util/array";
 import { PaletteBasicMaterial } from "@/engine/gfx/material/PaletteBasicMaterial";

 type SidebarPowerModel = {
diff --git a/src/gui/screen/mainMenu/lobby/SkirmishScreen.ts b/src/gui/screen/mainMenu/lobby/SkirmishScreen.ts
index c1fd1c3..5d83d87 100644
--- a/src/gui/screen/mainMenu/lobby/SkirmishScreen.ts
+++ b/src/gui/screen/mainMenu/lobby/SkirmishScreen.ts
@@ -25,7 +25,7 @@ import { HtmlView } from "@/gui/jsx/HtmlView";
 // DownloadError - 暂时注释,使用any类型替代
 // import { CancellationTokenSource, OperationCanceledError } from "@puzzl/core/lib/async/cancellation"; // 未使用
 import { MapPreviewRenderer } from "@/gui/screen/mainMenu/lobby/MapPreviewRenderer";
-import { findIndexReverse } from "@/util/Array";
+import { findIndexReverse } from "@/util/array";
 import { StorageKey } from "@/LocalPrefs";
 import { isNotNullOrUndefined } from "@/util/typeGuard";
 import { PreferredHostOpts } from "./PreferredHostOpts";
diff --git a/src/gui/screen/options/component/StorageExplorer.tsx b/src/gui/screen/options/component/StorageExplorer.tsx
index 33cb019..ffaefee 100644
--- a/src/gui/screen/options/component/StorageExplorer.tsx
+++ b/src/gui/screen/options/component/StorageExplorer.tsx
@@ -1,6 +1,6 @@
 import React, { useEffect, useRef, useState } from 'react';
 import { Engine } from '../../../../engine/Engine';
-import AppLogger from '../../../../util/Logger';
+import AppLogger from '../../../../util/logger';
 import { Strings } from '../../../../data/Strings';
 import { MessageBoxApi } from '../../../component/MessageBoxApi';

diff --git a/vite.config.ts b/vite.config.ts
index a74a036..13db9ff 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -6,6 +6,9 @@ export default defineConfig({
   plugins: [react()],
   server: {
     port: 3000, // 您可以根据需要更改端口
+    host: 'localhost', // 明确指定 host
+    // 注意:这些 CORS 头部需要在生产环境中启用以支持 SharedArrayBuffer
+    // 如果遇到跨域问题,请临时注释掉
     headers: {
       'Cross-Origin-Embedder-Policy': 'require-corp',
       'Cross-Origin-Opener-Policy': 'same-origin',
3.2 缺少资源文件

下载 https://download.ra2web.com/full-pack.7z ,网页中选择此打包文件,或者选择解压出来的文件夹。