Game client codebase including: - CharacterActionControl: Character and creature management - GlobalScript: Network, items, skills, quests, utilities - RYLClient: Main client application with GUI and event handlers - Engine: 3D rendering engine (RYLGL) - MemoryManager: Custom memory allocation - Library: Third-party dependencies (DirectX, boost, etc.) - Tools: Development utilities 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
272 lines
7.3 KiB
C++
272 lines
7.3 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: AsyncIo.h
|
|
//
|
|
// Desc: DirectShow sample code - base library for I/O functionality.
|
|
//
|
|
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
#ifndef __ASYNCIO_H__
|
|
#define __ASYNCIO_H__
|
|
//
|
|
// definition of CAsyncFile object that performs file access. It provides
|
|
// asynchronous, unbuffered, aligned reads from a file, using a worker thread
|
|
// on win95 and potentially overlapped i/o if available.
|
|
|
|
// !!! Need to use real overlapped i/o if available
|
|
// currently only uses worker thread, not overlapped i/o
|
|
|
|
|
|
class CAsyncIo;
|
|
class CAsyncStream;
|
|
|
|
//
|
|
// Model the stream we read from based on a file-like interface
|
|
//
|
|
class CAsyncStream
|
|
{
|
|
public:
|
|
virtual ~CAsyncStream() {};
|
|
virtual HRESULT SetPointer(LONGLONG llPos) = 0;
|
|
virtual HRESULT Read(PBYTE pbBuffer,
|
|
DWORD dwBytesToRead,
|
|
BOOL bAlign,
|
|
LPDWORD pdwBytesRead) = 0;
|
|
virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0;
|
|
virtual DWORD Alignment() = 0;
|
|
virtual void Lock() = 0;
|
|
virtual void Unlock() = 0;
|
|
//virtual void SetStopHandle(HANDLE hevStop) {}
|
|
};
|
|
|
|
// represents a single request and performs the i/o. Can be called on either
|
|
// worker thread or app thread, but must hold pcsFile across file accesses.
|
|
// (ie across SetFilePointer/ReadFile pairs)
|
|
class CAsyncRequest
|
|
{
|
|
CAsyncIo *m_pIo;
|
|
CAsyncStream *m_pStream;
|
|
LONGLONG m_llPos;
|
|
BOOL m_bAligned;
|
|
LONG m_lLength;
|
|
BYTE* m_pBuffer;
|
|
LPVOID m_pContext;
|
|
DWORD m_dwUser;
|
|
HRESULT m_hr;
|
|
|
|
public:
|
|
// init the params for this request. Issue the i/o
|
|
// if overlapped i/o is possible.
|
|
HRESULT Request(
|
|
CAsyncIo *pIo,
|
|
CAsyncStream *pStream,
|
|
LONGLONG llPos,
|
|
LONG lLength,
|
|
BOOL bAligned,
|
|
BYTE* pBuffer,
|
|
LPVOID pContext, // filter's context
|
|
DWORD dwUser); // downstream filter's context
|
|
|
|
// issue the i/o if not overlapped, and block until i/o complete.
|
|
// returns error code of file i/o
|
|
HRESULT Complete();
|
|
|
|
// cancels the i/o. blocks until i/o is no longer pending
|
|
HRESULT Cancel()
|
|
{
|
|
return S_OK;
|
|
};
|
|
|
|
// accessor functions
|
|
LPVOID GetContext()
|
|
{
|
|
return m_pContext;
|
|
};
|
|
|
|
DWORD GetUser()
|
|
{
|
|
return m_dwUser;
|
|
};
|
|
|
|
HRESULT GetHResult() {
|
|
return m_hr;
|
|
};
|
|
|
|
// we set m_lLength to the actual length
|
|
LONG GetActualLength() {
|
|
return m_lLength;
|
|
};
|
|
|
|
LONGLONG GetStart() {
|
|
return m_llPos;
|
|
};
|
|
};
|
|
|
|
|
|
typedef CGenericList<CAsyncRequest> CRequestList;
|
|
|
|
// this class needs a worker thread, but the ones defined in classes\base
|
|
// are not suitable (they assume you have one message sent or posted per
|
|
// request, whereas here for efficiency we want just to set an event when
|
|
// there is work on the queue).
|
|
//
|
|
// we create CAsyncRequest objects and queue them on m_listWork. The worker
|
|
// thread pulls them off, completes them and puts them on m_listDone.
|
|
// The events m_evWork and m_evDone are set when the corresponding lists are
|
|
// not empty.
|
|
//
|
|
// Synchronous requests are done on the caller thread. These should be
|
|
// synchronised by the caller, but to make sure we hold m_csFile across
|
|
// the SetFilePointer/ReadFile code.
|
|
//
|
|
// Flush by calling BeginFlush. This rejects all further requests (by
|
|
// setting m_bFlushing within m_csLists), cancels all requests and moves them
|
|
// to the done list, and sets m_evDone to ensure that no WaitForNext operations
|
|
// will block. Call EndFlush to cancel this state.
|
|
//
|
|
// we support unaligned calls to SyncRead. This is done by opening the file
|
|
// twice if we are using unbuffered i/o (m_dwAlign > 1).
|
|
// !!!fix this to buffer on top of existing file handle?
|
|
class CAsyncIo
|
|
{
|
|
|
|
CCritSec m_csReader;
|
|
CAsyncStream *m_pStream;
|
|
|
|
CCritSec m_csLists; // locks access to the list and events
|
|
BOOL m_bFlushing; // true if between BeginFlush/EndFlush
|
|
CRequestList m_listWork;
|
|
CRequestList m_listDone;
|
|
CAMEvent m_evWork; // set when list is not empty
|
|
CAMEvent m_evDone;
|
|
|
|
// for correct flush behaviour: all protected by m_csLists
|
|
LONG m_cItemsOut; // nr of items not on listDone or listWork
|
|
BOOL m_bWaiting; // TRUE if someone waiting for m_evAllDone
|
|
CAMEvent m_evAllDone; // signal when m_cItemsOut goes to 0 if m_cWaiting
|
|
|
|
|
|
CAMEvent m_evStop; // set when thread should exit
|
|
HANDLE m_hThread;
|
|
|
|
LONGLONG Size() {
|
|
ASSERT(m_pStream != NULL);
|
|
return m_pStream->Size();
|
|
};
|
|
|
|
// start the thread
|
|
HRESULT StartThread(void);
|
|
|
|
// stop the thread and close the handle
|
|
HRESULT CloseThread(void);
|
|
|
|
// manage the list of requests. hold m_csLists and ensure
|
|
// that the (manual reset) event hevList is set when things on
|
|
// the list but reset when the list is empty.
|
|
// returns null if list empty
|
|
CAsyncRequest* GetWorkItem();
|
|
|
|
// get an item from the done list
|
|
CAsyncRequest* GetDoneItem();
|
|
|
|
// put an item on the work list
|
|
HRESULT PutWorkItem(CAsyncRequest* pRequest);
|
|
|
|
// put an item on the done list
|
|
HRESULT PutDoneItem(CAsyncRequest* pRequest);
|
|
|
|
// called on thread to process any active requests
|
|
void ProcessRequests(void);
|
|
|
|
// initial static thread proc calls ThreadProc with DWORD
|
|
// param as this
|
|
static DWORD WINAPI InitialThreadProc(LPVOID pv) {
|
|
CAsyncIo * pThis = (CAsyncIo*) pv;
|
|
return pThis->ThreadProc();
|
|
};
|
|
|
|
DWORD ThreadProc(void);
|
|
|
|
public:
|
|
|
|
CAsyncIo(CAsyncStream *pStream);
|
|
~CAsyncIo();
|
|
|
|
// open the file
|
|
HRESULT Open(LPCTSTR pName);
|
|
|
|
// ready for async activity - call this before
|
|
// calling Request
|
|
HRESULT AsyncActive(void);
|
|
|
|
// call this when no more async activity will happen before
|
|
// the next AsyncActive call
|
|
HRESULT AsyncInactive(void);
|
|
|
|
// queue a requested read. must be aligned.
|
|
HRESULT Request(
|
|
LONGLONG llPos,
|
|
LONG lLength,
|
|
BOOL bAligned,
|
|
BYTE* pBuffer,
|
|
LPVOID pContext,
|
|
DWORD dwUser);
|
|
|
|
// wait for the next read to complete
|
|
HRESULT WaitForNext(
|
|
DWORD dwTimeout,
|
|
LPVOID *ppContext,
|
|
DWORD * pdwUser,
|
|
LONG * pcbActual
|
|
);
|
|
|
|
// perform a read of an already aligned buffer
|
|
HRESULT SyncReadAligned(
|
|
LONGLONG llPos,
|
|
LONG lLength,
|
|
BYTE* pBuffer,
|
|
LONG* pcbActual,
|
|
PVOID pvContext
|
|
);
|
|
|
|
// perform a synchronous read. will be buffered
|
|
// if not aligned.
|
|
HRESULT SyncRead(
|
|
LONGLONG llPos,
|
|
LONG lLength,
|
|
BYTE* pBuffer);
|
|
|
|
// return length
|
|
HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable);
|
|
|
|
// all Reader positions, read lengths and memory locations must
|
|
// be aligned to this.
|
|
HRESULT Alignment(LONG* pl);
|
|
|
|
HRESULT BeginFlush();
|
|
HRESULT EndFlush();
|
|
|
|
LONG Alignment()
|
|
{
|
|
return m_pStream->Alignment();
|
|
};
|
|
|
|
BOOL IsAligned(LONG l) {
|
|
if ((l & (Alignment() -1)) == 0) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
};
|
|
|
|
BOOL IsAligned(LONGLONG ll) {
|
|
return IsAligned( (LONG) (ll & 0xffffffff));
|
|
};
|
|
|
|
// Accessor
|
|
HANDLE StopEvent() const { return m_evDone; }
|
|
};
|
|
|
|
#endif // __ASYNCIO_H__
|