Commit e6e7bab4 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/service/shuffle_hand' into 'main'

Feat/service/shuffle hand

See merge request !76
parents ddd5f1ac c7f3bbcf
Pipeline #19528 passed with stages
in 5 minutes and 15 seconds
neos-protobuf @ 9b1e1b0f
Subproject commit 707b028ef6ecbe6de328f9e1114707553e0f3df2
Subproject commit 9b1e1b0fdb8982b80c535178f44981cb17206866
......@@ -4857,7 +4857,9 @@ export namespace ygopro {
}
}
export class StocGameMessage extends pb_1.Message {
#one_of_decls: number[][] = [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]];
#one_of_decls: number[][] = [
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
];
constructor(
data?:
| any[]
......@@ -4876,6 +4878,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -4891,6 +4894,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -4906,6 +4910,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -4921,6 +4926,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -4936,6 +4942,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -4951,6 +4958,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -4966,6 +4974,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -4981,6 +4990,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -4996,6 +5006,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -5011,6 +5022,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -5026,6 +5038,7 @@ export namespace ygopro {
select_effect_yn?: StocGameMessage.MsgSelectEffectYn;
select_position?: never;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -5041,6 +5054,7 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: StocGameMessage.MsgSelectPosition;
select_option?: never;
shuffle_hand?: never;
}
| {
start?: never;
......@@ -5056,6 +5070,23 @@ export namespace ygopro {
select_effect_yn?: never;
select_position?: never;
select_option?: StocGameMessage.MsgSelectOption;
shuffle_hand?: never;
}
| {
start?: never;
draw?: never;
new_turn?: never;
new_phase?: never;
hint?: never;
select_idle_cmd?: never;
select_place?: never;
move?: never;
select_card?: never;
select_chain?: never;
select_effect_yn?: never;
select_position?: never;
select_option?: never;
shuffle_hand?: StocGameMessage.MsgShuffleHand;
}
))
) {
......@@ -5108,6 +5139,9 @@ export namespace ygopro {
if ("select_option" in data && data.select_option != undefined) {
this.select_option = data.select_option;
}
if ("shuffle_hand" in data && data.shuffle_hand != undefined) {
this.shuffle_hand = data.shuffle_hand;
}
}
}
get start() {
......@@ -5279,6 +5313,19 @@ export namespace ygopro {
get has_select_option() {
return pb_1.Message.getField(this, 13) != null;
}
get shuffle_hand() {
return pb_1.Message.getWrapperField(
this,
StocGameMessage.MsgShuffleHand,
14
) as StocGameMessage.MsgShuffleHand;
}
set shuffle_hand(value: StocGameMessage.MsgShuffleHand) {
pb_1.Message.setOneofWrapperField(this, 14, this.#one_of_decls[0], value);
}
get has_shuffle_hand() {
return pb_1.Message.getField(this, 14) != null;
}
get gameMsg() {
const cases: {
[index: number]:
......@@ -5295,7 +5342,8 @@ export namespace ygopro {
| "select_chain"
| "select_effect_yn"
| "select_position"
| "select_option";
| "select_option"
| "shuffle_hand";
} = {
0: "none",
1: "start",
......@@ -5311,11 +5359,12 @@ export namespace ygopro {
11: "select_effect_yn",
12: "select_position",
13: "select_option",
14: "shuffle_hand",
};
return cases[
pb_1.Message.computeOneofCase(
this,
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
)
];
}
......@@ -5351,6 +5400,9 @@ export namespace ygopro {
select_option?: ReturnType<
typeof StocGameMessage.MsgSelectOption.prototype.toObject
>;
shuffle_hand?: ReturnType<
typeof StocGameMessage.MsgShuffleHand.prototype.toObject
>;
}): StocGameMessage {
const message = new StocGameMessage({});
if (data.start != null) {
......@@ -5408,6 +5460,11 @@ export namespace ygopro {
data.select_option
);
}
if (data.shuffle_hand != null) {
message.shuffle_hand = StocGameMessage.MsgShuffleHand.fromObject(
data.shuffle_hand
);
}
return message;
}
toObject() {
......@@ -5443,6 +5500,9 @@ export namespace ygopro {
select_option?: ReturnType<
typeof StocGameMessage.MsgSelectOption.prototype.toObject
>;
shuffle_hand?: ReturnType<
typeof StocGameMessage.MsgShuffleHand.prototype.toObject
>;
} = {};
if (this.start != null) {
data.start = this.start.toObject();
......@@ -5483,6 +5543,9 @@ export namespace ygopro {
if (this.select_option != null) {
data.select_option = this.select_option.toObject();
}
if (this.shuffle_hand != null) {
data.shuffle_hand = this.shuffle_hand.toObject();
}
return data;
}
serialize(): Uint8Array;
......@@ -5533,6 +5596,10 @@ export namespace ygopro {
writer.writeMessage(13, this.select_option, () =>
this.select_option.serialize(writer)
);
if (this.has_shuffle_hand)
writer.writeMessage(14, this.shuffle_hand, () =>
this.shuffle_hand.serialize(writer)
);
if (!w) return writer.getResultBuffer();
}
static deserialize(bytes: Uint8Array | pb_1.BinaryReader): StocGameMessage {
......@@ -5641,6 +5708,14 @@ export namespace ygopro {
StocGameMessage.MsgSelectOption.deserialize(reader))
);
break;
case 14:
reader.readMessage(
message.shuffle_hand,
() =>
(message.shuffle_hand =
StocGameMessage.MsgShuffleHand.deserialize(reader))
);
break;
default:
reader.skipField();
}
......@@ -8665,5 +8740,109 @@ export namespace ygopro {
}
}
}
export class MsgShuffleHand extends pb_1.Message {
#one_of_decls: number[][] = [];
constructor(
data?:
| any[]
| {
player?: number;
hands?: number[];
}
) {
super();
pb_1.Message.initialize(
this,
Array.isArray(data) ? data : [],
0,
-1,
[2],
this.#one_of_decls
);
if (!Array.isArray(data) && typeof data == "object") {
if ("player" in data && data.player != undefined) {
this.player = data.player;
}
if ("hands" in data && data.hands != undefined) {
this.hands = data.hands;
}
}
}
get player() {
return pb_1.Message.getFieldWithDefault(this, 1, 0) as number;
}
set player(value: number) {
pb_1.Message.setField(this, 1, value);
}
get hands() {
return pb_1.Message.getFieldWithDefault(this, 2, []) as number[];
}
set hands(value: number[]) {
pb_1.Message.setField(this, 2, value);
}
static fromObject(data: {
player?: number;
hands?: number[];
}): MsgShuffleHand {
const message = new MsgShuffleHand({});
if (data.player != null) {
message.player = data.player;
}
if (data.hands != null) {
message.hands = data.hands;
}
return message;
}
toObject() {
const data: {
player?: number;
hands?: number[];
} = {};
if (this.player != null) {
data.player = this.player;
}
if (this.hands != null) {
data.hands = this.hands;
}
return data;
}
serialize(): Uint8Array;
serialize(w: pb_1.BinaryWriter): void;
serialize(w?: pb_1.BinaryWriter): Uint8Array | void {
const writer = w || new pb_1.BinaryWriter();
if (this.player != 0) writer.writeInt32(1, this.player);
if (this.hands.length) writer.writePackedInt32(2, this.hands);
if (!w) return writer.getResultBuffer();
}
static deserialize(
bytes: Uint8Array | pb_1.BinaryReader
): MsgShuffleHand {
const reader =
bytes instanceof pb_1.BinaryReader
? bytes
: new pb_1.BinaryReader(bytes),
message = new MsgShuffleHand();
while (reader.nextField()) {
if (reader.isEndGroup()) break;
switch (reader.getFieldNumber()) {
case 1:
message.player = reader.readInt32();
break;
case 2:
message.hands = reader.readPackedInt32();
break;
default:
reader.skipField();
}
}
return message;
}
serializeBinary(): Uint8Array {
return this.serialize();
}
static deserializeBinary(bytes: Uint8Array): MsgShuffleHand {
return MsgShuffleHand.deserialize(bytes);
}
}
}
}
......@@ -19,5 +19,19 @@
"fieldType": "uint8"
}
]
},
"33": {
"protoType": "shuffle_hand",
"fields": [
{
"fieldName": "player",
"fieldType": "uint8"
},
{
"fieldName": "hands",
"fieldType": "repeated",
"repeatedType": "uint32"
}
]
}
}
......@@ -13,7 +13,8 @@ const ReadFieldHandlerMap: Map<string, readFieldHandler> = new Map([
["CardLocation", (reader) => reader.readCardLocation()],
]);
const MsgConstructorMap: Map<string, Constructor> = new Map([
["move", ygopro.StocGameMessage.MsgMove],
["move", ygopro.StocGameMessage.MsgMove as Constructor],
["shuffle_hand", ygopro.StocGameMessage.MsgShuffleHand],
]);
export interface penetrateType {
......@@ -21,6 +22,7 @@ export interface penetrateType {
fields: {
fieldName: string;
fieldType: string;
repeatedType?: string;
}[];
}
......@@ -46,6 +48,22 @@ class PenetrateManager {
return undefined;
}
private readRepeatedField(reader: BufferReader, repeatedType: string): any {
const handler = this.readFieldHandlerMap.get(repeatedType);
if (handler) {
const count = reader.readUint8();
let repeated = [];
for (let i = 0; i < count; i++) {
repeated.push(handler(reader));
}
return repeated;
}
return undefined;
}
private constructMsg(protoType: string, object: any): any {
const constructor = this.msgConstructorMap.get(protoType);
......@@ -65,7 +83,10 @@ class PenetrateManager {
let object: any = {};
for (let field of fields) {
object[field.fieldName] = this.readField(reader, field.fieldType);
object[field.fieldName] =
field.fieldType === "repeated" && field.repeatedType
? this.readRepeatedField(reader, field.repeatedType)
: this.readField(reader, field.fieldType);
}
gameMsg[protoType] = this.constructMsg(protoType, object);
......
......@@ -80,6 +80,35 @@ export function createAsyncMetaThunk(name: string): AsyncThunk<
);
}
export function createAsyncRepeatedMetaThunk(
name: string
): AsyncThunk<
{ controler: number; metas: CardMeta[] },
{ controler: number; codes: number[] },
{}
> {
return createAsyncThunk(
name,
async (param: { controler: number; codes: number[] }) => {
const controler = param.controler;
const Ids = param.codes;
const metas = await Promise.all(
Ids.map(async (id) => {
if (id == 0) {
return { id, data: {}, text: {} };
} else {
return await fetchCard(id);
}
})
);
const response = { controler, metas };
return response;
}
);
}
export function extendState<T extends DuelFieldState>(
state: T | undefined,
newState: CardState
......@@ -180,3 +209,18 @@ export function insertCard<T extends DuelFieldState>(
state.inner.splice(sequence, 0, card);
}
}
export function updateCardMeta<T extends DuelFieldState>(
state: T | undefined,
metas: CardMeta[]
) {
if (state) {
state.inner.forEach((item) => {
metas.forEach((meta) => {
if (item.occupant?.id === meta.id) {
item.occupant = meta;
}
});
});
}
}
import {
createAsyncThunk,
ActionReducerMapBuilder,
CaseReducer,
PayloadAction,
} from "@reduxjs/toolkit";
import { DuelState } from "./mod";
import { RootState } from "../../store";
import { fetchCard, CardMeta } from "../../api/cards";
import { judgeSelf } from "./util";
import {
Interactivity,
......@@ -15,31 +13,16 @@ import {
createAsyncMetaThunk,
insertCard,
extendMeta,
createAsyncRepeatedMetaThunk,
updateCardMeta,
} from "./generic";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
export interface HandState extends DuelFieldState {}
// 增加手牌
export const fetchHandsMeta = createAsyncThunk(
"duel/fetchHandsMeta",
async (param: [number, number[]]) => {
const player = param[0];
const Ids = param[1];
const metas = await Promise.all(
Ids.map(async (id) => {
if (id === 0) {
return { id, data: {}, text: {} };
} else {
return await fetchCard(id);
}
})
);
const response: [number, CardMeta[]] = [player, metas];
return response;
}
export const fetchHandsMeta = createAsyncRepeatedMetaThunk(
"duel/fetchHandsMeta"
);
// 清空手牌互动性
......@@ -92,19 +75,22 @@ export const removeHandImpl: CaseReducer<
export const insertHandMeta = createAsyncMetaThunk("duel/insertHandMeta");
export const updateHandsMeta = createAsyncRepeatedMetaThunk(
"duel/updateHandsMeta"
);
export const handsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(fetchHandsMeta.pending, (state, action) => {
// Meta结果没返回之前先更新手牌`ID`
const player = action.meta.arg[0];
const ids = action.meta.arg[1];
const player = action.meta.arg.controler;
const ids = action.meta.arg.codes;
const cards = ids.map((id, idx) => {
const cards = ids.map((id) => {
return {
occupant: { id, data: {}, text: {} },
location: {
controler: player,
location: ygopro.CardZone.HAND,
sequence: idx,
},
idleInteractivities: [],
};
......@@ -125,19 +111,11 @@ export const handsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
});
builder.addCase(fetchHandsMeta.fulfilled, (state, action) => {
// `Meta`结果回来后更新手牌的`Meta`结果
const player = action.payload[0];
const metas = action.payload[1];
const player = action.payload.controler;
const metas = action.payload.metas;
const hands = judgeSelf(player, state) ? state.meHands : state.opHands;
if (hands) {
for (let hand of hands.inner) {
for (let meta of metas) {
if (hand.occupant?.id === meta.id) {
hand.occupant = meta;
}
}
}
}
updateCardMeta(hands, metas);
});
builder.addCase(insertHandMeta.pending, (state, action) => {
......@@ -162,6 +140,35 @@ export const handsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
extendMeta(hands, meta, sequence);
});
builder.addCase(updateHandsMeta.pending, (state, action) => {
const controler = action.meta.arg.controler;
const codes = action.meta.arg.codes;
const metas = codes.map((code) => {
return {
occupant: { id: code, data: {}, text: {} },
location: {
controler,
location: ygopro.CardZone.HAND,
},
idleInteractivities: [],
};
});
const hands = judgeSelf(controler, state) ? state.meHands : state.opHands;
if (hands) {
hands.inner = metas;
}
});
builder.addCase(updateHandsMeta.fulfilled, (state, action) => {
const controler = action.payload.controler;
const metas = action.payload.metas;
const hands = judgeSelf(controler, state) ? state.meHands : state.opHands;
updateCardMeta(hands, metas);
});
};
// 在特定位置增加手牌
......
......@@ -6,5 +6,5 @@ export default (
draw: ygopro.StocGameMessage.MsgDraw,
dispatch: AppDispatch
) => {
dispatch(fetchHandsMeta([draw.player, draw.cards]));
dispatch(fetchHandsMeta({ controler: draw.player, codes: draw.cards }));
};
......@@ -13,6 +13,7 @@ import onMsgSelectChain from "./selectChain";
import onMsgSelectEffectYn from "./selectEffectYn";
import onMsgSelectPosition from "./selectPosition";
import onMsgSelectOption from "./selectOption";
import onMsgShuffleHand from "./shuffleHand";
export default function handleGameMsg(pb: ygopro.YgoStocMsg) {
const dispatch = store.dispatch;
......@@ -97,6 +98,12 @@ export default function handleGameMsg(pb: ygopro.YgoStocMsg) {
break;
}
case "shuffle_hand": {
const shuffleHand = msg.shuffle_hand;
onMsgShuffleHand(shuffleHand, dispatch);
break;
}
default: {
break;
}
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { updateHandsMeta } from "../../reducers/duel/handsSlice";
import { AppDispatch } from "../../store";
import MsgShuffleHand = ygopro.StocGameMessage.MsgShuffleHand;
export default (shuffleHand: MsgShuffleHand, dispatch: AppDispatch) => {
dispatch(
updateHandsMeta({ controler: shuffleHand.player, codes: shuffleHand.hands })
);
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment