diff options
Diffstat (limited to 'src/mystery_gift_link.c')
-rw-r--r-- | src/mystery_gift_link.c | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/mystery_gift_link.c b/src/mystery_gift_link.c new file mode 100644 index 000000000..55f4b7852 --- /dev/null +++ b/src/mystery_gift_link.c @@ -0,0 +1,222 @@ +#include "global.h" +#include "malloc.h" +#include "decompress.h" +#include "util.h" +#include "link.h" +#include "link_rfu.h" +#include "overworld.h" +#include "script.h" +#include "battle_tower.h" +#include "mystery_event_script.h" +#include "mystery_gift.h" +#include "mystery_gift_link.h" + +/* + Handles the link connection functions used by the Mystery Gift client/server. + Note: MysteryGiftLink is shortened to MGL for internal functions. +*/ + +struct SendRecvHeader +{ + u16 ident; + u16 crc; + u16 size; +}; + +static u32 MGL_Receive(struct MysteryGiftLink *); +static u32 MGL_Send(struct MysteryGiftLink *); + +u32 MysteryGiftLink_Recv(struct MysteryGiftLink * link) +{ + return link->recvFunc(link); +} + +u32 MysteryGiftLink_Send(struct MysteryGiftLink * link) +{ + return link->sendFunc(link); +} + +void MysteryGiftLink_Init(struct MysteryGiftLink * link, u32 sendPlayerId, u32 recvPlayerId) +{ + link->sendPlayerId = sendPlayerId; + link->recvPlayerId = recvPlayerId; + link->state = 0; + link->sendCRC = 0; + link->sendSize = 0; + link->sendCounter = 0; + link->recvCRC = 0; + link->recvSize = 0; + link->recvCounter = 0; + link->sendBuffer = NULL; + link->recvBuffer = NULL; + link->sendFunc = MGL_Send; + link->recvFunc = MGL_Receive; +} + +void MysteryGiftLink_InitSend(struct MysteryGiftLink * link, u32 ident, const void * src, u32 size) +{ + link->state = 0; + link->sendIdent = ident; + link->sendCounter = 0; + link->sendCRC = 0; + if (size != 0) + link->sendSize = size; + else + link->sendSize = MG_LINK_BUFFER_SIZE; + link->sendBuffer = src; +} + +void MysteryGiftLink_InitRecv(struct MysteryGiftLink * link, u32 ident, void * dest) +{ + link->state = 0; + link->recvIdent = ident; + link->recvCounter = 0; + link->recvCRC = 0; + link->recvSize = 0; + link->recvBuffer = dest; +} + +static void MGL_ReceiveBlock(u32 playerId, void * dest, size_t size) +{ + memcpy(dest, gBlockRecvBuffer[playerId], size); +} + +static bool32 MGL_HasReceived(u32 playerId) +{ + if ((GetBlockReceivedStatus() >> playerId) & 1) + return TRUE; + else + return FALSE; +} + +static void MGL_ResetReceived(u32 playerId) +{ + ResetBlockReceivedFlag(playerId); +} + +static bool32 MGL_Receive(struct MysteryGiftLink * link) +{ + struct SendRecvHeader header; + + switch (link->state) + { + case 0: + if (MGL_HasReceived(link->recvPlayerId)) + { + MGL_ReceiveBlock(link->recvPlayerId, &header, sizeof(header)); + link->recvSize = header.size; + link->recvCRC = header.crc; + if (link->recvSize > MG_LINK_BUFFER_SIZE) + { + LinkRfu_FatalError(); + return FALSE; + } + else if (link->recvIdent != header.ident) + { + LinkRfu_FatalError(); + return FALSE; + } + else + { + link->recvCounter = 0; + MGL_ResetReceived(link->recvPlayerId); + link->state++; + } + } + break; + case 1: + if (MGL_HasReceived(link->recvPlayerId)) + { + size_t blocksize = link->recvCounter * 252; + if (link->recvSize - blocksize <= 252) + { + MGL_ReceiveBlock(link->recvPlayerId, link->recvBuffer + blocksize, link->recvSize - blocksize); + link->recvCounter++; + link->state++; + } + else + { + MGL_ReceiveBlock(link->recvPlayerId, link->recvBuffer + blocksize, 252); + link->recvCounter++; + } + MGL_ResetReceived(link->recvPlayerId); + } + break; + case 2: + if (CalcCRC16WithTable(link->recvBuffer, link->recvSize) != link->recvCRC) + { + LinkRfu_FatalError(); + return FALSE; + } + else + { + link->state = 0; + return TRUE; + } + break; + } + + return FALSE; +} + +static bool32 MGL_Send(struct MysteryGiftLink * link) +{ + struct SendRecvHeader header; + + switch (link->state) + { + case 0: + if (IsLinkTaskFinished()) + { + header.ident = link->sendIdent; + header.size = link->sendSize; + header.crc = CalcCRC16WithTable(link->sendBuffer, link->sendSize); + link->sendCRC = header.crc; + link->sendCounter = 0; + SendBlock(0, &header, sizeof(header)); + link->state++; + } + break; + case 1: + if (IsLinkTaskFinished()) + { + if (MGL_HasReceived(link->sendPlayerId)) + { + size_t blocksize; + MGL_ResetReceived(link->sendPlayerId); + blocksize = 252 * link->sendCounter; + if (link->sendSize - blocksize <= 252) + { + SendBlock(0, link->sendBuffer + blocksize, link->sendSize - blocksize); + link->sendCounter++; + link->state++; + } + else + { + SendBlock(0, link->sendBuffer + blocksize, 252); + link->sendCounter++; + } + } + } + break; + case 2: + if (IsLinkTaskFinished()) + { + if (CalcCRC16WithTable(link->sendBuffer, link->sendSize) != link->sendCRC) + LinkRfu_FatalError(); + else + link->state++; + } + break; + case 3: + if (MGL_HasReceived(link->sendPlayerId)) + { + MGL_ResetReceived(link->sendPlayerId); + link->state = 0; + return TRUE; + } + break; + } + + return FALSE; +} |