feat: integrate erqiwang rooms and use spec-compliant Web compilation
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../../sdk/contracts/roomtype.ts';
|
||||||
export type VipCode = string | number;
|
export type VipCode = string | number;
|
||||||
/** min_ary_indexof in the legacy source compares short codes with ==. */
|
/** min_ary_indexof in the legacy source compares short codes with ==. */
|
||||||
export const sameVipCode=(left:VipCode,right:VipCode):boolean=>left==right;
|
export const sameVipCode=(left:VipCode,right:VipCode):boolean=>left==right;
|
||||||
@@ -5,7 +6,7 @@ export interface VipRoom {
|
|||||||
readonly shortCode: VipCode;
|
readonly shortCode: VipCode;
|
||||||
readonly title: string;
|
readonly title: string;
|
||||||
readonly owner: string;
|
readonly owner: string;
|
||||||
readonly roomcodes: { readonly roomtype: readonly unknown[]; readonly roomlist: readonly VipCode[] } | null;
|
readonly roomcodes: { readonly roomtype: Roomtype; readonly roomlist: readonly VipCode[] } | null;
|
||||||
readonly playerList: readonly (readonly unknown[])[];
|
readonly playerList: readonly (readonly unknown[])[];
|
||||||
readonly deskState: readonly unknown[];
|
readonly deskState: readonly unknown[];
|
||||||
readonly seatCount: readonly VipCode[];
|
readonly seatCount: readonly VipCode[];
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../sdk/contracts/roomtype.ts';
|
||||||
import { APP } from '../core/constants.ts';
|
import { APP } from '../core/constants.ts';
|
||||||
import type { OutboundEnvelope } from '../core/types/envelope.ts';
|
import type { OutboundEnvelope } from '../core/types/envelope.ts';
|
||||||
import type {
|
import type {
|
||||||
@@ -48,7 +49,7 @@ type SubscriptionReleaseResult =
|
|||||||
|
|
||||||
interface BoundRoomGeneration {
|
interface BoundRoomGeneration {
|
||||||
readonly roomcode: string;
|
readonly roomcode: string;
|
||||||
readonly roomtype: readonly unknown[];
|
readonly roomtype: Roomtype;
|
||||||
readonly selfSeat: number;
|
readonly selfSeat: number;
|
||||||
readonly seatCount: number;
|
readonly seatCount: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ export class PlatformRuntime {
|
|||||||
this.wireIsOpen = false;
|
this.wireIsOpen = false;
|
||||||
|
|
||||||
const errors: unknown[] = [];
|
const errors: unknown[] = [];
|
||||||
for (const off of [...this.stateObservers]) {
|
for (const off of [...this.stateObservers]) {
|
||||||
this.captureCleanupError(errors, off);
|
this.captureCleanupError(errors, off);
|
||||||
}
|
}
|
||||||
this.captureCleanupError(errors, () => { this.clearLoginGuard(); });
|
this.captureCleanupError(errors, () => { this.clearLoginGuard(); });
|
||||||
@@ -556,7 +556,7 @@ export class PlatformRuntime {
|
|||||||
this.connectionIntent = { type: 'none' };
|
this.connectionIntent = { type: 'none' };
|
||||||
this.wireIsOpen = false;
|
this.wireIsOpen = false;
|
||||||
const errors: unknown[] = [];
|
const errors: unknown[] = [];
|
||||||
for (const off of [...this.stateObservers]) {
|
for (const off of [...this.stateObservers]) {
|
||||||
this.captureCleanupError(errors, off);
|
this.captureCleanupError(errors, off);
|
||||||
}
|
}
|
||||||
this.captureCleanupError(errors, () => { this.store.setConnectionPhase('kicked'); });
|
this.captureCleanupError(errors, () => { this.store.setConnectionPhase('kicked'); });
|
||||||
@@ -722,7 +722,7 @@ export class PlatformRuntime {
|
|||||||
this.wireIsOpen = false;
|
this.wireIsOpen = false;
|
||||||
|
|
||||||
const cleanupErrors: unknown[] = [];
|
const cleanupErrors: unknown[] = [];
|
||||||
for (const off of [...this.stateObservers]) {
|
for (const off of [...this.stateObservers]) {
|
||||||
this.captureCleanupError(cleanupErrors, off);
|
this.captureCleanupError(cleanupErrors, off);
|
||||||
}
|
}
|
||||||
this.captureCleanupError(cleanupErrors, () => { this.clearLoginGuard(); });
|
this.captureCleanupError(cleanupErrors, () => { this.clearLoginGuard(); });
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../../sdk/contracts/roomtype.ts';
|
||||||
import type { Unsubscribe } from '../../core/reactive.ts';
|
import type { Unsubscribe } from '../../core/reactive.ts';
|
||||||
import {parseVipRooms} from '../../protocol/contracts/vip-room.ts';
|
import {parseVipRooms} from '../../protocol/contracts/vip-room.ts';
|
||||||
import {parseRankList,parseVipRankList} from '../../protocol/contracts/rank-list.ts';
|
import {parseRankList,parseVipRankList} from '../../protocol/contracts/rank-list.ts';
|
||||||
@@ -6,7 +7,8 @@ import type {LoginAccountIdentity} from '../../protocol/contracts/login-contract
|
|||||||
import {requireStringOrFiniteNumber} from '../../protocol/contracts/validation.ts';
|
import {requireStringOrFiniteNumber} from '../../protocol/contracts/validation.ts';
|
||||||
import {
|
import {
|
||||||
hasOwn,
|
hasOwn,
|
||||||
requireArray,
|
requireArray,
|
||||||
|
requireRoomtype,
|
||||||
requireBoolean,
|
requireBoolean,
|
||||||
requireInteger,
|
requireInteger,
|
||||||
requireNumber,
|
requireNumber,
|
||||||
@@ -152,7 +154,7 @@ function verifyRoomtypeSourceGraph(graph: readonly RoomtypeObjectSnapshot[]): vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cloneAndFreezeRoomtype(value: readonly unknown[]): readonly unknown[] {
|
export function cloneAndFreezeRoomtype(value: Roomtype): Roomtype {
|
||||||
const copies = new WeakMap<object, object>();
|
const copies = new WeakMap<object, object>();
|
||||||
const active = new WeakSet<object>();
|
const active = new WeakSet<object>();
|
||||||
const ownedGraph: object[] = [];
|
const ownedGraph: object[] = [];
|
||||||
@@ -241,7 +243,7 @@ export function cloneAndFreezeRoomtype(value: readonly unknown[]): readonly unkn
|
|||||||
return target;
|
return target;
|
||||||
};
|
};
|
||||||
|
|
||||||
const canonical = copy(value, 'roomtype') as readonly unknown[];
|
const canonical = copy(value, 'roomtype') as Roomtype;
|
||||||
verifyRoomtypeSourceGraph(sourceGraph);
|
verifyRoomtypeSourceGraph(sourceGraph);
|
||||||
for (let index = ownedGraph.length - 1; index >= 0; index -= 1) {
|
for (let index = ownedGraph.length - 1; index >= 0; index -= 1) {
|
||||||
Object.freeze(ownedGraph[index]);
|
Object.freeze(ownedGraph[index]);
|
||||||
@@ -287,7 +289,7 @@ function buildRoom(
|
|||||||
const raw = requireRecord(rawValue, '$.raw');
|
const raw = requireRecord(rawValue, '$.raw');
|
||||||
const roomcode = requireString(room.roomcode, '$.room.roomcode');
|
const roomcode = requireString(room.roomcode, '$.room.roomcode');
|
||||||
const selfSeat = requireInteger(room.seat, '$.room.seat');
|
const selfSeat = requireInteger(room.seat, '$.room.seat');
|
||||||
const roomtype = requireArray(room.roomtype, '$.room.roomtype');
|
const roomtype = requireRoomtype(room.roomtype, '$.room.roomtype');
|
||||||
const sourcePlayers = requireArray(room.players, '$.room.players');
|
const sourcePlayers = requireArray(room.players, '$.room.players');
|
||||||
if (requireString(raw.roomcode, '$.raw.roomcode') !== roomcode) {
|
if (requireString(raw.roomcode, '$.raw.roomcode') !== roomcode) {
|
||||||
throw new RangeError('$.room.roomcode: expected value parsed from raw roomcode');
|
throw new RangeError('$.room.roomcode: expected value parsed from raw roomcode');
|
||||||
@@ -569,7 +571,7 @@ export class PlatformStore {
|
|||||||
this.transitions.push({
|
this.transitions.push({
|
||||||
state,
|
state,
|
||||||
previous,
|
previous,
|
||||||
listeners: [...this.listeners],
|
listeners: [...this.listeners],
|
||||||
});
|
});
|
||||||
if (this.publishing) return state;
|
if (this.publishing) return state;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../../sdk/contracts/roomtype.ts';
|
||||||
import type { PlatformGameConnectionPhase } from '../../sdk/contracts/snapshots.ts';
|
import type { PlatformGameConnectionPhase } from '../../sdk/contracts/snapshots.ts';
|
||||||
import type { TaskData } from '../../core/types/task.ts';
|
import type { TaskData } from '../../core/types/task.ts';
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ export interface InsideRoomState {
|
|||||||
readonly seatPlayerIds: readonly (number | null)[];
|
readonly seatPlayerIds: readonly (number | null)[];
|
||||||
readonly readySeats: readonly number[];
|
readonly readySeats: readonly number[];
|
||||||
readonly offlineSeats: readonly number[];
|
readonly offlineSeats: readonly number[];
|
||||||
readonly roomtype: readonly unknown[];
|
readonly roomtype: Roomtype;
|
||||||
readonly stage: number;
|
readonly stage: number;
|
||||||
readonly needprepare: number;
|
readonly needprepare: number;
|
||||||
readonly infinite: number;
|
readonly infinite: number;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
export {
|
export {
|
||||||
hasOwn,
|
hasOwn,
|
||||||
optionalField,
|
optionalField,
|
||||||
requireArray,
|
requireArray,
|
||||||
|
requireRoomtype,
|
||||||
requireBoolean,
|
requireBoolean,
|
||||||
requireInteger,
|
requireInteger,
|
||||||
requireNumber,
|
requireNumber,
|
||||||
|
|||||||
+9
-7
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../../sdk/contracts/roomtype.ts';
|
||||||
import {
|
import {
|
||||||
buildFirstSliceEnvelope,
|
buildFirstSliceEnvelope,
|
||||||
type FirstSliceEnvelope,
|
type FirstSliceEnvelope,
|
||||||
@@ -5,7 +6,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
hasOwn,
|
hasOwn,
|
||||||
optionalField,
|
optionalField,
|
||||||
requireArray,
|
requireArray,
|
||||||
|
requireRoomtype,
|
||||||
requireInteger,
|
requireInteger,
|
||||||
requireNumber,
|
requireNumber,
|
||||||
requireRecord,
|
requireRecord,
|
||||||
@@ -22,7 +24,7 @@ export type ReconnectSnapshot =
|
|||||||
export interface ParsedRoomSnapshot {
|
export interface ParsedRoomSnapshot {
|
||||||
readonly roomcode: string;
|
readonly roomcode: string;
|
||||||
readonly seat: number;
|
readonly seat: number;
|
||||||
readonly roomtype: readonly unknown[];
|
readonly roomtype: Roomtype;
|
||||||
readonly players: readonly unknown[];
|
readonly players: readonly unknown[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +42,7 @@ export function reconnectFrom(raw: JsonRecord): ReconnectSnapshot {
|
|||||||
export function parseRoomEntryFields(raw: JsonRecord): ParsedRoomSnapshot {
|
export function parseRoomEntryFields(raw: JsonRecord): ParsedRoomSnapshot {
|
||||||
const roomcode = requireString(raw.roomcode, '$.data.roomcode');
|
const roomcode = requireString(raw.roomcode, '$.data.roomcode');
|
||||||
const seat = requireInteger(raw.seat, '$.data.seat');
|
const seat = requireInteger(raw.seat, '$.data.seat');
|
||||||
const roomtype = requireArray(raw.roomtype, '$.data.roomtype');
|
const roomtype = requireRoomtype(raw.roomtype, '$.data.roomtype');
|
||||||
const players = requireArray(raw.players, '$.data.players');
|
const players = requireArray(raw.players, '$.data.players');
|
||||||
if (seat < 0 || seat >= players.length) {
|
if (seat < 0 || seat >= players.length) {
|
||||||
throw new RangeError(`$.data.seat: expected server seat index within players, received number`);
|
throw new RangeError(`$.data.seat: expected server seat index within players, received number`);
|
||||||
@@ -246,7 +248,7 @@ export function parseKickServerPayload(value: unknown): ParsedKickPayload {
|
|||||||
|
|
||||||
|
|
||||||
export interface CreateRoomEnvironment {
|
export interface CreateRoomEnvironment {
|
||||||
readonly roomtype: readonly unknown[];
|
readonly roomtype: Roomtype;
|
||||||
readonly location: unknown;
|
readonly location: unknown;
|
||||||
readonly ip: string;
|
readonly ip: string;
|
||||||
}
|
}
|
||||||
@@ -267,7 +269,7 @@ export function buildCreateRoomRequest(
|
|||||||
agentid: requireStringOrFiniteNumber(identity.agentid, '$.identity.agentid'),
|
agentid: requireStringOrFiniteNumber(identity.agentid, '$.identity.agentid'),
|
||||||
playerid: requireInteger(playerid, '$.playerid'),
|
playerid: requireInteger(playerid, '$.playerid'),
|
||||||
gameid: requireStringOrFiniteNumber(identity.gameid, '$.identity.gameid'),
|
gameid: requireStringOrFiniteNumber(identity.gameid, '$.identity.gameid'),
|
||||||
roomtype: requireArray(raw.roomtype, '$.command.roomtype'),
|
roomtype: requireRoomtype(raw.roomtype, '$.command.roomtype'),
|
||||||
ip: requireString(raw.ip, '$.command.ip'),
|
ip: requireString(raw.ip, '$.command.ip'),
|
||||||
location: raw.location,
|
location: raw.location,
|
||||||
});
|
});
|
||||||
@@ -275,7 +277,7 @@ export function buildCreateRoomRequest(
|
|||||||
|
|
||||||
export interface ParsedCreateRoomResponse {
|
export interface ParsedCreateRoomResponse {
|
||||||
readonly state: number;
|
readonly state: number;
|
||||||
readonly room: { readonly roomcode: string; readonly seat: number; readonly roomtype: readonly unknown[] } | null;
|
readonly room: { readonly roomcode: string; readonly seat: number; readonly roomtype: Roomtype } | null;
|
||||||
readonly needprepare: number;
|
readonly needprepare: number;
|
||||||
readonly infinite: number;
|
readonly infinite: number;
|
||||||
readonly raw: JsonRecord;
|
readonly raw: JsonRecord;
|
||||||
@@ -296,7 +298,7 @@ export function parseCreateRoomResponse(value: unknown): ParsedCreateRoomRespons
|
|||||||
state,
|
state,
|
||||||
room: {roomcode: requireString(raw.roomcode, '$.data.roomcode'),
|
room: {roomcode: requireString(raw.roomcode, '$.data.roomcode'),
|
||||||
seat: requireInteger(raw.seat, '$.data.seat'),
|
seat: requireInteger(raw.seat, '$.data.seat'),
|
||||||
roomtype: requireArray(raw.roomtype, '$.data.roomtype')},
|
roomtype: requireRoomtype(raw.roomtype, '$.data.roomtype')},
|
||||||
needprepare: flag('needprepare'), infinite: flag('infinite'), raw,
|
needprepare: flag('needprepare'), infinite: flag('infinite'), raw,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../../sdk/contracts/roomtype.ts';
|
||||||
export type JsonRecord = Readonly<Record<string, unknown>>;
|
export type JsonRecord = Readonly<Record<string, unknown>>;
|
||||||
|
|
||||||
function receivedType(value: unknown): string {
|
function receivedType(value: unknown): string {
|
||||||
@@ -66,3 +67,9 @@ export function optionalField<T>(
|
|||||||
if (!hasOwn(record, key)) return undefined;
|
if (!hasOwn(record, key)) return undefined;
|
||||||
return validate(record[key], `${path}.${key}`);
|
return validate(record[key], `${path}.${key}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Validate the transport shape without interpreting game-specific options. */
|
||||||
|
export function requireRoomtype(value: unknown, path: string): Roomtype {
|
||||||
|
if (typeof value === 'string' || Array.isArray(value)) return value;
|
||||||
|
return invalid(path, 'string or array', value);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {requireArray,requireRecord,requireString} from './validation.ts';
|
import {requireArray,requireRoomtype,requireRecord,requireString} from './validation.ts';
|
||||||
import type {VipCode,VipRoom} from '../../core/types/vip-room.ts';
|
import type {VipCode,VipRoom} from '../../core/types/vip-room.ts';
|
||||||
export function vipCode(value:unknown,path:string):VipCode {
|
export function vipCode(value:unknown,path:string):VipCode {
|
||||||
if(typeof value==='string'&&value.length>0)return value;
|
if(typeof value==='string'&&value.length>0)return value;
|
||||||
@@ -12,7 +12,8 @@ export function parseVipRooms(payload:unknown):readonly VipRoom[]{
|
|||||||
const p=`$.data.roomInfo[${index}]`,r=requireRecord(value,p);
|
const p=`$.data.roomInfo[${index}]`,r=requireRecord(value,p);
|
||||||
const playerList=requireArray(r.playerList,p+'.playerList').map((v,i)=>Object.freeze([...requireArray(v,`${p}.playerList[${i}]`)]));
|
const playerList=requireArray(r.playerList,p+'.playerList').map((v,i)=>Object.freeze([...requireArray(v,`${p}.playerList[${i}]`)]));
|
||||||
const codes=r.roomcodes?requireRecord(r.roomcodes,p+'.roomcodes'):null;
|
const codes=r.roomcodes?requireRecord(r.roomcodes,p+'.roomcodes'):null;
|
||||||
const roomcodes=codes?Object.freeze({roomtype:Object.freeze([...requireArray(codes.roomtype,p+'.roomcodes.roomtype')]),roomlist:Object.freeze(requireArray(codes.roomlist,p+'.roomcodes.roomlist').map((v,i)=>vipCode(v,`${p}.roomcodes.roomlist[${i}]`)))}):null;
|
const rawType=codes?requireRoomtype(codes.roomtype,p+'.roomcodes.roomtype'):null;
|
||||||
|
const roomcodes=codes?Object.freeze({roomtype:typeof rawType==='string'?rawType:Object.freeze([...(rawType as readonly unknown[])]),roomlist:Object.freeze(requireArray(codes.roomlist,p+'.roomcodes.roomlist').map((v,i)=>vipCode(v,`${p}.roomcodes.roomlist[${i}]`)))}):null;
|
||||||
const deskState=roomcodes?requireArray(r.deskState,p+'.deskState'):[];
|
const deskState=roomcodes?requireArray(r.deskState,p+'.deskState'):[];
|
||||||
const seatCount=roomcodes?requireArray(r.seatCount,p+'.seatCount').map((v,i)=>vipCode(v,`${p}.seatCount[${i}]`)):[];
|
const seatCount=roomcodes?requireArray(r.seatCount,p+'.seatCount').map((v,i)=>vipCode(v,`${p}.seatCount[${i}]`)):[];
|
||||||
if(roomcodes&&[roomcodes.roomlist.length,deskState.length,seatCount.length].some(n=>n!==playerList.length))throw TypeError(p+': desk arrays must have matching lengths');
|
if(roomcodes&&[roomcodes.roomlist.length,deskState.length,seatCount.length].some(n=>n!==playerList.length))throw TypeError(p+': desk arrays must have matching lengths');
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import type {Roomtype} from './roomtype.ts';
|
||||||
/** Pre-room capability: a game owns its page and validated, opaque wire configuration. */
|
/** Pre-room capability: a game owns its page and validated, opaque wire configuration. */
|
||||||
export interface CreateRoomPageContext {
|
export interface CreateRoomPageContext {
|
||||||
readonly previousRoomtype:unknown;
|
readonly previousRoomtype:unknown;
|
||||||
submit(roomtype:readonly unknown[]):void;
|
submit(roomtype: Roomtype):void;
|
||||||
cancel():void;
|
cancel():void;
|
||||||
reportError(message:string):void;
|
reportError(message:string):void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from './roomtype.ts';
|
||||||
import type { GameModule } from './game-module.ts';
|
import type { GameModule } from './game-module.ts';
|
||||||
|
|
||||||
/** The one compile-time game identity and module factory for an app. */
|
/** The one compile-time game identity and module factory for an app. */
|
||||||
@@ -6,6 +7,6 @@ export interface GameEntry {
|
|||||||
readonly gameId: string | number;
|
readonly gameId: string | number;
|
||||||
readonly route: string;
|
readonly route: string;
|
||||||
/** Interprets this game's actual server roomtype; no synthetic/default input is required. */
|
/** Interprets this game's actual server roomtype; no synthetic/default input is required. */
|
||||||
resolveSeatCount(roomtype: readonly unknown[]): number;
|
resolveSeatCount(roomtype: Roomtype): number;
|
||||||
createModule(): GameModule;
|
createModule(): GameModule;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ export * from './game-module.ts';
|
|||||||
export * from './game-seat-mapper.ts';
|
export * from './game-seat-mapper.ts';
|
||||||
export * from './platform-events.ts';
|
export * from './platform-events.ts';
|
||||||
export * from './snapshots.ts';
|
export * from './snapshots.ts';
|
||||||
|
|
||||||
|
export type {Roomtype} from './roomtype.ts';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import type {Roomtype} from './roomtype.ts';
|
||||||
/** Platform lifecycle events delivered to the current game module. */
|
/** Platform lifecycle events delivered to the current game module. */
|
||||||
export type PlatformToGameEvent =
|
export type PlatformToGameEvent =
|
||||||
| { readonly type: 'room.entered'; readonly roomtype: readonly unknown[] }
|
| { readonly type: 'room.entered'; readonly roomtype: Roomtype }
|
||||||
| { readonly type: 'room.player-joined'; readonly seat: number }
|
| { readonly type: 'room.player-joined'; readonly seat: number }
|
||||||
| { readonly type: 'room.player-left'; readonly seat: number }
|
| { readonly type: 'room.player-left'; readonly seat: number }
|
||||||
| { readonly type: 'room.player-ready'; readonly seat: number }
|
| { readonly type: 'room.player-ready'; readonly seat: number }
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/** Opaque subgame wire configuration. The game defines its contents. */
|
||||||
|
export type Roomtype = string | readonly unknown[];
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "69bfa9e3-15e3-4ed5-a26a-1fda48ffc906",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from './roomtype.ts';
|
||||||
/** Public connection phases available to a game. */
|
/** Public connection phases available to a game. */
|
||||||
export type PlatformGameConnectionPhase =
|
export type PlatformGameConnectionPhase =
|
||||||
| 'connected'
|
| 'connected'
|
||||||
@@ -20,7 +21,7 @@ export interface PlatformGameSelfSnapshot {
|
|||||||
/** Plain public room projection. `roomtype` remains opaque server data. */
|
/** Plain public room projection. `roomtype` remains opaque server data. */
|
||||||
export interface PlatformGameRoomSnapshot {
|
export interface PlatformGameRoomSnapshot {
|
||||||
readonly roomcode: string;
|
readonly roomcode: string;
|
||||||
readonly roomtype: readonly unknown[];
|
readonly roomtype: Roomtype;
|
||||||
readonly stage: number;
|
readonly stage: number;
|
||||||
readonly needprepare: number;
|
readonly needprepare: number;
|
||||||
readonly infinite: number;
|
readonly infinite: number;
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../contracts/roomtype.ts';
|
||||||
import type { strict } from 'node:assert';
|
import type { strict } from 'node:assert';
|
||||||
import type {
|
import type {
|
||||||
GameEntry,
|
GameEntry,
|
||||||
@@ -16,7 +17,7 @@ export type GameContractHostFactory = () => GameContractHost;
|
|||||||
|
|
||||||
/** The game owns each room configuration, its expected count and matching Host fixture. */
|
/** The game owns each room configuration, its expected count and matching Host fixture. */
|
||||||
export interface GameContractSample {
|
export interface GameContractSample {
|
||||||
readonly roomtype: readonly unknown[];
|
readonly roomtype: Roomtype;
|
||||||
readonly expectedSeatCount: number;
|
readonly expectedSeatCount: number;
|
||||||
readonly makeHost: GameContractHostFactory;
|
readonly makeHost: GameContractHostFactory;
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -701,7 +701,7 @@
|
|||||||
},
|
},
|
||||||
"_lpos": {
|
"_lpos": {
|
||||||
"__type__": "cc.Vec3",
|
"__type__": "cc.Vec3",
|
||||||
"x": -229.49841260344616,
|
"x": -231.99801937299284,
|
||||||
"y": 178,
|
"y": 178,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
@@ -742,8 +742,8 @@
|
|||||||
},
|
},
|
||||||
"_contentSize": {
|
"_contentSize": {
|
||||||
"__type__": "cc.Size",
|
"__type__": "cc.Size",
|
||||||
"width": 19.996825206892293,
|
"width": 24.996038745985672,
|
||||||
"height": 25.200000000000003
|
"height": 31.500000000000004
|
||||||
},
|
},
|
||||||
"_anchorPoint": {
|
"_anchorPoint": {
|
||||||
"__type__": "cc.Vec2",
|
"__type__": "cc.Vec2",
|
||||||
@@ -781,10 +781,10 @@
|
|||||||
"_string": "消",
|
"_string": "消",
|
||||||
"_horizontalAlign": 0,
|
"_horizontalAlign": 0,
|
||||||
"_verticalAlign": 1,
|
"_verticalAlign": 1,
|
||||||
"_actualFontSize": 21.083333333333336,
|
"_actualFontSize": 26.354166666666668,
|
||||||
"_fontSize": 20,
|
"_fontSize": 25,
|
||||||
"_fontFamily": "Arial",
|
"_fontFamily": "Arial",
|
||||||
"_lineHeight": 20,
|
"_lineHeight": 25,
|
||||||
"_overflow": 0,
|
"_overflow": 0,
|
||||||
"_enableWrapText": true,
|
"_enableWrapText": true,
|
||||||
"_font": null,
|
"_font": null,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.2.0",
|
||||||
|
"importer": "directory",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "66d74934-1469-4fe1-ad7d-92b5cd70e688",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.50",
|
||||||
|
"importer": "prefab",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "c1608cf0-5b48-4714-8a06-9363c854ab71",
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"syncNodeName": "ErqiwangCreateRoom"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import {_decorator,Button,Label,Toggle,ToggleContainer} from 'cc';
|
||||||
|
import {CreateRoomPage} from '../../scripts/platform-login/CreateRoomPage.ts';
|
||||||
|
import type {CreateRoomPageContext} from '../../framework/sdk/contracts/create-room-page.ts';
|
||||||
|
import {ErqiwangRoomRules} from './erqiwang-room-rules.ts';
|
||||||
|
const {ccclass,property}=_decorator;
|
||||||
|
@ccclass('ErqiwangCreateRoomView')
|
||||||
|
export class ErqiwangCreateRoomView extends CreateRoomPage {
|
||||||
|
@property([ToggleContainer]) groups:ToggleContainer[]=[];
|
||||||
|
@property([Toggle]) options:Toggle[]=[];
|
||||||
|
@property([Label]) optionLabels:Label[]=[];
|
||||||
|
@property(Button) submitButton:Button|null=null;
|
||||||
|
@property([Button]) cancelButtons:Button[]=[];
|
||||||
|
@property(Label) feeLabel:Label|null=null;
|
||||||
|
private readonly rules=new ErqiwangRoomRules();
|
||||||
|
private context:CreateRoomPageContext|null=null;
|
||||||
|
private busy=false;
|
||||||
|
private releases:Array<()=>void>=[];
|
||||||
|
open(context:CreateRoomPageContext):void{
|
||||||
|
this.close();
|
||||||
|
if(this.groups.length!==3||this.options.length!==8||this.optionLabels.length!==8||!this.feeLabel||!this.submitButton||this.cancelButtons.length!==2)throw Error('ErqiwangCreateRoomView requires serialized controls');
|
||||||
|
this.rules.open(context.previousRoomtype);this.context=context;
|
||||||
|
// Permit all toggles to reset before restoring each mandatory group.
|
||||||
|
this.groups.forEach(group=>group.allowSwitchOff=true);
|
||||||
|
this.optionLabels.forEach((label,i)=>label.string=['6局','12局','房主扣卡','AA每人扣卡','可查牌','不查牌','傍王','爬坡'][i]);
|
||||||
|
this.options.forEach((toggle,i)=>{
|
||||||
|
toggle.isChecked=i<6?this.rules.selection[Math.floor(i/2)]===i%2:this.rules.selection[i-3]===1;
|
||||||
|
const changed=()=>{if(this.busy||!this.context)return;if(i<6&&!toggle.isChecked)return;this.rules.select(i<6?Math.floor(i/2):i-3,i<6?i%2:Number(toggle.isChecked));this.renderFee();};
|
||||||
|
toggle.node.on(Toggle.EventType.TOGGLE,changed);this.releases.push(()=>toggle.node.off(Toggle.EventType.TOGGLE,changed));
|
||||||
|
});
|
||||||
|
this.groups.forEach(group=>group.allowSwitchOff=false);
|
||||||
|
const bind=(button:Button,action:()=>void)=>{const fn=()=>{if(!this.busy&&this.context)try{action();}catch(error){context.reportError(error instanceof Error?error.message:String(error));}};
|
||||||
|
button.node.on(Button.EventType.CLICK,fn);this.releases.push(()=>button.node.off(Button.EventType.CLICK,fn));};
|
||||||
|
bind(this.submitButton,()=>context.submit(this.rules.build()));
|
||||||
|
this.cancelButtons.forEach(button=>{const cancel=()=>{if(this.context===context)context.cancel();};button.node.on(Button.EventType.CLICK,cancel);this.releases.push(()=>button.node.off(Button.EventType.CLICK,cancel));});this.setBusy(false);this.renderFee();
|
||||||
|
}
|
||||||
|
private renderFee():void{if(this.feeLabel)this.feeLabel.string=`${this.rules.selection[1]===1?'每人':'房主'}消耗 ${this.rules.roomCards} 张房卡`; }
|
||||||
|
setBusy(busy:boolean):void{this.busy=busy;this.options.forEach(toggle=>toggle.interactable=!busy);if(this.submitButton)this.submitButton.interactable=!busy;}
|
||||||
|
close():void{for(const release of this.releases.splice(0))release();this.context=null;}
|
||||||
|
onDestroy():void{this.close();}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "987021eb-b5b3-4b73-bba9-39f3ea97c6b9",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.1.50",
|
||||||
|
"importer": "prefab",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "28fcf5a7-d779-4400-9c71-300cf492bcc7",
|
||||||
|
"files": [
|
||||||
|
".json"
|
||||||
|
],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {
|
||||||
|
"syncNodeName": "ErqiwangRoom"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import {_decorator} from 'cc';
|
||||||
|
import {TemplateRoomView} from '../template/TemplateRoomView.ts';
|
||||||
|
import type {TemplateRoomActions} from '../template/template-game.ts';
|
||||||
|
import type {PlatformGameSnapshot} from '../../framework/sdk/contracts/index.ts';
|
||||||
|
const {ccclass}=_decorator;
|
||||||
|
/** Temporary room receipt surface for the create-room integration stage. */
|
||||||
|
@ccclass('ErqiwangRoomView')
|
||||||
|
export class ErqiwangRoomView extends TemplateRoomView {
|
||||||
|
render(snapshot:PlatformGameSnapshot,actions:TemplateRoomActions):void{
|
||||||
|
super.render(snapshot,actions);
|
||||||
|
if(this.roomLabel)this.roomLabel.string='二七王 房间号:'+snapshot.room.roomcode+'\n玩法尚未接入';
|
||||||
|
if(this.prepareButton)this.prepareButton.node.active=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "aeb4bcf6-864b-4d21-bfce-19b69f5c526c",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import type {GameEntry,GameHost,GameModule,PlatformGameSnapshot} from '../../framework/sdk/contracts/index.ts';
|
||||||
|
import {ErqiwangRoomRules} from './erqiwang-room-rules.ts';
|
||||||
|
export interface ErqiwangRoomActions {prepare():void;exit():void;}
|
||||||
|
export interface ErqiwangRoomPresentation {render(snapshot:PlatformGameSnapshot,actions:ErqiwangRoomActions):void;close():void;}
|
||||||
|
/** Creation-stage room handoff. Gameplay and deskinfo rendering are not migrated yet. */
|
||||||
|
export function createErqiwangGame(gameId:string|number){
|
||||||
|
let active:ErqiwangModule|null=null;
|
||||||
|
class ErqiwangModule implements GameModule {
|
||||||
|
private host:GameHost|null=null;
|
||||||
|
private unsubscribe:(()=>void)|null=null;
|
||||||
|
private view:ErqiwangRoomPresentation|null=null;
|
||||||
|
restored:unknown=null;
|
||||||
|
attach(host:GameHost):void{
|
||||||
|
if(this.host||active)throw Error('Erqiwang module already attached');
|
||||||
|
this.host=host;active=this;this.unsubscribe=host.subscribe(()=>this.render());
|
||||||
|
}
|
||||||
|
mount(view:ErqiwangRoomPresentation):void{this.view?.close();this.view=view;this.render();}
|
||||||
|
private requireHost():GameHost{if(!this.host)throw Error('Erqiwang room session disposed');return this.host;}
|
||||||
|
private render():void{this.view?.render(this.requireHost().getSnapshot(),{prepare:()=>this.requireHost().execute({type:'room.prepare'}),exit:()=>this.requireHost().execute({type:'room.exit'})});}
|
||||||
|
handlePlatformEvent():void{this.render();}
|
||||||
|
handleGameMessage():void{throw Error('二七王玩法消息处理尚未接入');}
|
||||||
|
restore(deskinfo:unknown):void{this.requireHost();this.restored=deskinfo;}
|
||||||
|
dispose():void{this.unsubscribe?.();this.unsubscribe=null;this.view?.close();this.view=null;this.host=null;this.restored=null;if(active===this)active=null;}
|
||||||
|
}
|
||||||
|
const rules=new ErqiwangRoomRules();
|
||||||
|
const entry:GameEntry={key:'erqiwang',gameId,route:'erqiwang',resolveSeatCount:roomtype=>rules.seatCount(roomtype),createModule:()=>new ErqiwangModule()};
|
||||||
|
return {entry,mount(view:ErqiwangRoomPresentation){if(!active)throw Error('Erqiwang room not attached');active.mount(view);},
|
||||||
|
get restoredSnapshot():unknown{return active?.restored;}};
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "9ed79bcf-75f3-44b9-b171-b0f465b7b2fc",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import type {Roomtype} from '../../framework/sdk/contracts/roomtype.ts';
|
||||||
|
/** UI order differs from server class.config.js: aset, deduct, bangwang, climb, nocheck. */
|
||||||
|
const WIRE_INDEX = [0,1,4,2,3] as const;
|
||||||
|
export class ErqiwangRoomRules {
|
||||||
|
private selected=[0,0,0,0,0];
|
||||||
|
get selection():readonly number[]{return [...this.selected];}
|
||||||
|
get roomCards():number{return (this.selected[0]===1?2:1)*(this.selected[1]===1?1:2);}
|
||||||
|
open(previous:unknown):void{
|
||||||
|
if(previous===null){this.selected=[0,0,0,0,0];return;}
|
||||||
|
this.validate(previous);
|
||||||
|
this.selected=WIRE_INDEX.map(index=>Number((previous as string)[index]));
|
||||||
|
}
|
||||||
|
select(group:number,value:number):void{
|
||||||
|
if(!Number.isInteger(group)||group<0||group>=5||(value!==0&&value!==1))throw Error('Invalid erqiwang option');
|
||||||
|
this.selected[group]=value;
|
||||||
|
}
|
||||||
|
build():string{
|
||||||
|
const bits=Array<string>(11).fill('0');
|
||||||
|
WIRE_INDEX.forEach((wire,group)=>bits[wire]=String(this.selected[group]));
|
||||||
|
return bits.join('');
|
||||||
|
}
|
||||||
|
seatCount(roomtype:Roomtype):number{this.validate(roomtype);return 3;}
|
||||||
|
private validate(value:unknown):void{
|
||||||
|
if(typeof value!=='string'||!/^[01]{5}0{6}$/.test(value))throw Error('二七王房间配置必须为 11 位字符串,后 6 位为 0');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "574b385e-9068-4418-8a63-110ad96d0915",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../../framework/sdk/contracts/roomtype.ts';
|
||||||
/** Source: 01_SubGame_modify.js. Options are presentation state, not a rule-array encoder. */
|
/** Source: 01_SubGame_modify.js. Options are presentation state, not a rule-array encoder. */
|
||||||
export class TemplateRoomRules {
|
export class TemplateRoomRules {
|
||||||
readonly labels=['10局(房卡X1)','20局(房卡X2)','房主扣卡','每人扣卡'] as const;
|
readonly labels=['10局(房卡X1)','20局(房卡X2)','房主扣卡','每人扣卡'] as const;
|
||||||
@@ -13,7 +14,7 @@ export class TemplateRoomRules {
|
|||||||
this.selected[group]=index;
|
this.selected[group]=index;
|
||||||
}
|
}
|
||||||
build():unknown[]{return [1,4,1,2,2,[1,1,[1,2000,10],null,null,1],[1,0,5]];}
|
build():unknown[]{return [1,4,1,2,2,[1,1,[1,2000,10],null,null,1],[1,0,5]];}
|
||||||
seatCount(roomtype:readonly unknown[]):number{
|
seatCount(roomtype: Roomtype):number{
|
||||||
if(!Array.isArray(roomtype))throw Error('Template roomtype must be an array');
|
if(!Array.isArray(roomtype))throw Error('Template roomtype must be an array');
|
||||||
// Desk.Create uses Game_Config.Max.PlayerCnt because the template defines no getMaxPlayerCount hook.
|
// Desk.Create uses Game_Config.Max.PlayerCnt because the template defines no getMaxPlayerCount hook.
|
||||||
return 10;
|
return 10;
|
||||||
|
|||||||
@@ -1,661 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"__type__": "cc.SceneAsset",
|
|
||||||
"_name": "Login",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_native": "",
|
|
||||||
"scene": {
|
|
||||||
"__id__": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Scene",
|
|
||||||
"_name": "Login",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_parent": null,
|
|
||||||
"_children": [
|
|
||||||
{
|
|
||||||
"__id__": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 4
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_active": true,
|
|
||||||
"_components": [],
|
|
||||||
"_prefab": {
|
|
||||||
"__id__": 19
|
|
||||||
},
|
|
||||||
"_lpos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_lrot": {
|
|
||||||
"__type__": "cc.Quat",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_lscale": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1,
|
|
||||||
"y": 1,
|
|
||||||
"z": 1
|
|
||||||
},
|
|
||||||
"_mobility": 0,
|
|
||||||
"_layer": 1073741824,
|
|
||||||
"_euler": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"autoReleaseAssets": false,
|
|
||||||
"_globals": {
|
|
||||||
"__id__": 20
|
|
||||||
},
|
|
||||||
"_id": "9490c809-bcb7-4a9e-af1f-acd680227bc4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Node",
|
|
||||||
"_name": "Camera",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_parent": {
|
|
||||||
"__id__": 1
|
|
||||||
},
|
|
||||||
"_children": [],
|
|
||||||
"_active": true,
|
|
||||||
"_components": [
|
|
||||||
{
|
|
||||||
"__id__": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_prefab": null,
|
|
||||||
"_lpos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 800,
|
|
||||||
"y": 360,
|
|
||||||
"z": 1000
|
|
||||||
},
|
|
||||||
"_lrot": {
|
|
||||||
"__type__": "cc.Quat",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_lscale": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1,
|
|
||||||
"y": 1,
|
|
||||||
"z": 1
|
|
||||||
},
|
|
||||||
"_mobility": 0,
|
|
||||||
"_layer": 33554432,
|
|
||||||
"_euler": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_id": "a68KuGzBVD2IGLPd5z3pYi"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Camera",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 2
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_projection": 0,
|
|
||||||
"_priority": 0,
|
|
||||||
"_fov": 45,
|
|
||||||
"_fovAxis": 0,
|
|
||||||
"_orthoHeight": 360,
|
|
||||||
"_near": 1,
|
|
||||||
"_far": 2000,
|
|
||||||
"_color": {
|
|
||||||
"__type__": "cc.Color",
|
|
||||||
"r": 51,
|
|
||||||
"g": 51,
|
|
||||||
"b": 51,
|
|
||||||
"a": 255
|
|
||||||
},
|
|
||||||
"_depth": 1,
|
|
||||||
"_stencil": 0,
|
|
||||||
"_clearFlags": 7,
|
|
||||||
"_rect": {
|
|
||||||
"__type__": "cc.Rect",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 1,
|
|
||||||
"height": 1
|
|
||||||
},
|
|
||||||
"_aperture": 19,
|
|
||||||
"_shutter": 7,
|
|
||||||
"_iso": 0,
|
|
||||||
"_screenScale": 1,
|
|
||||||
"_visibility": 1117782015,
|
|
||||||
"_targetTexture": null,
|
|
||||||
"_postProcess": null,
|
|
||||||
"_usePostProcess": false,
|
|
||||||
"_cameraType": -1,
|
|
||||||
"_trackingType": 0,
|
|
||||||
"_id": "95vXCLVwZAnpgZ7/Uwwsji"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Node",
|
|
||||||
"_name": "Canvas",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_parent": {
|
|
||||||
"__id__": 1
|
|
||||||
},
|
|
||||||
"_children": [
|
|
||||||
{
|
|
||||||
"__id__": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 13
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_active": true,
|
|
||||||
"_components": [
|
|
||||||
{
|
|
||||||
"__id__": 16
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 17
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 18
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_prefab": null,
|
|
||||||
"_lpos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 800,
|
|
||||||
"y": 360,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_lrot": {
|
|
||||||
"__type__": "cc.Quat",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_lscale": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1,
|
|
||||||
"y": 1,
|
|
||||||
"z": 1
|
|
||||||
},
|
|
||||||
"_mobility": 0,
|
|
||||||
"_layer": 33554432,
|
|
||||||
"_euler": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_id": "70gbryz/VPqpu+opfSJoWa"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Node",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"_parent": {
|
|
||||||
"__id__": 4
|
|
||||||
},
|
|
||||||
"_prefab": {
|
|
||||||
"__id__": 6
|
|
||||||
},
|
|
||||||
"__editorExtras__": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.PrefabInfo",
|
|
||||||
"root": {
|
|
||||||
"__id__": 5
|
|
||||||
},
|
|
||||||
"asset": {
|
|
||||||
"__uuid__": "b209cefb-b381-4c7c-b765-94a5ab75a89c",
|
|
||||||
"__expectedType__": "cc.Prefab"
|
|
||||||
},
|
|
||||||
"fileId": "33yDavvzhB6IAjia4PLDbg",
|
|
||||||
"instance": {
|
|
||||||
"__id__": 7
|
|
||||||
},
|
|
||||||
"targetOverrides": null,
|
|
||||||
"nestedPrefabInstanceRoots": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.PrefabInstance",
|
|
||||||
"fileId": "ebnOxopupO4ap7jFhZuQbk",
|
|
||||||
"prefabRootNode": null,
|
|
||||||
"mountedChildren": [],
|
|
||||||
"mountedComponents": [],
|
|
||||||
"propertyOverrides": [
|
|
||||||
{
|
|
||||||
"__id__": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 11
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 12
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"removedComponents": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "CCPropertyOverrideInfo",
|
|
||||||
"targetInfo": {
|
|
||||||
"__id__": 9
|
|
||||||
},
|
|
||||||
"propertyPath": [
|
|
||||||
"_name"
|
|
||||||
],
|
|
||||||
"value": "Login_Layer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.TargetInfo",
|
|
||||||
"localID": [
|
|
||||||
"33yDavvzhB6IAjia4PLDbg"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "CCPropertyOverrideInfo",
|
|
||||||
"targetInfo": {
|
|
||||||
"__id__": 9
|
|
||||||
},
|
|
||||||
"propertyPath": [
|
|
||||||
"_lpos"
|
|
||||||
],
|
|
||||||
"value": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "CCPropertyOverrideInfo",
|
|
||||||
"targetInfo": {
|
|
||||||
"__id__": 9
|
|
||||||
},
|
|
||||||
"propertyPath": [
|
|
||||||
"_lrot"
|
|
||||||
],
|
|
||||||
"value": {
|
|
||||||
"__type__": "cc.Quat",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "CCPropertyOverrideInfo",
|
|
||||||
"targetInfo": {
|
|
||||||
"__id__": 9
|
|
||||||
},
|
|
||||||
"propertyPath": [
|
|
||||||
"_euler"
|
|
||||||
],
|
|
||||||
"value": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Node",
|
|
||||||
"_name": "LoginFlow_Node",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_parent": {
|
|
||||||
"__id__": 4
|
|
||||||
},
|
|
||||||
"_children": [],
|
|
||||||
"_active": true,
|
|
||||||
"_components": [
|
|
||||||
{
|
|
||||||
"__id__": 14
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 15
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_prefab": null,
|
|
||||||
"_lpos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_lrot": {
|
|
||||||
"__type__": "cc.Quat",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_lscale": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1,
|
|
||||||
"y": 1,
|
|
||||||
"z": 1
|
|
||||||
},
|
|
||||||
"_mobility": 0,
|
|
||||||
"_layer": 33554432,
|
|
||||||
"_euler": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_id": "fcp86q55FCsoAB/fOiWeHO"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.UITransform",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 13
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_contentSize": {
|
|
||||||
"__type__": "cc.Size",
|
|
||||||
"width": 100,
|
|
||||||
"height": 100
|
|
||||||
},
|
|
||||||
"_anchorPoint": {
|
|
||||||
"__type__": "cc.Vec2",
|
|
||||||
"x": 0.5,
|
|
||||||
"y": 0.5
|
|
||||||
},
|
|
||||||
"_id": "50hCb+fYBIgL72OODgBoQD"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "bad5buGaitIB7iC7Qf+eoiB",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 13
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_id": "85RWmRT71EzIOWG6Qsha/3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.UITransform",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 4
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_contentSize": {
|
|
||||||
"__type__": "cc.Size",
|
|
||||||
"width": 1600,
|
|
||||||
"height": 720
|
|
||||||
},
|
|
||||||
"_anchorPoint": {
|
|
||||||
"__type__": "cc.Vec2",
|
|
||||||
"x": 0.5,
|
|
||||||
"y": 0.5
|
|
||||||
},
|
|
||||||
"_id": "c6QNB3wx9GYYzOAodcozbv"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Canvas",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 4
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_cameraComponent": null,
|
|
||||||
"_alignCanvasWithScreen": true,
|
|
||||||
"_id": "48VGgW1kRITZOItV2ROj/Y"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Widget",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 4
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_alignFlags": 45,
|
|
||||||
"_target": null,
|
|
||||||
"_left": 0,
|
|
||||||
"_right": 0,
|
|
||||||
"_top": 0,
|
|
||||||
"_bottom": 0,
|
|
||||||
"_horizontalCenter": 0,
|
|
||||||
"_verticalCenter": 0,
|
|
||||||
"_isAbsLeft": true,
|
|
||||||
"_isAbsRight": true,
|
|
||||||
"_isAbsTop": true,
|
|
||||||
"_isAbsBottom": true,
|
|
||||||
"_isAbsHorizontalCenter": true,
|
|
||||||
"_isAbsVerticalCenter": true,
|
|
||||||
"_originalWidth": 1600,
|
|
||||||
"_originalHeight": 720,
|
|
||||||
"_alignMode": 1,
|
|
||||||
"_lockFlags": 0,
|
|
||||||
"_id": "d9PQijkfZPf7WjO0Xufvgu"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.PrefabInfo",
|
|
||||||
"root": null,
|
|
||||||
"asset": null,
|
|
||||||
"fileId": "9490c809-bcb7-4a9e-af1f-acd680227bc4",
|
|
||||||
"instance": null,
|
|
||||||
"targetOverrides": null,
|
|
||||||
"nestedPrefabInstanceRoots": [
|
|
||||||
{
|
|
||||||
"__id__": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.SceneGlobals",
|
|
||||||
"ambient": {
|
|
||||||
"__id__": 21
|
|
||||||
},
|
|
||||||
"shadows": {
|
|
||||||
"__id__": 22
|
|
||||||
},
|
|
||||||
"_skybox": {
|
|
||||||
"__id__": 23
|
|
||||||
},
|
|
||||||
"fog": {
|
|
||||||
"__id__": 24
|
|
||||||
},
|
|
||||||
"octree": {
|
|
||||||
"__id__": 25
|
|
||||||
},
|
|
||||||
"skin": {
|
|
||||||
"__id__": 26
|
|
||||||
},
|
|
||||||
"lightProbeInfo": {
|
|
||||||
"__id__": 27
|
|
||||||
},
|
|
||||||
"postSettings": {
|
|
||||||
"__id__": 28
|
|
||||||
},
|
|
||||||
"bakedWithStationaryMainLight": false,
|
|
||||||
"bakedWithHighpLightmap": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.AmbientInfo",
|
|
||||||
"_skyColorHDR": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0.2,
|
|
||||||
"y": 0.5,
|
|
||||||
"z": 0.8,
|
|
||||||
"w": 0.520833125
|
|
||||||
},
|
|
||||||
"_skyColor": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0.2,
|
|
||||||
"y": 0.5,
|
|
||||||
"z": 0.8,
|
|
||||||
"w": 0.520833125
|
|
||||||
},
|
|
||||||
"_skyIllumHDR": 20000,
|
|
||||||
"_skyIllum": 20000,
|
|
||||||
"_groundAlbedoHDR": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0.2,
|
|
||||||
"y": 0.2,
|
|
||||||
"z": 0.2,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_groundAlbedo": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0.2,
|
|
||||||
"y": 0.2,
|
|
||||||
"z": 0.2,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_skyColorLDR": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0.2,
|
|
||||||
"y": 0.5,
|
|
||||||
"z": 0.8,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_skyIllumLDR": 20000,
|
|
||||||
"_groundAlbedoLDR": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0.2,
|
|
||||||
"y": 0.2,
|
|
||||||
"z": 0.2,
|
|
||||||
"w": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.ShadowsInfo",
|
|
||||||
"_enabled": false,
|
|
||||||
"_type": 0,
|
|
||||||
"_normal": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 1,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_distance": 0,
|
|
||||||
"_planeBias": 1,
|
|
||||||
"_shadowColor": {
|
|
||||||
"__type__": "cc.Color",
|
|
||||||
"r": 0,
|
|
||||||
"g": 0,
|
|
||||||
"b": 0,
|
|
||||||
"a": 76
|
|
||||||
},
|
|
||||||
"_maxReceived": 4,
|
|
||||||
"_size": {
|
|
||||||
"__type__": "cc.Vec2",
|
|
||||||
"x": 1024,
|
|
||||||
"y": 1024
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.SkyboxInfo",
|
|
||||||
"_envLightingType": 0,
|
|
||||||
"_envmapHDR": null,
|
|
||||||
"_envmap": null,
|
|
||||||
"_envmapLDR": null,
|
|
||||||
"_diffuseMapHDR": null,
|
|
||||||
"_diffuseMapLDR": null,
|
|
||||||
"_enabled": false,
|
|
||||||
"_useHDR": true,
|
|
||||||
"_editableMaterial": null,
|
|
||||||
"_reflectionHDR": null,
|
|
||||||
"_reflectionLDR": null,
|
|
||||||
"_rotationAngle": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.FogInfo",
|
|
||||||
"_type": 0,
|
|
||||||
"_fogColor": {
|
|
||||||
"__type__": "cc.Color",
|
|
||||||
"r": 200,
|
|
||||||
"g": 200,
|
|
||||||
"b": 200,
|
|
||||||
"a": 255
|
|
||||||
},
|
|
||||||
"_enabled": false,
|
|
||||||
"_fogDensity": 0.3,
|
|
||||||
"_fogStart": 0.5,
|
|
||||||
"_fogEnd": 300,
|
|
||||||
"_fogAtten": 5,
|
|
||||||
"_fogTop": 1.5,
|
|
||||||
"_fogRange": 1.2,
|
|
||||||
"_accurate": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.OctreeInfo",
|
|
||||||
"_enabled": false,
|
|
||||||
"_minPos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": -1024,
|
|
||||||
"y": -1024,
|
|
||||||
"z": -1024
|
|
||||||
},
|
|
||||||
"_maxPos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1024,
|
|
||||||
"y": 1024,
|
|
||||||
"z": 1024
|
|
||||||
},
|
|
||||||
"_depth": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.SkinInfo",
|
|
||||||
"_enabled": true,
|
|
||||||
"_blurRadius": 0.01,
|
|
||||||
"_sssIntensity": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.LightProbeInfo",
|
|
||||||
"_giScale": 1,
|
|
||||||
"_giSamples": 1024,
|
|
||||||
"_bounces": 2,
|
|
||||||
"_reduceRinging": 0,
|
|
||||||
"_showProbe": true,
|
|
||||||
"_showWireframe": true,
|
|
||||||
"_showConvex": false,
|
|
||||||
"_data": null,
|
|
||||||
"_lightProbeSphereVolume": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.PostSettingsInfo",
|
|
||||||
"_toneMappingType": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"ver": "1.1.50",
|
|
||||||
"importer": "scene",
|
|
||||||
"imported": true,
|
|
||||||
"uuid": "9490c809-bcb7-4a9e-af1f-acd680227bc4",
|
|
||||||
"files": [
|
|
||||||
".json"
|
|
||||||
],
|
|
||||||
"subMetas": {},
|
|
||||||
"userData": {}
|
|
||||||
}
|
|
||||||
@@ -395,12 +395,13 @@
|
|||||||
},
|
},
|
||||||
"_enabled": true,
|
"_enabled": true,
|
||||||
"__prefab": null,
|
"__prefab": null,
|
||||||
|
"gameKey": "erqiwang",
|
||||||
"createRoom": {
|
"createRoom": {
|
||||||
"__uuid__": "584dbb85-4acc-4bea-9d9b-e0cbeb8741da",
|
"__uuid__": "c1608cf0-5b48-4714-8a06-9363c854ab71",
|
||||||
"__expectedType__": "cc.Prefab"
|
"__expectedType__": "cc.Prefab"
|
||||||
},
|
},
|
||||||
"room": {
|
"room": {
|
||||||
"__uuid__": "f4582832-23e2-4981-be26-08dfe832aa96",
|
"__uuid__": "28fcf5a7-d779-4400-9c71-300cf492bcc7",
|
||||||
"__expectedType__": "cc.Prefab"
|
"__expectedType__": "cc.Prefab"
|
||||||
},
|
},
|
||||||
"roomScene": {
|
"roomScene": {
|
||||||
|
|||||||
@@ -1,449 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"__type__": "cc.SceneAsset",
|
|
||||||
"_name": "scene-2d",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_native": "",
|
|
||||||
"scene": {
|
|
||||||
"__id__": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Scene",
|
|
||||||
"_name": "scene-2d",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_parent": null,
|
|
||||||
"_children": [
|
|
||||||
{
|
|
||||||
"__id__": 2
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_active": true,
|
|
||||||
"_components": [],
|
|
||||||
"_prefab": null,
|
|
||||||
"_lpos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_lrot": {
|
|
||||||
"__type__": "cc.Quat",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_lscale": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1,
|
|
||||||
"y": 1,
|
|
||||||
"z": 1
|
|
||||||
},
|
|
||||||
"_mobility": 0,
|
|
||||||
"_layer": 1073741824,
|
|
||||||
"_euler": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"autoReleaseAssets": false,
|
|
||||||
"_globals": {
|
|
||||||
"__id__": 8
|
|
||||||
},
|
|
||||||
"_id": "aa6aad6d-aef0-4b69-95a0-18ffda41f4c7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Node",
|
|
||||||
"_name": "Canvas",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_parent": {
|
|
||||||
"__id__": 1
|
|
||||||
},
|
|
||||||
"_children": [
|
|
||||||
{
|
|
||||||
"__id__": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_active": true,
|
|
||||||
"_components": [
|
|
||||||
{
|
|
||||||
"__id__": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__id__": 7
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_prefab": null,
|
|
||||||
"_lpos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 800,
|
|
||||||
"y": 360.00000000000006,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_lrot": {
|
|
||||||
"__type__": "cc.Quat",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_lscale": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1,
|
|
||||||
"y": 1,
|
|
||||||
"z": 1
|
|
||||||
},
|
|
||||||
"_mobility": 0,
|
|
||||||
"_layer": 33554432,
|
|
||||||
"_euler": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_id": "beI88Z2HpFELqR4T5EMHpg"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Node",
|
|
||||||
"_name": "Camera",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"_parent": {
|
|
||||||
"__id__": 2
|
|
||||||
},
|
|
||||||
"_children": [],
|
|
||||||
"_active": true,
|
|
||||||
"_components": [
|
|
||||||
{
|
|
||||||
"__id__": 4
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"_prefab": null,
|
|
||||||
"_lpos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 1000
|
|
||||||
},
|
|
||||||
"_lrot": {
|
|
||||||
"__type__": "cc.Quat",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_lscale": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1,
|
|
||||||
"y": 1,
|
|
||||||
"z": 1
|
|
||||||
},
|
|
||||||
"_mobility": 0,
|
|
||||||
"_layer": 1073741824,
|
|
||||||
"_euler": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_id": "ebFwiq8gBFaYpqYbdoDODe"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Camera",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 3
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_projection": 0,
|
|
||||||
"_priority": 0,
|
|
||||||
"_fov": 45,
|
|
||||||
"_fovAxis": 0,
|
|
||||||
"_orthoHeight": 360,
|
|
||||||
"_near": 0,
|
|
||||||
"_far": 2000,
|
|
||||||
"_color": {
|
|
||||||
"__type__": "cc.Color",
|
|
||||||
"r": 0,
|
|
||||||
"g": 0,
|
|
||||||
"b": 0,
|
|
||||||
"a": 255
|
|
||||||
},
|
|
||||||
"_depth": 1,
|
|
||||||
"_stencil": 0,
|
|
||||||
"_clearFlags": 7,
|
|
||||||
"_rect": {
|
|
||||||
"__type__": "cc.Rect",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 1,
|
|
||||||
"height": 1
|
|
||||||
},
|
|
||||||
"_aperture": 19,
|
|
||||||
"_shutter": 7,
|
|
||||||
"_iso": 0,
|
|
||||||
"_screenScale": 1,
|
|
||||||
"_visibility": 1108344832,
|
|
||||||
"_targetTexture": null,
|
|
||||||
"_postProcess": null,
|
|
||||||
"_usePostProcess": false,
|
|
||||||
"_cameraType": -1,
|
|
||||||
"_trackingType": 0,
|
|
||||||
"_id": "63WIch3o5BEYRlXzTT0oWc"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.UITransform",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 2
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_contentSize": {
|
|
||||||
"__type__": "cc.Size",
|
|
||||||
"width": 1600,
|
|
||||||
"height": 720
|
|
||||||
},
|
|
||||||
"_anchorPoint": {
|
|
||||||
"__type__": "cc.Vec2",
|
|
||||||
"x": 0.5,
|
|
||||||
"y": 0.5
|
|
||||||
},
|
|
||||||
"_id": "d6rUX5yfhMlKoWX2bSbawx"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Canvas",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 2
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_cameraComponent": {
|
|
||||||
"__id__": 4
|
|
||||||
},
|
|
||||||
"_alignCanvasWithScreen": true,
|
|
||||||
"_id": "12O/ljcVlEqLmVm3U2gEOQ"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.Widget",
|
|
||||||
"_name": "",
|
|
||||||
"_objFlags": 0,
|
|
||||||
"__editorExtras__": {},
|
|
||||||
"node": {
|
|
||||||
"__id__": 2
|
|
||||||
},
|
|
||||||
"_enabled": true,
|
|
||||||
"__prefab": null,
|
|
||||||
"_alignFlags": 45,
|
|
||||||
"_target": null,
|
|
||||||
"_left": 0,
|
|
||||||
"_right": 0,
|
|
||||||
"_top": 5.684341886080802e-14,
|
|
||||||
"_bottom": 5.684341886080802e-14,
|
|
||||||
"_horizontalCenter": 0,
|
|
||||||
"_verticalCenter": 0,
|
|
||||||
"_isAbsLeft": true,
|
|
||||||
"_isAbsRight": true,
|
|
||||||
"_isAbsTop": true,
|
|
||||||
"_isAbsBottom": true,
|
|
||||||
"_isAbsHorizontalCenter": true,
|
|
||||||
"_isAbsVerticalCenter": true,
|
|
||||||
"_originalWidth": 0,
|
|
||||||
"_originalHeight": 0,
|
|
||||||
"_alignMode": 2,
|
|
||||||
"_lockFlags": 0,
|
|
||||||
"_id": "c5V1EV8IpMtrIvY1OE9t2u"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.SceneGlobals",
|
|
||||||
"ambient": {
|
|
||||||
"__id__": 9
|
|
||||||
},
|
|
||||||
"shadows": {
|
|
||||||
"__id__": 10
|
|
||||||
},
|
|
||||||
"_skybox": {
|
|
||||||
"__id__": 11
|
|
||||||
},
|
|
||||||
"fog": {
|
|
||||||
"__id__": 12
|
|
||||||
},
|
|
||||||
"octree": {
|
|
||||||
"__id__": 13
|
|
||||||
},
|
|
||||||
"skin": {
|
|
||||||
"__id__": 14
|
|
||||||
},
|
|
||||||
"lightProbeInfo": {
|
|
||||||
"__id__": 15
|
|
||||||
},
|
|
||||||
"postSettings": {
|
|
||||||
"__id__": 16
|
|
||||||
},
|
|
||||||
"bakedWithStationaryMainLight": false,
|
|
||||||
"bakedWithHighpLightmap": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.AmbientInfo",
|
|
||||||
"_skyColorHDR": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 0.520833125
|
|
||||||
},
|
|
||||||
"_skyColor": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 0.520833125
|
|
||||||
},
|
|
||||||
"_skyIllumHDR": 20000,
|
|
||||||
"_skyIllum": 20000,
|
|
||||||
"_groundAlbedoHDR": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 0
|
|
||||||
},
|
|
||||||
"_groundAlbedo": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"z": 0,
|
|
||||||
"w": 0
|
|
||||||
},
|
|
||||||
"_skyColorLDR": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0.2,
|
|
||||||
"y": 0.5,
|
|
||||||
"z": 0.8,
|
|
||||||
"w": 1
|
|
||||||
},
|
|
||||||
"_skyIllumLDR": 20000,
|
|
||||||
"_groundAlbedoLDR": {
|
|
||||||
"__type__": "cc.Vec4",
|
|
||||||
"x": 0.2,
|
|
||||||
"y": 0.2,
|
|
||||||
"z": 0.2,
|
|
||||||
"w": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.ShadowsInfo",
|
|
||||||
"_enabled": false,
|
|
||||||
"_type": 0,
|
|
||||||
"_normal": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 0,
|
|
||||||
"y": 1,
|
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"_distance": 0,
|
|
||||||
"_planeBias": 1,
|
|
||||||
"_shadowColor": {
|
|
||||||
"__type__": "cc.Color",
|
|
||||||
"r": 76,
|
|
||||||
"g": 76,
|
|
||||||
"b": 76,
|
|
||||||
"a": 255
|
|
||||||
},
|
|
||||||
"_maxReceived": 4,
|
|
||||||
"_size": {
|
|
||||||
"__type__": "cc.Vec2",
|
|
||||||
"x": 512,
|
|
||||||
"y": 512
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.SkyboxInfo",
|
|
||||||
"_envLightingType": 0,
|
|
||||||
"_envmapHDR": null,
|
|
||||||
"_envmap": null,
|
|
||||||
"_envmapLDR": null,
|
|
||||||
"_diffuseMapHDR": null,
|
|
||||||
"_diffuseMapLDR": null,
|
|
||||||
"_enabled": false,
|
|
||||||
"_useHDR": true,
|
|
||||||
"_editableMaterial": null,
|
|
||||||
"_reflectionHDR": null,
|
|
||||||
"_reflectionLDR": null,
|
|
||||||
"_rotationAngle": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.FogInfo",
|
|
||||||
"_type": 0,
|
|
||||||
"_fogColor": {
|
|
||||||
"__type__": "cc.Color",
|
|
||||||
"r": 200,
|
|
||||||
"g": 200,
|
|
||||||
"b": 200,
|
|
||||||
"a": 255
|
|
||||||
},
|
|
||||||
"_enabled": false,
|
|
||||||
"_fogDensity": 0.3,
|
|
||||||
"_fogStart": 0.5,
|
|
||||||
"_fogEnd": 300,
|
|
||||||
"_fogAtten": 5,
|
|
||||||
"_fogTop": 1.5,
|
|
||||||
"_fogRange": 1.2,
|
|
||||||
"_accurate": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.OctreeInfo",
|
|
||||||
"_enabled": false,
|
|
||||||
"_minPos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": -1024,
|
|
||||||
"y": -1024,
|
|
||||||
"z": -1024
|
|
||||||
},
|
|
||||||
"_maxPos": {
|
|
||||||
"__type__": "cc.Vec3",
|
|
||||||
"x": 1024,
|
|
||||||
"y": 1024,
|
|
||||||
"z": 1024
|
|
||||||
},
|
|
||||||
"_depth": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.SkinInfo",
|
|
||||||
"_enabled": false,
|
|
||||||
"_blurRadius": 0.01,
|
|
||||||
"_sssIntensity": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.LightProbeInfo",
|
|
||||||
"_giScale": 1,
|
|
||||||
"_giSamples": 1024,
|
|
||||||
"_bounces": 2,
|
|
||||||
"_reduceRinging": 0,
|
|
||||||
"_showProbe": true,
|
|
||||||
"_showWireframe": true,
|
|
||||||
"_showConvex": false,
|
|
||||||
"_data": null,
|
|
||||||
"_lightProbeSphereVolume": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"__type__": "cc.PostSettingsInfo",
|
|
||||||
"_toneMappingType": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"ver": "1.1.50",
|
|
||||||
"importer": "scene",
|
|
||||||
"imported": true,
|
|
||||||
"uuid": "aa6aad6d-aef0-4b69-95a0-18ffda41f4c7",
|
|
||||||
"files": [
|
|
||||||
".json"
|
|
||||||
],
|
|
||||||
"subMetas": {},
|
|
||||||
"userData": {}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import {createErqiwangGame} from '../../games/erqiwang/erqiwang-game.ts';
|
||||||
|
import {ErqiwangRoomView} from '../../games/erqiwang/ErqiwangRoomView.ts';
|
||||||
import { _decorator, assetManager, Component, Director, Label, Node, Prefab, ProgressBar, SceneAsset,
|
import { _decorator, assetManager, Component, Director, Label, Node, Prefab, ProgressBar, SceneAsset,
|
||||||
UITransform, Widget, director, instantiate, isValid } from 'cc';
|
UITransform, Widget, director, instantiate, isValid } from 'cc';
|
||||||
import { resolveRuntimeConfig, type RuntimeConfig } from '../../framework/config/runtime-config.ts';
|
import { resolveRuntimeConfig, type RuntimeConfig } from '../../framework/config/runtime-config.ts';
|
||||||
@@ -150,7 +152,9 @@ export class PlatformStartup extends Component {
|
|||||||
/** 退出只重建账号会话;配置、原生桥和已加载资源由常驻组件保留。 */
|
/** 退出只重建账号会话;配置、原生桥和已加载资源由常驻组件保留。 */
|
||||||
private async startSession(firstStart:boolean):Promise<void>{
|
private async startSession(firstStart:boolean):Promise<void>{
|
||||||
const identity=required(this.config,'config').identity;
|
const identity=required(this.config,'config').identity;
|
||||||
this.game=createTemplateGame(identity.gameid);
|
const gameKey=required(this.getComponent(SubgameAssets),'SubgameAssets').gameKey;
|
||||||
|
if(gameKey!=='erqiwang'&&gameKey!=='Game_Surface_3')throw Error('Unsupported subgame: '+gameKey);
|
||||||
|
this.game=gameKey==='erqiwang'?createErqiwangGame(identity.gameid):createTemplateGame(identity.gameid);
|
||||||
this.runtime=new PlatformRuntime({gameEntry:this.game.entry,
|
this.runtime=new PlatformRuntime({gameEntry:this.game.entry,
|
||||||
roomHistory:new OwnedRoomHistory(window.localStorage,identity.gameid,identity.agentid),
|
roomHistory:new OwnedRoomHistory(window.localStorage,identity.gameid,identity.agentid),
|
||||||
resolveRuntimeConfig:async()=>required(this.config,'config'),
|
resolveRuntimeConfig:async()=>required(this.config,'config'),
|
||||||
@@ -359,7 +363,7 @@ export class PlatformStartup extends Component {
|
|||||||
await this.flow.enter(required(assets.roomScene,'subgame room scene').name,()=>{
|
await this.flow.enter(required(assets.roomScene,'subgame room scene').name,()=>{
|
||||||
if(required(this.runtime,'runtime').state.room.kind!=='inside')return;
|
if(required(this.runtime,'runtime').state.room.kind!=='inside')return;
|
||||||
const root=instantiate(required(assets.room,'subgame room prefab'));root.parent=this.canvas();root.setPosition(0,0,0);
|
const root=instantiate(required(assets.room,'subgame room prefab'));root.parent=this.canvas();root.setPosition(0,0,0);
|
||||||
const view=required(root.getComponent(TemplateRoomView),'TemplateRoomView');
|
const view=assets.gameKey==='erqiwang'?required(root.getComponent(ErqiwangRoomView),'ErqiwangRoomView'):required(root.getComponent(TemplateRoomView),'TemplateRoomView');
|
||||||
root.on('room-action-error',(error:unknown)=>this.tip(error instanceof Error?error.message:String(error)));
|
root.on('room-action-error',(error:unknown)=>this.tip(error instanceof Error?error.message:String(error)));
|
||||||
root.on('room-action-timeout',()=>this.tip('房间操作超时,请重试'));
|
root.on('room-action-timeout',()=>this.tip('房间操作超时,请重试'));
|
||||||
this.createStatus();required(this.game,'template game').mount(view);this.events.push({kind:'scene',data:'Room'});
|
this.createStatus();required(this.game,'template game').mount(view);this.events.push({kind:'scene',data:'Room'});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const {ccclass,property}=_decorator;
|
|||||||
/** App composition root: each game assigns its own pre-room page, room view and scene. */
|
/** App composition root: each game assigns its own pre-room page, room view and scene. */
|
||||||
@ccclass('SubgameAssets')
|
@ccclass('SubgameAssets')
|
||||||
export class SubgameAssets extends Component {
|
export class SubgameAssets extends Component {
|
||||||
|
@property gameKey:string='Game_Surface_3';
|
||||||
@property(Prefab) createRoom:Prefab|null=null;
|
@property(Prefab) createRoom:Prefab|null=null;
|
||||||
@property(Prefab) room:Prefab|null=null;
|
@property(Prefab) room:Prefab|null=null;
|
||||||
@property(SceneAsset) roomScene:SceneAsset|null=null;
|
@property(SceneAsset) roomScene:SceneAsset|null=null;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../../framework/sdk/contracts/roomtype.ts';
|
||||||
import {_decorator,Button,Component,instantiate,Label,Node,Prefab,ScrollView,Sprite,SpriteFrame,UITransform} from 'cc';
|
import {_decorator,Button,Component,instantiate,Label,Node,Prefab,ScrollView,Sprite,SpriteFrame,UITransform} from 'cc';
|
||||||
import type {VipCode,VipRoom} from '../../framework/core/types/vip-room.ts';
|
import type {VipCode,VipRoom} from '../../framework/core/types/vip-room.ts';
|
||||||
import {sameVipCode} from '../../framework/core/types/vip-room.ts';
|
import {sameVipCode} from '../../framework/core/types/vip-room.ts';
|
||||||
@@ -15,8 +16,8 @@ export class VipRoomListView extends Component {
|
|||||||
@property([SpriteFrame]) deskFrames:SpriteFrame[]=[];
|
@property([SpriteFrame]) deskFrames:SpriteFrame[]=[];
|
||||||
private rooms:readonly VipRoom[]=[];
|
private rooms:readonly VipRoom[]=[];
|
||||||
private selected:VipCode|null=null;
|
private selected:VipCode|null=null;
|
||||||
private describe:(roomtype:readonly unknown[])=>string=()=>{throw Error('VIP room description provider is not configured');};
|
private describe:(roomtype: Roomtype)=>string=()=>{throw Error('VIP room description provider is not configured');};
|
||||||
configure(describe:(roomtype:readonly unknown[])=>string):void {this.describe=describe;this.showRooms();}
|
configure(describe:(roomtype: Roomtype)=>string):void {this.describe=describe;this.showRooms();}
|
||||||
get selectedCode():VipCode|null {return this.selected;}
|
get selectedCode():VipCode|null {return this.selected;}
|
||||||
render(rooms:readonly VipRoom[],codes:readonly VipCode[]):void {
|
render(rooms:readonly VipRoom[],codes:readonly VipCode[]):void {
|
||||||
this.rooms=orderedVipRooms(rooms,codes);
|
this.rooms=orderedVipRooms(rooms,codes);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type {Roomtype} from '../../framework/sdk/contracts/roomtype.ts';
|
||||||
import { assetManager, BlockInputEvents, Button, EditBox, ImageAsset, Label, Mask, Node, Prefab, ScrollView, Sprite, SpriteFrame, Texture2D, UITransform, Widget, instantiate, isValid } from 'cc';
|
import { assetManager, BlockInputEvents, Button, EditBox, ImageAsset, Label, Mask, Node, Prefab, ScrollView, Sprite, SpriteFrame, Texture2D, UITransform, Widget, instantiate, isValid } from 'cc';
|
||||||
import type { RuntimeConfig } from '../../framework/config/runtime-config.ts';
|
import type { RuntimeConfig } from '../../framework/config/runtime-config.ts';
|
||||||
import { selectLobbyModel, shouldShowNotice, type LobbyModel, type LobbyPolicy } from '../../framework/presentation/lobby-model.ts';
|
import { selectLobbyModel, shouldShowNotice, type LobbyModel, type LobbyPolicy } from '../../framework/presentation/lobby-model.ts';
|
||||||
@@ -67,10 +68,10 @@ export class LobbyPanel {
|
|||||||
private readonly onAction:(action:LobbyAction)=>void,
|
private readonly onAction:(action:LobbyAction)=>void,
|
||||||
private readonly claimTask:(taskid:number|string)=>void,
|
private readonly claimTask:(taskid:number|string)=>void,
|
||||||
private readonly nativeCall:(name:string,data:Record<string,unknown>)=>void,
|
private readonly nativeCall:(name:string,data:Record<string,unknown>)=>void,
|
||||||
private readonly vip?:{request:(codes:readonly VipCode[])=>void;join:(code:VipCode)=>void;describe:(roomtype:readonly unknown[])=>string},
|
private readonly vip?:{request:(codes:readonly VipCode[])=>void;join:(code:VipCode)=>void;describe:(roomtype: Roomtype)=>string},
|
||||||
private readonly invite?:{query:()=>void;bind:(code:string)=>void;paste:()=>Promise<string>},
|
private readonly invite?:{query:()=>void;bind:(code:string)=>void;paste:()=>Promise<string>},
|
||||||
private readonly extras?:{rank:()=>void;redeem:(cardno:string)=>void;paste:()=>Promise<string>;vipRank?:(limit:number)=>void;joinOwned?:(code:number)=>void;loading?:(show:boolean)=>void;
|
private readonly extras?:{rank:()=>void;redeem:(cardno:string)=>void;paste:()=>Promise<string>;vipRank?:(limit:number)=>void;joinOwned?:(code:number)=>void;loading?:(show:boolean)=>void;
|
||||||
room?:{createPrefab:Prefab;join(code:number):void;create(roomtype:readonly unknown[]):void;busy():boolean;close():void}}){
|
room?:{createPrefab:Prefab;join(code:number):void;create(roomtype: Roomtype):void;busy():boolean;close():void}}){
|
||||||
this.requestLoading=new RequestLoading(show=>need(this.extras?.loading,'request Loading UI')(show));
|
this.requestLoading=new RequestLoading(show=>need(this.extras?.loading,'request Loading UI')(show));
|
||||||
this.model=selectLobbyModel(state);
|
this.model=selectLobbyModel(state);
|
||||||
if(assets.switches.length!==2)throw Error('LobbyAssets requires 2 switch frames');
|
if(assets.switches.length!==2)throw Error('LobbyAssets requires 2 switch frames');
|
||||||
@@ -479,7 +480,7 @@ export class LobbyPanel {
|
|||||||
const text=window.localStorage.getItem('tsgame_roomtype_'+this.config.identity.gameid+this.config.identity.agentid);
|
const text=window.localStorage.getItem('tsgame_roomtype_'+this.config.identity.gameid+this.config.identity.agentid);
|
||||||
let previous:unknown=null;
|
let previous:unknown=null;
|
||||||
if(text!==null&&text!==''){
|
if(text!==null&&text!==''){
|
||||||
const saved=JSON.parse(text);if(!saved||!Array.isArray(saved.data))throw Error('Invalid saved roomtype');previous=saved.data;
|
const saved=JSON.parse(text);if(!saved||!(typeof saved.data==='string'||Array.isArray(saved.data)))throw Error('Invalid saved roomtype');previous=saved.data;
|
||||||
}
|
}
|
||||||
const current=()=>this.modal===modal&&this.roomPage===page&&this.model.canAct;
|
const current=()=>this.modal===modal&&this.roomPage===page&&this.model.canAct;
|
||||||
page.open({previousRoomtype:previous,submit:roomtype=>{if(current())commands.create(roomtype);},cancel:()=>{if(this.modal===modal)this.close();},reportError:text=>{if(current())this.tip(text);}});
|
page.open({previousRoomtype:previous,submit:roomtype=>{if(current())commands.create(roomtype);},cancel:()=>{if(this.modal===modal)this.close();},reportError:text=>{if(current())this.tip(text);}});
|
||||||
|
|||||||
@@ -7,5 +7,8 @@
|
|||||||
"fitWidth": true,
|
"fitWidth": true,
|
||||||
"fitHeight": true
|
"fitHeight": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"script": {
|
||||||
|
"loose": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
|
|||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import { readLayerXml, emitPrefabJson } from '../../scripts/legacy-layer-to-cocos-prefab.mjs';
|
import { readLayerXml, emitPrefabJson } from '../../scripts/legacy-layer-to-cocos-prefab.mjs';
|
||||||
import { ROOT, HOST_PROJECT } from '../../scripts/lib/paths.mjs';
|
import { ROOT } from '../../scripts/lib/paths.mjs';
|
||||||
|
|
||||||
// PoC 阶段 3 端到端: Layer00002.xml Login_Layer (18 spirits, group 2, 包含 Spirit405 渠道logo +
|
// PoC 阶段 3 端到端: Layer00002.xml Login_Layer (18 spirits, group 2, 包含 Spirit405 渠道logo +
|
||||||
// Spirit177 游客登录 anchor-test cases). 验证生成 prefab 与 fixtures/Login_Layer.prefab 在
|
// Spirit177 游客登录 anchor-test cases). 验证生成 prefab 与 fixtures/Login_Layer.prefab 在
|
||||||
@@ -19,7 +19,7 @@ import { ROOT, HOST_PROJECT } from '../../scripts/lib/paths.mjs';
|
|||||||
// ImgResID 427 的依赖. 这是 Task 11 fix round 1 的 spec intent: 验证 anchor 公式精度,
|
// ImgResID 427 的依赖. 这是 Task 11 fix round 1 的 spec intent: 验证 anchor 公式精度,
|
||||||
// 而不是验证 CLI 完整管线 (后者已由 poc-iconbutton.test.mjs / poc-protocol.test.mjs 覆盖).
|
// 而不是验证 CLI 完整管线 (后者已由 poc-iconbutton.test.mjs / poc-protocol.test.mjs 覆盖).
|
||||||
const FIXTURE_XML = join(ROOT, 'framework-tests', 'legacy-layer-migration', 'fixtures', 'Layer00002.xml');
|
const FIXTURE_XML = join(ROOT, 'framework-tests', 'legacy-layer-migration', 'fixtures', 'Layer00002.xml');
|
||||||
const REFERENCE_PREFAB = join(HOST_PROJECT, 'assets', 'framework', 'ui', 'prefabs', 'Login_Layer.prefab');
|
const REFERENCE_PREFAB = join(ROOT, 'framework-tests', 'legacy-layer-migration', 'fixtures', 'Login_Layer.prefab');
|
||||||
|
|
||||||
function buildFilteredLayer() {
|
function buildFilteredLayer() {
|
||||||
const layer = readLayerXml(FIXTURE_XML);
|
const layer = readLayerXml(FIXTURE_XML);
|
||||||
@@ -98,4 +98,4 @@ test('PoC 阶段 3 - 游客登录 _lpos 误差 < 0.001 (bypass CLI)', () => {
|
|||||||
|
|
||||||
assert.ok(Math.abs(genVisitor._lpos.x - expVisitor._lpos.x) < 0.001, `x mismatch: gen=${genVisitor._lpos.x} exp=${expVisitor._lpos.x}`);
|
assert.ok(Math.abs(genVisitor._lpos.x - expVisitor._lpos.x) < 0.001, `x mismatch: gen=${genVisitor._lpos.x} exp=${expVisitor._lpos.x}`);
|
||||||
assert.ok(Math.abs(genVisitor._lpos.y - expVisitor._lpos.y) < 0.001, `y mismatch: gen=${genVisitor._lpos.y} exp=${expVisitor._lpos.y}`);
|
assert.ok(Math.abs(genVisitor._lpos.y - expVisitor._lpos.y) < 0.001, `y mismatch: gen=${genVisitor._lpos.y} exp=${expVisitor._lpos.y}`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -824,6 +824,7 @@ test('canonical roomtype preserves sparse length, holes, and negative zero', ()
|
|||||||
|
|
||||||
assert.equal(state.room.kind, 'inside');
|
assert.equal(state.room.kind, 'inside');
|
||||||
if (state.room.kind !== 'inside') return;
|
if (state.room.kind !== 'inside') return;
|
||||||
|
assert.ok(Array.isArray(state.room.roomtype));
|
||||||
assert.equal(state.room.roomtype.length, 5);
|
assert.equal(state.room.roomtype.length, 5);
|
||||||
assert.equal(0 in state.room.roomtype, false);
|
assert.equal(0 in state.room.roomtype, false);
|
||||||
assert.equal(1 in state.room.roomtype, true);
|
assert.equal(1 in state.room.roomtype, true);
|
||||||
|
|||||||
@@ -604,7 +604,7 @@ for (const mutate of [
|
|||||||
setup.session.handleLogin(fixture('player-login-success.json'));
|
setup.session.handleLogin(fixture('player-login-success.json'));
|
||||||
const before = setup.store.getState();
|
const before = setup.store.getState();
|
||||||
const data = {state: 0, roomcode: '123456', seat: 0, roomtype: [1, {count: 4}]};
|
const data = {state: 0, roomcode: '123456', seat: 0, roomtype: [1, {count: 4}]};
|
||||||
setup.gameSession.entry.resolveSeatCount = roomtype => { mutate(roomtype); return 4; };
|
setup.gameSession.entry.resolveSeatCount = roomtype => { assert.ok(Array.isArray(roomtype)); mutate(roomtype); return 4; };
|
||||||
assert.throws(() => setup.session.handleCreateRoom(data), TypeError);
|
assert.throws(() => setup.session.handleCreateRoom(data), TypeError);
|
||||||
assert.deepEqual(data.roomtype, [1, {count: 4}]);
|
assert.deepEqual(data.roomtype, [1, {count: 4}]);
|
||||||
assert.equal(Object.isFrozen(data.roomtype), false);
|
assert.equal(Object.isFrozen(data.roomtype), false);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import {createErqiwangGame} from '../../YouleNexus/assets/games/erqiwang/erqiwang-game.ts';
|
||||||
import { STARTUP_CONFIG as EDITABLE_STARTUP_CONFIG } from '../../YouleNexus/assets/framework/config/profiles.ts';
|
import { STARTUP_CONFIG as EDITABLE_STARTUP_CONFIG } from '../../YouleNexus/assets/framework/config/profiles.ts';
|
||||||
// 固定测试来源,允许开发者独立切换项目的 local/remote 开关。
|
// 固定测试来源,允许开发者独立切换项目的 local/remote 开关。
|
||||||
const STARTUP_CONFIG = Object.freeze({...EDITABLE_STARTUP_CONFIG, configSource:'remote' as const});
|
const STARTUP_CONFIG = Object.freeze({...EDITABLE_STARTUP_CONFIG, configSource:'remote' as const});
|
||||||
@@ -736,7 +737,7 @@ test('a denied join retains the lobby root, reports the raw outcome and permits
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('runtime resolves seats only from the actual game-owned server roomtype at room entry', async () => {
|
test('runtime resolves seats only from the actual game-owned server roomtype at room entry', async () => {
|
||||||
const roomtypes: Array<readonly unknown[]> = [];
|
const roomtypes: Array<string | readonly unknown[]> = [];
|
||||||
const attached: GameHost[] = [];
|
const attached: GameHost[] = [];
|
||||||
const setup = makeRuntime(runtimeConfig(), makeGameEntry({
|
const setup = makeRuntime(runtimeConfig(), makeGameEntry({
|
||||||
resolveSeatCount(roomtype) {
|
resolveSeatCount(roomtype) {
|
||||||
@@ -795,7 +796,7 @@ for(const loginRoute of ['agent','room','platform'])test(`${loginRoute} login de
|
|||||||
const before = runtime.state;
|
const before = runtime.state;
|
||||||
runtime.login(ACCOUNT);
|
runtime.login(ACCOUNT);
|
||||||
const denial = { state: -1, msg: '短信验证码不正确', time: 0 };
|
const denial = { state: -1, msg: '短信验证码不正确', time: 0 };
|
||||||
assert.equal(wire.sent.at(-1)?.route,'agent','outbound login remains agent');
|
assert.equal(wire.sent[wire.sent.length - 1]?.route,'agent','outbound login remains agent');
|
||||||
wire.emit({ type: 'message', message: { route: loginRoute, rpc: 'player_login', data: denial } });
|
wire.emit({ type: 'message', message: { route: loginRoute, rpc: 'player_login', data: denial } });
|
||||||
|
|
||||||
assert.equal(runtime.state, before);
|
assert.equal(runtime.state, before);
|
||||||
@@ -1651,7 +1652,7 @@ test('kick_offline bypasses pending login and stops late navigation', async () =
|
|||||||
await runtime.start();wire.emit({type:'open',server:'ws://agent'});runtime.login(ACCOUNT);
|
await runtime.start();wire.emit({type:'open',server:'ws://agent'});runtime.login(ACCOUNT);
|
||||||
const data={fromOther:true,gameid:'another-game'};
|
const data={fromOther:true,gameid:'another-game'};
|
||||||
wire.emit({type:'message',message:{route:'agent',rpc:'kick_offline',data}});
|
wire.emit({type:'message',message:{route:'agent',rpc:'kick_offline',data}});
|
||||||
assert.equal(scene.calls.at(-1)?.name,'kicked');assert.equal(scene.calls.at(-1)?.value,data);
|
assert.equal(scene.calls[scene.calls.length - 1]?.name,'kicked');assert.equal(scene.calls[scene.calls.length - 1]?.value,data);
|
||||||
assert.equal(wire.stopCalls,1);
|
assert.equal(wire.stopCalls,1);
|
||||||
const count=scene.calls.length;wire.emit({type:'open',server:'ws://agent'});
|
const count=scene.calls.length;wire.emit({type:'open',server:'ws://agent'});
|
||||||
assert.equal(scene.calls.length,count);
|
assert.equal(scene.calls.length,count);
|
||||||
@@ -1663,7 +1664,7 @@ test('show_message preserves text and legacy numeric timeout without navigating'
|
|||||||
const before=runtime.state;
|
const before=runtime.state;
|
||||||
for(const time of ['3000','0','-1']){
|
for(const time of ['3000','0','-1']){
|
||||||
wire.emit({type:'message',message:{route:'agent',rpc:'show_message',data:{msg:'服务器提示#第二行',time}}});
|
wire.emit({type:'message',message:{route:'agent',rpc:'show_message',data:{msg:'服务器提示#第二行',time}}});
|
||||||
assert.deepEqual(scene.calls.at(-1),{name:'tips',value:{message:'服务器提示#第二行',time:Number(time)}});
|
assert.deepEqual(scene.calls[scene.calls.length - 1],{name:'tips',value:{message:'服务器提示#第二行',time:Number(time)}});
|
||||||
assert.equal(runtime.state,before);
|
assert.equal(runtime.state,before);
|
||||||
}
|
}
|
||||||
runtime.stop();
|
runtime.stop();
|
||||||
@@ -2394,3 +2395,18 @@ test('create wire outcome enters only on success and a repeated success leaves t
|
|||||||
if(runtime.state.room.kind==='inside')assert.equal(runtime.state.room.seatPlayerIds.length,10);
|
if(runtime.state.room.kind==='inside')assert.equal(runtime.state.room.seatPlayerIds.length,10);
|
||||||
runtime.stop();assert.equal(disposals,1);
|
runtime.stop();assert.equal(disposals,1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('erqiwang creation preserves wire string, three seats and room host exit',async()=>{
|
||||||
|
const config=runtimeConfig(),game=createErqiwangGame(config.identity.gameid);
|
||||||
|
const {runtime,wire,scene}=makeRuntime(config,game.entry);await runtime.start();
|
||||||
|
wire.emit({type:'open',server:'ws://agent'});runtime.login(ACCOUNT);
|
||||||
|
wire.emit({type:'message',message:{route:'agent',rpc:'player_login',data:fixture('player-login-success.json')}});
|
||||||
|
const roomtype='11011000000';runtime.createRoom({roomtype,location:null,ip:'127.0.0.1'});
|
||||||
|
assert.equal((wire.sent[wire.sent.length - 1]?.data as {roomtype:unknown}).roomtype,roomtype);
|
||||||
|
wire.emit({type:'message',message:{route:'agent',rpc:'create_room',data:{state:0,roomcode:'123456',seat:0,roomtype,needprepare:1}}});
|
||||||
|
assert.equal(runtime.state.room.kind,'inside');
|
||||||
|
if(runtime.state.room.kind==='inside'){assert.equal(runtime.state.room.roomtype,roomtype);assert.equal(runtime.state.room.seatPlayerIds.length,3);}
|
||||||
|
assert.equal(scene.calls.filter(x=>x.name==='room').length,1);
|
||||||
|
let rendered=false;game.mount({render(snapshot,actions){assert.equal(snapshot.room.roomtype,roomtype);rendered=true;actions.exit();},close(){}});
|
||||||
|
assert.ok(rendered);assert.equal(wire.sent[wire.sent.length - 1]?.rpc,'self_exit_room');runtime.stop();
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import {test} from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import {cloneAndFreezeRoomtype} from '../../YouleNexus/assets/framework/platform/stores/platform-store.ts';
|
||||||
|
import {parseCreateRoomResponse,parseRoomEntryFields} from '../../YouleNexus/assets/framework/protocol/contracts/room-contracts.ts';
|
||||||
|
import {ErqiwangRoomRules} from '../../YouleNexus/assets/games/erqiwang/erqiwang-room-rules.ts';
|
||||||
|
import {createRequire} from 'node:module';
|
||||||
|
const require=createRequire(import.meta.url);
|
||||||
|
const server=require('../../../server/games/erqiwang/class.config.js');
|
||||||
|
|
||||||
|
test('all 32 UI combinations match actual server config, round-trip and fees',()=>{
|
||||||
|
for(let mask=0;mask<32;mask++){
|
||||||
|
const r=new ErqiwangRoomRules();r.open(null);
|
||||||
|
for(let group=0;group<5;group++)r.select(group,(mask>>group)&1);
|
||||||
|
const code=r.build();assert.match(code,/^[01]{5}0{6}$/);
|
||||||
|
const cfg=server.parse(code);
|
||||||
|
assert.deepEqual([cfg.aset12,cfg.deductAA,cfg.nocheck,cfg.bangwang,cfg.climb],r.selection.map(Boolean));
|
||||||
|
const copy=new ErqiwangRoomRules();copy.open(code);assert.deepEqual(copy.selection,r.selection);
|
||||||
|
assert.equal(r.roomCards,(cfg.aset12?2:1)*(cfg.deductAA?1:2));
|
||||||
|
assert.equal(r.seatCount(code),3);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
test('required groups have defaults and malformed saved configuration is rejected',()=>{
|
||||||
|
const r=new ErqiwangRoomRules();r.open(null);assert.equal(r.build(),'00000000000');
|
||||||
|
for(const invalid of ['00000','00000000001','2'.repeat(11),[],{},123])assert.throws(()=>r.open(invalid));
|
||||||
|
assert.throws(()=>r.select(5,0));assert.throws(()=>r.select(0,2));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('platform preserves erqiwang string through canonical state and entry responses',()=>{
|
||||||
|
const code='10100000000';
|
||||||
|
assert.equal(cloneAndFreezeRoomtype(code as never),code);
|
||||||
|
assert.equal(parseCreateRoomResponse({state:0,roomcode:'123456',seat:0,roomtype:code}).room?.roomtype,code);
|
||||||
|
assert.equal(parseRoomEntryFields({roomcode:'123456',seat:0,roomtype:code,players:[{},null,null]}).roomtype,code);
|
||||||
|
const array=[1,[2]];const copied=cloneAndFreezeRoomtype(array);
|
||||||
|
assert.deepEqual(copied,array);assert.notEqual(copied,array);
|
||||||
|
assert.ok(Object.isFrozen(copied));
|
||||||
|
});
|
||||||
@@ -11,5 +11,5 @@ test('template module attaches only when opened and releases its view and subscr
|
|||||||
let actions:any;game.mount({render:(s,a)=>{views.push(s);actions=a;},close:()=>views.push('closed')});
|
let actions:any;game.mount({render:(s,a)=>{views.push(s);actions=a;},close:()=>views.push('closed')});
|
||||||
actions.exit();actions.prepare();assert.deepEqual(commands,[{type:'room.exit'},{type:'room.prepare'}]);
|
actions.exit();actions.prepare();assert.deepEqual(commands,[{type:'room.exit'},{type:'room.prepare'}]);
|
||||||
const deskinfo={nested:[1,2]};module.restore(deskinfo);assert.equal(game.restoredSnapshot,deskinfo);
|
const deskinfo={nested:[1,2]};module.restore(deskinfo);assert.equal(game.restoredSnapshot,deskinfo);
|
||||||
module.dispose();assert.equal(unsubscribed,1);assert.equal(views.at(-1),'closed');assert.throws(()=>actions.exit());
|
module.dispose();assert.equal(unsubscribed,1);assert.equal(views[views.length - 1],'closed');assert.throws(()=>actions.exit());
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# 二七王创建房间接入
|
||||||
|
|
||||||
|
核对日期:2026-09-07。本篇记录创建房间阶段的实际实现,不代表二七王牌桌玩法已迁移完成。
|
||||||
|
|
||||||
|
## 资源与入口
|
||||||
|
|
||||||
|
工程为 `cocoscreator_projects/YouleNexus`。`PlatformStartup.scene` 的 `PlatformServices / SubgameAssets` 已配置:
|
||||||
|
|
||||||
|
- `gameKey = erqiwang`。
|
||||||
|
- `createRoom`:`assets/games/erqiwang/ErqiwangCreateRoom.prefab`。
|
||||||
|
- `room`:`assets/games/erqiwang/ErqiwangRoom.prefab`。
|
||||||
|
- `roomScene`:沿用 `assets/scenes/TemplateRoom.scene` 的通用场景容器。
|
||||||
|
|
||||||
|
联调 gameid 按用户确认沿用默认 `J9r4022t80pxlb01zOK76DN1WD4QewFl`,身份仍由运行配置提供,不在创建页重复定义。
|
||||||
|
|
||||||
|
## 页面与规则
|
||||||
|
|
||||||
|
`ErqiwangCreateRoomView` 继承平台 `CreateRoomPage`,只通过上下文提交、取消和报告错误。平台统一处理登录身份、IP、定位、请求信封、等待、超时和回包。
|
||||||
|
|
||||||
|
Inspector 绑定三组 `ToggleContainer`,`allowSwitchOff=false`;八个 Toggle 依次为 6 局、12 局、房主扣卡、AA 每人扣卡、可查牌、不查牌、傍王、爬坡。最后两个 Toggle 没有 ToggleContainer,可以独立勾选或取消。费用由局数与扣卡方式联动计算。
|
||||||
|
|
||||||
|
规则模型 `erqiwang-room-rules.ts` 是前端选项与编码转换的唯一来源。界面顺序为局数、扣卡、查牌、傍王、爬坡;实际服务器编码顺序仍为局数、扣卡、傍王、爬坡、查牌。尾部六位填零,总长度十一位。默认 `00000000000`。协议依据见 [服务端协议 §0.5](../../../../server/games/erqiwang/docs/protocol/packet_protocol.md#05-roomtype-房间选项位串),不能按界面顺序直接发包。
|
||||||
|
|
||||||
|
模型拒绝错误长度、非二进制选项、非零预留位以及数组型历史配置;历史来自平台成功回包保存的 `tsgame_roomtype_ + gameid + agentid`,格式仍为 JSON `{data: roomtype}`。没有历史时使用规则来源定义的默认选择,不静默修补非法历史。
|
||||||
|
|
||||||
|
## 平台契约与房间交接
|
||||||
|
|
||||||
|
公共 SDK 的 `Roomtype = string | readonly unknown[]` 用于创建页面、请求、成功响应、状态、GameEntry、GameHost 快照及事件。字符串保持原值,数组仍复制并冻结;平台不解释二七王位含义。VIP 房间配置同样保留字符串。
|
||||||
|
|
||||||
|
创建成功后,`createErqiwangGame` 校验配置并提供三个服务器座位,平台维护权威状态,临时房间页显示房号、玩家以及“玩法尚未接入”。退出使用本房间 GameHost。准备按钮暂不展示,避免进入尚未迁移的牌桌流程。玩法消息处理未实现,收到会显式报错;deskinfo 仅保留原值,尚无玩法恢复表现。
|
||||||
|
|
||||||
|
## 验证与限制
|
||||||
|
|
||||||
|
- `framework-tests/presentation/erqiwang-room-entry.test.ts`:穷举 32 种选项组合,对照实际服务端 `class.config.js` 验证编码、恢复、费用和人数。
|
||||||
|
- `framework-tests/platform/runtime.test.ts`:模拟登录、创建出站包、成功回包、三座位状态、房间显示与退出命令。
|
||||||
|
- 相关回归测试 157 项通过;Cocos 工程与框架 TypeScript 检查、导入边界检查通过。
|
||||||
|
- Game View 实际坐标点击验证 11 项:必选互斥、费用、独立开关、精确编码、busy、防重复、关闭清理及历史恢复。新 prefab 共 52 处 UUID 引用有效。
|
||||||
|
|
||||||
|
本次未修改服务器代码,未在真实服务器创建房间。本地模拟通过不等于实际服务端创建成功;后续联调从大厅“创建房间”入口进行,并检查出站 roomtype 类型与值。
|
||||||
Reference in New Issue
Block a user