Commit 998fb4a9 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/update_card_data' into 'main'

Feat/update card data

See merge request mycard/Neos!147
parents d6111209 86ec6b1c
neos-protobuf @ 96e06224
Subproject commit 91892bf33e2359f6617c82b0f5f3617ed36f3540 Subproject commit 96e06224838437a6cd0c985070f31ddedc08ad89
...@@ -71,6 +71,14 @@ impl BufferReader { ...@@ -71,6 +71,14 @@ impl BufferReader {
ret ret
} }
pub fn offset(&self) -> usize {
self.offset
}
pub fn setOffset(&mut self, offset: usize) {
self.offset = offset;
}
} }
#[wasm_bindgen] #[wasm_bindgen]
......
This diff is collapsed.
...@@ -49,3 +49,4 @@ export const MSG_RECOVER = 92; ...@@ -49,3 +49,4 @@ export const MSG_RECOVER = 92;
export const MSG_PAY_LP_COST = 100; export const MSG_PAY_LP_COST = 100;
export const MSG_WIN = 5; export const MSG_WIN = 5;
export const MSG_WAITING = 3; export const MSG_WAITING = 3;
export const MSG_UPDATE_DATA = 6;
...@@ -25,6 +25,7 @@ import MsgWaitAdapter from "./wait"; ...@@ -25,6 +25,7 @@ import MsgWaitAdapter from "./wait";
import MsgDamage from "./damage"; import MsgDamage from "./damage";
import MsgRecover from "./recover"; import MsgRecover from "./recover";
import MsgWin from "./win"; import MsgWin from "./win";
import MsgUpdateDataAdapter from "./updateData";
import PENETRATE from "./penetrate"; import PENETRATE from "./penetrate";
/* /*
...@@ -148,6 +149,11 @@ export default class GameMsgAdapter implements StocAdapter { ...@@ -148,6 +149,11 @@ export default class GameMsgAdapter implements StocAdapter {
break; break;
} }
case GAME_MSG.MSG_UPDATE_DATA: {
gameMsg.update_data = MsgUpdateDataAdapter(gameData);
break;
}
default: { default: {
gameMsg.unimplemented = new ygopro.StocGameMessage.MsgUnimplemented({ gameMsg.unimplemented = new ygopro.StocGameMessage.MsgUnimplemented({
command: func, command: func,
......
import {
QUERY_ALIAS,
QUERY_ATTACK,
QUERY_ATTRIBUTE,
QUERY_BASE_ATTACK,
QUERY_BASE_DEFENSE,
QUERY_CODE,
QUERY_COUNTERS,
QUERY_DEFENSE,
QUERY_EQUIP_CARD,
QUERY_LEVEL,
QUERY_LINK,
QUERY_LSCALE,
QUERY_OVERLAY_CARD,
QUERY_OWNER,
QUERY_POSITION,
QUERY_RACE,
QUERY_RANK,
QUERY_REASON,
QUERY_REASON_CARD,
QUERY_RSCALE,
QUERY_STATUS,
QUERY_TARGET_CARD,
QUERY_TYPE,
} from "../../../../../common";
import { ygopro } from "../../../idl/ocgcore";
import { BufferReaderExt } from "../../bufferIO";
import { numberToCardZone } from "../../util";
import MsgUpdateData = ygopro.StocGameMessage.MsgUpdateData;
/*
* Msg UpdateData
*
* @param - todo
*
* @usage - ygopro后端通知前端更新卡片元数据
* */
export default (data: Uint8Array) => {
const reader = new BufferReaderExt(data);
const player = reader.inner.readUint8();
const zone = numberToCardZone(reader.inner.readUint8());
const msg = new MsgUpdateData({
player,
zone,
actions: [],
});
try {
while (true) {
const len = reader.inner.readInt32();
if (len == 4) continue;
const pos = reader.inner.offset();
const action = _readUpdateAction(reader);
if (action) {
msg.actions.push(action);
}
reader.inner.setOffset(pos + len - 4);
}
} catch (e) {
// console.log(e)
}
return msg;
};
function _readUpdateAction(
reader: BufferReaderExt
): MsgUpdateData.Action | undefined {
const flag = reader.inner.readInt32();
if (flag == 0) return undefined;
const mask = -1;
let code = mask;
let location;
let alias = mask;
let type_ = mask;
let level = mask;
let rank = mask;
let attribute = mask;
let race = mask;
let attack = mask;
let defense = mask;
let base_attack = mask;
let base_defense = mask;
let reason = mask;
let reason_card = mask;
let equip_card;
let target_cards = [];
let overlay_cards = [];
let counters = new Map<number, number>();
let owner = mask;
let status = mask;
let lscale = mask;
let rscale = mask;
let link = mask;
if (flag & QUERY_CODE) {
code = reader.inner.readInt32();
}
if (flag & QUERY_POSITION) {
location = reader.readCardLocation();
}
if (flag & QUERY_ALIAS) {
alias = reader.inner.readInt32();
}
if (flag & QUERY_TYPE) {
type_ = reader.inner.readInt32();
}
if (flag & QUERY_LEVEL) {
level = reader.inner.readInt32();
}
if (flag & QUERY_RANK) {
rank = reader.inner.readInt32();
}
if (flag & QUERY_ATTRIBUTE) {
attribute = reader.inner.readInt32();
}
if (flag & QUERY_RACE) {
race = reader.inner.readInt32();
}
if (flag & QUERY_ATTACK) {
attack = reader.inner.readInt32();
}
if (flag & QUERY_DEFENSE) {
defense = reader.inner.readInt32();
}
if (flag & QUERY_BASE_ATTACK) {
base_attack = reader.inner.readInt32();
}
if (flag & QUERY_BASE_DEFENSE) {
base_defense = reader.inner.readInt32();
}
if (flag & QUERY_REASON) {
reason = reader.inner.readInt32();
}
if (flag & QUERY_REASON_CARD) {
reason_card = reader.inner.readInt32();
}
if (flag & QUERY_EQUIP_CARD) {
equip_card = reader.readCardLocation();
}
if (flag & QUERY_TARGET_CARD) {
const count = reader.inner.readInt32();
for (let i = 0; i < count; i += 1) {
target_cards.push(reader.readCardLocation());
}
}
if (flag & QUERY_OVERLAY_CARD) {
const count = reader.inner.readInt32();
for (let i = 0; i < count; i += 1) {
overlay_cards.push(reader.inner.readInt32());
}
}
if (flag & QUERY_COUNTERS) {
const count = reader.inner.readInt32();
for (let i = 0; i < count; i += 1) {
const ctype = reader.inner.readUint16();
const ccount = reader.inner.readUint16();
counters.set(ctype, ccount);
}
}
if (flag & QUERY_OWNER) {
owner = reader.inner.readInt32();
}
if (flag & QUERY_STATUS) {
status = reader.inner.readInt32();
}
if (flag & QUERY_LSCALE) {
lscale = reader.inner.readInt32();
}
if (flag & QUERY_RSCALE) {
rscale = reader.inner.readInt32();
}
if (flag & QUERY_LINK) {
link = reader.inner.readInt32();
}
return new MsgUpdateData.Action({
code,
location,
alias,
type_,
level,
rank,
attribute,
race,
attack,
defense,
base_attack,
base_defense,
reason,
reason_card,
equip_card,
target_cards,
overlay_cards,
counters,
owner,
status,
lscale,
rscale,
link,
});
}
...@@ -196,3 +196,27 @@ export const REASON_MATERIAL = 0x8; // ...@@ -196,3 +196,27 @@ export const REASON_MATERIAL = 0x8; //
// const REASON_REVEAL = 0x8000000; // // const REASON_REVEAL = 0x8000000; //
// const REASON_LINK = 0x10000000; // // const REASON_LINK = 0x10000000; //
// const REASON_LOST_OVERLAY = 0x20000000; // // const REASON_LOST_OVERLAY = 0x20000000; //
export const QUERY_CODE = 0x1;
export const QUERY_POSITION = 0x2;
export const QUERY_ALIAS = 0x4;
export const QUERY_TYPE = 0x8;
export const QUERY_LEVEL = 0x10;
export const QUERY_RANK = 0x20;
export const QUERY_ATTRIBUTE = 0x40;
export const QUERY_RACE = 0x80;
export const QUERY_ATTACK = 0x100;
export const QUERY_DEFENSE = 0x200;
export const QUERY_BASE_ATTACK = 0x400;
export const QUERY_BASE_DEFENSE = 0x800;
export const QUERY_REASON = 0x1000;
export const QUERY_REASON_CARD = 0x2000;
export const QUERY_EQUIP_CARD = 0x4000;
export const QUERY_TARGET_CARD = 0x8000;
export const QUERY_OVERLAY_CARD = 0x10000;
export const QUERY_COUNTERS = 0x20000;
export const QUERY_OWNER = 0x40000;
export const QUERY_STATUS = 0x80000;
export const QUERY_LSCALE = 0x200000;
export const QUERY_RSCALE = 0x400000;
export const QUERY_LINK = 0x800000;
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { import {
clearIdleInteractivities, clearIdleInteractivities,
clearPlaceInteractivities, clearPlaceInteractivities,
DuelReducer, DuelReducer,
updateCardData,
} from "./generic"; } from "./generic";
import { judgeSelf } from "./util"; import { judgeSelf } from "./util";
type MsgUpdateData = ReturnType<
typeof ygopro.StocGameMessage.MsgUpdateData.prototype.toObject
>;
export const clearAllIdleInteractivitiesImpl: DuelReducer<number> = ( export const clearAllIdleInteractivitiesImpl: DuelReducer<number> = (
state, state,
...@@ -56,3 +61,66 @@ export const clearAllPlaceInteractivitiesImpl: DuelReducer<number> = ( ...@@ -56,3 +61,66 @@ export const clearAllPlaceInteractivitiesImpl: DuelReducer<number> = (
states.forEach((item) => clearPlaceInteractivities(item)); states.forEach((item) => clearPlaceInteractivities(item));
}; };
export const updateFieldDataImpl: DuelReducer<MsgUpdateData> = (
state,
action
) => {
const player = action.payload.player;
const zone = action.payload.zone;
const actions = action.payload.actions;
if (player && zone && actions) {
switch (zone) {
case ygopro.CardZone.HAND: {
const hand = judgeSelf(player, state) ? state.meHands : state.opHands;
updateCardData(hand, actions);
break;
}
case ygopro.CardZone.EXTRA: {
const extra = judgeSelf(player, state)
? state.meExtraDeck
: state.opExtraDeck;
updateCardData(extra, actions);
break;
}
case ygopro.CardZone.MZONE: {
const monster = judgeSelf(player, state)
? state.meMonsters
: state.opMonsters;
updateCardData(monster, actions);
break;
}
case ygopro.CardZone.SZONE: {
const magics = judgeSelf(player, state)
? state.meMagics
: state.opMagics;
updateCardData(magics, actions);
break;
}
case ygopro.CardZone.GRAVE: {
const cemetery = judgeSelf(player, state)
? state.meCemetery
: state.opCemetery;
updateCardData(cemetery, actions);
break;
}
case ygopro.CardZone.REMOVED: {
const exclusion = judgeSelf(player, state)
? state.meExclusion
: state.opExclusion;
updateCardData(exclusion, actions);
break;
}
default: {
break;
}
}
}
};
...@@ -8,6 +8,9 @@ import { CardMeta } from "../../api/cards"; ...@@ -8,6 +8,9 @@ import { CardMeta } from "../../api/cards";
import { ygopro } from "../../api/ocgcore/idl/ocgcore"; import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { fetchCard } from "../../api/cards"; import { fetchCard } from "../../api/cards";
import { DuelState } from "./mod"; import { DuelState } from "./mod";
type UpdateDataAction = ReturnType<
typeof ygopro.StocGameMessage.MsgUpdateData.Action.prototype.toObject
>;
export type DuelReducer<T> = CaseReducer<DuelState, PayloadAction<T>>; export type DuelReducer<T> = CaseReducer<DuelState, PayloadAction<T>>;
...@@ -283,3 +286,45 @@ export function setPosition<T extends DuelFieldState>( ...@@ -283,3 +286,45 @@ export function setPosition<T extends DuelFieldState>(
target.location.position = position; target.location.position = position;
} }
} }
export function updateCardData<T extends DuelFieldState>(
state: T | undefined,
actions: UpdateDataAction[]
) {
for (const payload of actions) {
const sequence = payload.location?.sequence;
if (typeof sequence !== "undefined") {
console.log(payload.type_);
const target = state?.inner.find((_, idx) => idx == sequence);
if (target && target.occupant) {
const occupant = target.occupant;
// 目前只更新以下字段
if (payload.code !== undefined && payload.code >= 0) {
occupant.id = payload.code;
occupant.text.id = payload.code;
}
if (payload.location !== undefined) {
target.location.position = payload.location.position;
}
if (payload.type_ !== undefined && payload.type_ >= 0) {
occupant.data.type = payload.type_;
}
if (payload.level !== undefined && payload.level >= 0) {
occupant.data.level = payload.level;
}
if (payload.attribute !== undefined && payload.attribute >= 0) {
occupant.data.attribute = payload.attribute;
}
if (payload.race !== undefined && payload.race >= 0) {
occupant.data.race = payload.race;
}
if (payload.attack !== undefined && payload.attack >= 0) {
occupant.data.atk = payload.attack;
}
if (payload.defense !== undefined && payload.defense >= 0) {
occupant.data.def = payload.defense;
}
}
}
}
}
...@@ -95,6 +95,7 @@ import { DeckState, initDeckImpl } from "./deckSlice"; ...@@ -95,6 +95,7 @@ import { DeckState, initDeckImpl } from "./deckSlice";
import { import {
clearAllIdleInteractivitiesImpl, clearAllIdleInteractivitiesImpl,
clearAllPlaceInteractivitiesImpl, clearAllPlaceInteractivitiesImpl,
updateFieldDataImpl,
} from "./commonSlice"; } from "./commonSlice";
import { import {
ExtraDeckState, ExtraDeckState,
...@@ -256,6 +257,7 @@ const duelSlice = createSlice({ ...@@ -256,6 +257,7 @@ const duelSlice = createSlice({
// 通用的`Reducer` // 通用的`Reducer`
clearAllIdleInteractivities: clearAllIdleInteractivitiesImpl, clearAllIdleInteractivities: clearAllIdleInteractivitiesImpl,
clearAllPlaceInteractivities: clearAllPlaceInteractivitiesImpl, clearAllPlaceInteractivities: clearAllPlaceInteractivitiesImpl,
updateFieldData: updateFieldDataImpl,
// 对局结果`Reducer` // 对局结果`Reducer`
setResult: (state, action: PayloadAction<MsgWin.ActionType>) => { setResult: (state, action: PayloadAction<MsgWin.ActionType>) => {
...@@ -352,6 +354,7 @@ export const { ...@@ -352,6 +354,7 @@ export const {
setResult, setResult,
setWaiting, setWaiting,
setUnimplemented, setUnimplemented,
updateFieldData,
} = duelSlice.actions; } = duelSlice.actions;
export const selectDuelHsStart = (state: RootState) => { export const selectDuelHsStart = (state: RootState) => {
return state.duel.meInitInfo != null; return state.duel.meInitInfo != null;
......
...@@ -22,6 +22,7 @@ import onMsgUpdateHp from "./updateHp"; ...@@ -22,6 +22,7 @@ import onMsgUpdateHp from "./updateHp";
import onMsgWin from "./win"; import onMsgWin from "./win";
import onMsgWait from "./wait"; import onMsgWait from "./wait";
import onUnimplemented from "./unimplemented"; import onUnimplemented from "./unimplemented";
import onMsgUpdateData from "./updateData";
import { setWaiting } from "../../reducers/duel/mod"; import { setWaiting } from "../../reducers/duel/mod";
const ActiveList = [ const ActiveList = [
...@@ -151,6 +152,11 @@ export default function handleGameMsg(pb: ygopro.YgoStocMsg) { ...@@ -151,6 +152,11 @@ export default function handleGameMsg(pb: ygopro.YgoStocMsg) {
break; break;
} }
case "update_data": {
onMsgUpdateData(msg.update_data, dispatch);
break;
}
case "unimplemented": { case "unimplemented": {
onUnimplemented(msg.unimplemented, dispatch); onUnimplemented(msg.unimplemented, dispatch);
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { updateFieldData } from "../../reducers/duel/mod";
import { AppDispatch } from "../../store";
import MsgUpdateData = ygopro.StocGameMessage.MsgUpdateData;
export default (updateData: MsgUpdateData, dispatch: AppDispatch) => {
dispatch(updateFieldData(updateData.toObject()));
};
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