Initial commit: ROW Client source code

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>
This commit is contained in:
2025-11-29 16:24:34 +09:00
commit e067522598
5135 changed files with 1745744 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,187 @@
# Microsoft Developer Studio Project File - Name="MultiMapper" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=MultiMapper - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "MultiMapper.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "MultiMapper.mak" CFG="MultiMapper - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "MultiMapper - Win32 Release Unicode" (based on "Win32 (x86) Application")
!MESSAGE "MultiMapper - Win32 Debug Unicode" (based on "Win32 (x86) Application")
!MESSAGE "MultiMapper - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "MultiMapper - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "MultiMapper - Win32 Release Unicode"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "MultiMapper___Win32_Release_Unicode"
# PROP BASE Intermediate_Dir "MultiMapper___Win32_Release_Unicode"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "MultiMapper___Win32_Release_Unicode"
# PROP Intermediate_Dir "MultiMapper___Win32_Release_Unicode"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\..\common\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "..\..\common\include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "UNICODE" /D "_UNICODE" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /machine:I386
# ADD LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib shlwapi.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "MultiMapper - Win32 Debug Unicode"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "MultiMapper___Win32_Debug_Unicode"
# PROP BASE Intermediate_Dir "MultiMapper___Win32_Debug_Unicode"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "MultiMapper___Win32_Debug_Unicode"
# PROP Intermediate_Dir "MultiMapper___Win32_Debug_Unicode"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\common\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\common\include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "UNICODE" /D "_UNICODE" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib shlwapi.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ELSEIF "$(CFG)" == "MultiMapper - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I "..\..\common\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
# ADD LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib shlwapi.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "MultiMapper - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\common\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib shlwapi.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /stack:0x200000,0x200000 /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "MultiMapper - Win32 Release Unicode"
# Name "MultiMapper - Win32 Debug Unicode"
# Name "MultiMapper - Win32 Release"
# Name "MultiMapper - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\DirectX.ico
# End Source File
# Begin Source File
SOURCE=.\multidi.cpp
# End Source File
# Begin Source File
SOURCE=.\multidi.h
# End Source File
# Begin Source File
SOURCE=.\MultiMapper.cpp
# End Source File
# Begin Source File
SOURCE=.\MultiMapper.rc
# End Source File
# Begin Source File
SOURCE=.\resource.h
# End Source File
# End Group
# Begin Group "Common"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\common\src\dxutil.cpp
# End Source File
# Begin Source File
SOURCE=..\..\common\include\dxutil.h
# End Source File
# End Group
# End Target
# End Project

View File

@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "MultiMapper"=.\MultiMapper.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1,220 @@
# Microsoft Developer Studio Generated NMAKE File, Based on MultiMapper.dsp
!IF "$(CFG)" == ""
CFG=MultiMapper - Win32 Debug
!MESSAGE No configuration specified. Defaulting to MultiMapper - Win32 Debug.
!ENDIF
!IF "$(CFG)" != "MultiMapper - Win32 Release" && "$(CFG)" != "MultiMapper - Win32 Debug"
!MESSAGE Invalid configuration "$(CFG)" specified.
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "MultiMapper.mak" CFG="MultiMapper - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "MultiMapper - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "MultiMapper - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
!ERROR An invalid configuration is specified.
!ENDIF
!IF "$(OS)" == "Windows_NT"
NULL=
!ELSE
NULL=nul
!ENDIF
!IF "$(CFG)" == "MultiMapper - Win32 Release"
OUTDIR=.\Release
INTDIR=.\Release
# Begin Custom Macros
OutDir=.\Release
# End Custom Macros
ALL : "$(OUTDIR)\MultiMapper.exe"
CLEAN :
-@erase "$(INTDIR)\dxutil.obj"
-@erase "$(INTDIR)\multidi.obj"
-@erase "$(INTDIR)\MultiMapper.obj"
-@erase "$(INTDIR)\MultiMapper.res"
-@erase "$(INTDIR)\vc60.idb"
-@erase "$(OUTDIR)\MultiMapper.exe"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
CPP=cl.exe
CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "..\..\common\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Fp"$(INTDIR)\MultiMapper.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
.c{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.c{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
MTL=midl.exe
MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
RSC=rc.exe
RSC_PROJ=/l 0x409 /fo"$(INTDIR)\MultiMapper.res" /d "NDEBUG"
BSC32=bscmake.exe
BSC32_FLAGS=/nologo /o"$(OUTDIR)\MultiMapper.bsc"
BSC32_SBRS= \
LINK32=link.exe
LINK32_FLAGS=dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\MultiMapper.pdb" /machine:I386 /out:"$(OUTDIR)\MultiMapper.exe" /stack:0x200000,0x200000
LINK32_OBJS= \
"$(INTDIR)\multidi.obj" \
"$(INTDIR)\MultiMapper.obj" \
"$(INTDIR)\dxutil.obj" \
"$(INTDIR)\MultiMapper.res"
"$(OUTDIR)\MultiMapper.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ELSEIF "$(CFG)" == "MultiMapper - Win32 Debug"
OUTDIR=.\Debug
INTDIR=.\Debug
# Begin Custom Macros
OutDir=.\Debug
# End Custom Macros
ALL : "$(OUTDIR)\MultiMapper.exe"
CLEAN :
-@erase "$(INTDIR)\dxutil.obj"
-@erase "$(INTDIR)\multidi.obj"
-@erase "$(INTDIR)\MultiMapper.obj"
-@erase "$(INTDIR)\MultiMapper.res"
-@erase "$(INTDIR)\vc60.idb"
-@erase "$(INTDIR)\vc60.pdb"
-@erase "$(OUTDIR)\MultiMapper.exe"
-@erase "$(OUTDIR)\MultiMapper.ilk"
-@erase "$(OUTDIR)\MultiMapper.pdb"
"$(OUTDIR)" :
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
CPP=cl.exe
CPP_PROJ=/nologo /MLd /W3 /Gm /GX /ZI /Od /I "..\..\common\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Fp"$(INTDIR)\MultiMapper.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /GZ /c
.c{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.obj::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.c{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cpp{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
.cxx{$(INTDIR)}.sbr::
$(CPP) @<<
$(CPP_PROJ) $<
<<
MTL=midl.exe
MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
RSC=rc.exe
RSC_PROJ=/l 0x409 /fo"$(INTDIR)\MultiMapper.res" /d "_DEBUG"
BSC32=bscmake.exe
BSC32_FLAGS=/nologo /o"$(OUTDIR)\MultiMapper.bsc"
BSC32_SBRS= \
LINK32=link.exe
LINK32_FLAGS=dsound.lib dinput8.lib dxerr8.lib d3dx8dt.lib d3d8.lib d3dxof.lib dxguid.lib winmm.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:yes /pdb:"$(OUTDIR)\MultiMapper.pdb" /debug /machine:I386 /out:"$(OUTDIR)\MultiMapper.exe" /pdbtype:sept /stack:0x200000,0x200000
LINK32_OBJS= \
"$(INTDIR)\multidi.obj" \
"$(INTDIR)\MultiMapper.obj" \
"$(INTDIR)\dxutil.obj" \
"$(INTDIR)\MultiMapper.res"
"$(OUTDIR)\MultiMapper.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
$(LINK32) @<<
$(LINK32_FLAGS) $(LINK32_OBJS)
<<
!ENDIF
!IF "$(NO_EXTERNAL_DEPS)" != "1"
!IF EXISTS("MultiMapper.dep")
!INCLUDE "MultiMapper.dep"
!ELSE
!MESSAGE Warning: cannot find "MultiMapper.dep"
!ENDIF
!ENDIF
!IF "$(CFG)" == "MultiMapper - Win32 Release" || "$(CFG)" == "MultiMapper - Win32 Debug"
SOURCE=.\multidi.cpp
"$(INTDIR)\multidi.obj" : $(SOURCE) "$(INTDIR)"
SOURCE=.\MultiMapper.cpp
"$(INTDIR)\MultiMapper.obj" : $(SOURCE) "$(INTDIR)"
SOURCE=.\MultiMapper.rc
"$(INTDIR)\MultiMapper.res" : $(SOURCE) "$(INTDIR)"
$(RSC) $(RSC_PROJ) $(SOURCE)
SOURCE=..\..\common\src\dxutil.cpp
"$(INTDIR)\dxutil.obj" : $(SOURCE) "$(INTDIR)"
$(CPP) $(CPP_PROJ) $(SOURCE)
!ENDIF

View File

@@ -0,0 +1,160 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define IDC_STATIC -1
#include <Windows.h>
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#define IDC_STATIC -1\r\n"
"#include <Windows.h>\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_MAIN ICON DISCARDABLE "DirectX.ico"
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_MAIN, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 326
TOPMARGIN, 7
BOTTOMMARGIN, 251
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_MAIN DIALOG DISCARDABLE 0, 0, 333, 260
STYLE DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE |
WS_CAPTION | WS_SYSMENU
CAPTION "DirectInput MultiMapper Sample"
FONT 8, "MS Shell Dlg"
BEGIN
PUSHBUTTON "E&xit",IDCANCEL,262,55,64,14
PUSHBUTTON "Configure &Input",IDM_CONFIGINPUT,262,7,64,14
RTEXT "Left/Right Axis:",IDC_STATIC,16,89,55,8
RTEXT "Up/Down Axis:",IDC_STATIC,16,79,55,8
LTEXT "Static",IDC_UD_AXIS_STATE_P1,80,79,48,8
LTEXT "Static",IDC_LR_AXIS_STATE_P1,80,89,48,8
RTEXT "Button State:",IDC_STATIC,16,99,55,8
LTEXT "Static",IDC_BUTTON_STATE_P1,80,99,48,8
LTEXT "Set the number of players, and click 'Configure Input' to view or change input settings.",
IDC_STATIC,7,27,244,17
GROUPBOX "Player 1",IDC_PLAYER1_GROUP,7,70,319,43
GROUPBOX "Player 2",IDC_PLAYER2_GROUP,7,115,319,43
RTEXT "Left/Right Axis:",IDC_TEXT2_P2,16,135,55,8
RTEXT "Up/Down Axis:",IDC_TEXT1_P2,16,125,55,8
LTEXT "Static",IDC_UD_AXIS_STATE_P2,80,125,48,8
LTEXT "Static",IDC_LR_AXIS_STATE_P2,80,135,48,8
RTEXT "Button State:",IDC_TEXT3_P2,16,145,55,8
LTEXT "Static",IDC_BUTTON_STATE_P2,80,145,48,8
LTEXT "Number of active players:",IDC_STATIC,7,54,81,8
COMBOBOX IDC_NUM_PLAYERS_COMBO,91,52,30,51,CBS_DROPDOWN |
CBS_SORT | WS_VSCROLL | WS_TABSTOP
RTEXT "Left/Right Axis:",IDC_TEXT2_P3,16,180,55,8
RTEXT "Up/Down Axis:",IDC_TEXT1_P3,16,170,55,8
LTEXT "Static",IDC_UD_AXIS_STATE_P3,80,170,48,8
LTEXT "Static",IDC_LR_AXIS_STATE_P3,80,180,48,8
RTEXT "Button State:",IDC_TEXT3_P3,16,190,55,8
LTEXT "Static",IDC_BUTTON_STATE_P3,80,190,48,8
GROUPBOX "Player 3",IDC_PLAYER3_GROUP,7,160,319,43
GROUPBOX "Player 4",IDC_PLAYER4_GROUP,7,206,319,43
RTEXT "Left/Right Axis:",IDC_TEXT2_P4,16,225,55,8
RTEXT "Up/Down Axis:",IDC_TEXT1_P4,16,215,55,8
LTEXT "Static",IDC_UD_AXIS_STATE_P4,80,215,48,8
LTEXT "Static",IDC_LR_AXIS_STATE_P4,80,225,48,8
RTEXT "Button State:",IDC_TEXT3_P4,16,235,55,8
LTEXT "Static",IDC_BUTTON_STATE_P4,80,235,48,8
LTEXT "This sample shows how a game can use the DirectInput action mapper to assign input devices to players based on knowledge of a user's prefered device. ",
IDC_STATIC,7,7,252,19
LTEXT "Sum of movement:",IDC_STATIC,130,54,60,8
LTEXT "Static",IDC_WORLD_STATE,191,54,65,8
PUSHBUTTON "Reset &Ownership",IDC_RESET_OWNERSHIP,262,23,64,14
LISTBOX IDC_DEVICE_ASSIGNED_P1,133,80,185,27,LBS_SORT |
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
WS_TABSTOP
LISTBOX IDC_DEVICE_ASSIGNED_P2,133,125,185,27,LBS_SORT |
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
WS_TABSTOP
LISTBOX IDC_DEVICE_ASSIGNED_P3,133,170,185,27,LBS_SORT |
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
WS_TABSTOP
LISTBOX IDC_DEVICE_ASSIGNED_P4,133,216,185,27,LBS_SORT |
LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL |
WS_TABSTOP
PUSHBUTTON "Reset &Mappings",IDC_RESET_MAPPINGS,262,39,64,14
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,909 @@
//-----------------------------------------------------------------------------
// File: MultiDI.cpp
//
// Desc: DirectInput framework class using semantic mapping with multiplayer
// device ownership. Feel free to use this class as a starting point
// for adding extra functionality.
//
// Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#define STRICT
#define DIRECTINPUT_VERSION 0x0800
#include <basetsd.h>
#include <tchar.h>
#include <stdio.h>
#include <windows.h>
#include <shlwapi.h> // defines SHDeleteKey
#include <dxerr8.h>
#include <d3d8types.h> // included to get the D3DCOLOR_RGBA macro.
#include "MultiDI.h"
#include "DXUtil.h"
#include <assert.h>
//-----------------------------------------------------------------------------
// Name: CMultiplayerInputDeviceManager
// Desc: Constructor
// Args: strRegKey - A location in the registry where device ownership
// information should be stored
//-----------------------------------------------------------------------------
CMultiplayerInputDeviceManager::CMultiplayerInputDeviceManager( TCHAR* strRegKey )
{
HRESULT hr = CoInitialize(NULL);
m_bCleanupCOM = SUCCEEDED(hr);
LONG nResult;
// Initialize members
m_pDI = NULL;
m_hWnd = NULL;
m_pdiaf = NULL;
m_pUsers = NULL;
m_pDeviceList = NULL;
m_AddDeviceCallback = NULL;
m_AddDeviceCallbackParam = NULL;
m_hKey = NULL;
m_dwNumDevices = 0;
m_dwMaxDevices = 0;
// Duplicate the registry location string since we'll need this again later
m_strKey = _tcsdup( strRegKey );
if( m_strKey == NULL )
return;
// Create a reg key to store device ownership data
nResult = RegCreateKeyEx( HKEY_CURRENT_USER, strRegKey, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&m_hKey, NULL );
if(nResult != ERROR_SUCCESS)
m_hKey = NULL;
}
//-----------------------------------------------------------------------------
// Name: ~CMultiplayerInputDeviceManager
// Desc: Destructor
//-----------------------------------------------------------------------------
CMultiplayerInputDeviceManager::~CMultiplayerInputDeviceManager()
{
Cleanup();
if( m_bCleanupCOM )
CoUninitialize();
RegCloseKey( m_hKey );
free( m_strKey );
}
//-----------------------------------------------------------------------------
// Name: Create
// Desc: Initializes the class, and enums the devices. See MultiMapper sample
// for how to use this class.
// It might fail if there are too many players for the
// number of devices availible, or if one player owns too many
// devices preventing others from having a device. Its up the app
// to prevent this or respond to this.
// Note: strUserName should be a array of sz strings
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::Create( HWND hWnd,
TCHAR* strUserNames[],
DWORD dwNumUsers,
DIACTIONFORMAT* pdiaf,
LPDIMANAGERCALLBACK AddDeviceCallback,
LPVOID pCallbackParam,
BOOL bResetOwnership,
BOOL bResetMappings )
{
HRESULT hr;
if( strUserNames == NULL || dwNumUsers == 0 )
return E_INVALIDARG;
Cleanup();
// Store data
m_hWnd = hWnd;
// Create and init the m_pUsers array
m_dwNumUsers = dwNumUsers;
m_pUsers = new PlayerInfo*[dwNumUsers];
for( DWORD i=0; i<dwNumUsers; i++ )
{
m_pUsers[i] = new PlayerInfo;
ZeroMemory( m_pUsers[i], sizeof(PlayerInfo) );
m_pUsers[i]->dwPlayerIndex = i; // set the 0-based player index (for easy referencing)
lstrcpyn( m_pUsers[i]->strPlayerName, strUserNames[i], MAX_PATH-1 );
}
m_AddDeviceCallback = AddDeviceCallback;
m_AddDeviceCallbackParam = pCallbackParam;
// Create the base DirectInput object
if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION,
IID_IDirectInput8, (VOID**)&m_pDI, NULL ) ) )
return DXTRACE_ERR_NOMSGBOX( TEXT("DirectInput8Create"), hr );
if( FAILED( hr = SetActionFormat( pdiaf, TRUE, bResetOwnership, bResetMappings ) ) )
return DXTRACE_ERR_NOMSGBOX( TEXT("SetActionFormat"), hr );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: SetActionFormat
// Desc: Sets a new action format.
// It re-enumerates the devices if bReenumerate
// It resets the ownership of the devices if bResetOwnership
// It resets the mapper actions of the devices if bResetMappings
// This function may fail if there are too many players for the
// number of devices availible, or if one player owns too many
// devices preventing others from having a device. Its up the app
// to prevent this or respond to this.
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::SetActionFormat( DIACTIONFORMAT* pdiaf,
BOOL bReenumerate,
BOOL bResetOwnership,
BOOL bResetMappings )
{
HRESULT hr;
DWORD iPlayer;
DWORD iDevice;
// Store the new action format
m_pdiaf = pdiaf;
// Only destroy and re-enumerate devices if the caller explicitly wants to.
// This isn't thread safe, so be sure not to have any other threads using
// this data unless you redesign this class
if( bReenumerate )
{
// Set all players to not have a device yet
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
m_pUsers[iPlayer]->bFoundDeviceForPlayer = FALSE;
if( bResetOwnership )
{
// Set all devices as not assigned to a player
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
m_pDeviceList[iDevice].pPlayerInfo = NULL;
// Delete the device ownership keys
DeleteDeviceOwnershipKeys();
}
// Devices must be unacquired to have a new action map set.
UnacquireDevices();
// Enumerate all available devices that map the pri 1 actions,
// and store them in the m_pDeviceList array
if( FAILED( hr = BuildDeviceList() ) )
return DXTRACE_ERR_NOMSGBOX( TEXT("BuildDeviceList"), hr );
// Assign devices to any players that don't have devices
// Some games may want to change this functionality.
if( FAILED( hr = AssignDevices() ) )
return DXTRACE_ERR_NOMSGBOX( TEXT("AssignDevices"), hr );
// Report an error if there are too many players for the
// number of devices availible, or if one player owns too many
// devices preventing others from having a device
if( FAILED( hr = VerifyAssignment() ) )
return hr;
// Now that every player has at least one device, build and set
// the action map, and use callback into the app to tell the
// app of the device assignment.
if( FAILED( hr = AddAssignedDevices( bResetMappings ) ) )
return DXTRACE_ERR_NOMSGBOX( TEXT("AddAssignedDevices"), hr );
// For every device that's assigned to a player, save its device key
// and assigned player to registry, so the app remembers which devices
// each player prefers
if( FAILED( hr = SaveDeviceOwnershipKeys() ) )
return DXTRACE_ERR_NOMSGBOX( TEXT("SaveDeviceOwnershipKeys"), hr );
}
else
{
// Just apply the new maps for each device owned by each user
// Devices must be unacquired to have a new action map set.
UnacquireDevices();
// Apply the new action map to the current devices.
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
{
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
PlayerInfo* pPlayerInfo = m_pDeviceList[iDevice].pPlayerInfo;
if( FAILED( hr = pdidDevice->BuildActionMap( m_pdiaf, pPlayerInfo->strPlayerName, DIDBAM_DEFAULT ) ) )
return DXTRACE_ERR_NOMSGBOX( TEXT("BuildActionMap"), hr );
if( FAILED( hr = pdidDevice->SetActionMap( m_pdiaf, pPlayerInfo->strPlayerName, DIDSAM_DEFAULT ) ) )
return DXTRACE_ERR_NOMSGBOX( TEXT("SetActionMap"), hr );
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: BuildDeviceList
// Desc:
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::BuildDeviceList()
{
// Cleanup any previously enumerated devices
CleanupDeviceList();
// Build a simple list of all devices currently attached to the machine. This
// array will be used to reassign devices to each user.
m_dwMaxDevices = 5;
m_dwNumDevices = 0;
m_pDeviceList = NULL;
m_pDeviceList = (DeviceInfo*) realloc( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) );
ZeroMemory( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) );
// Enumerate available devices for any user.
m_pDI->EnumDevicesBySemantics( NULL, m_pdiaf, StaticEnumSuitableDevicesCB,
this, DIEDBSFL_ATTACHEDONLY );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: EnumSuitableDevicesCB
// Desc: DirectInput device enumeratation callback. Calls AddDevice()
// on each device enumerated.
//-----------------------------------------------------------------------------
BOOL CALLBACK CMultiplayerInputDeviceManager::StaticEnumSuitableDevicesCB( LPCDIDEVICEINSTANCE pdidi,
LPDIRECTINPUTDEVICE8 pdidDevice,
DWORD dwFlags, DWORD dwDeviceRemaining,
VOID* pContext )
{
// Add the device to the device manager's internal list
CMultiplayerInputDeviceManager* pInputDeviceManager = (CMultiplayerInputDeviceManager*)pContext;
return pInputDeviceManager->EnumDevice( pdidi, pdidDevice,
dwFlags, dwDeviceRemaining );
}
//-----------------------------------------------------------------------------
// Name: EnumDevice
// Desc: Enums each device to see if its suitable to add
//-----------------------------------------------------------------------------
BOOL CMultiplayerInputDeviceManager::EnumDevice( const DIDEVICEINSTANCE* pdidi,
const LPDIRECTINPUTDEVICE8 pdidDevice,
DWORD dwFlags, DWORD dwRemainingDevices )
{
TCHAR strPlayerName[MAX_PATH];
TCHAR strDeviceGuid[40];
// Devices of type DI8DEVTYPE_DEVICECTRL are specialized devices not generally
// considered appropriate to control game actions. We just ignore these.
if( GET_DIDEVICE_TYPE(pdidi->dwDevType) != DI8DEVTYPE_DEVICECTRL )
{
// We're only interested in devices that map the pri 1 actions
if( dwFlags & DIEDBS_MAPPEDPRI1 )
{
// Add new pdidDevice struct to array, and resize array if needed
m_dwNumDevices++;
if( m_dwNumDevices > m_dwMaxDevices )
{
m_dwMaxDevices += 5;
m_pDeviceList = (DeviceInfo*) realloc( m_pDeviceList, m_dwMaxDevices*sizeof(DeviceInfo) );
ZeroMemory( m_pDeviceList + m_dwMaxDevices - 5, 5*sizeof(DeviceInfo) );
}
DXUtil_ConvertGUIDToString( &pdidi->guidInstance, strDeviceGuid );
DXUtil_ReadStringRegKey( m_hKey, strDeviceGuid, strPlayerName, MAX_PATH, TEXT("") );
// Add the device to the array m_pDeviceList
DWORD dwCurrentDevice = m_dwNumDevices-1;
ZeroMemory( &m_pDeviceList[dwCurrentDevice], sizeof(DeviceInfo) );
m_pDeviceList[dwCurrentDevice].didi = *pdidi;
m_pDeviceList[dwCurrentDevice].pdidDevice = pdidDevice;
m_pDeviceList[dwCurrentDevice].pdidDevice->AddRef();
m_pDeviceList[dwCurrentDevice].bMapsPri1Actions = ((dwFlags & DIEDBS_MAPPEDPRI1) == DIEDBS_MAPPEDPRI1);
m_pDeviceList[dwCurrentDevice].bMapsPri2Actions = ((dwFlags & DIEDBS_MAPPEDPRI2) == DIEDBS_MAPPEDPRI2);
if( lstrcmp( strPlayerName, TEXT("") ) != 0 )
{
m_pDeviceList[dwCurrentDevice].pPlayerInfo = LookupPlayer( strPlayerName );
if( m_pDeviceList[dwCurrentDevice].pPlayerInfo )
m_pDeviceList[dwCurrentDevice].pPlayerInfo->bFoundDeviceForPlayer = TRUE;
}
}
}
// Continue enumerating
return DIENUM_CONTINUE;
}
//-----------------------------------------------------------------------------
// Name: AssignDevices
// Desc:
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::AssignDevices()
{
DWORD iDevice;
DWORD iPlayer;
// For any device that doesn't have a user assigned to it,
// then assign it to the first user that needs a device
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
{
if( m_pDeviceList[iDevice].pPlayerInfo == NULL )
{
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
{
if( !m_pUsers[iPlayer]->bFoundDeviceForPlayer )
{
m_pDeviceList[iDevice].pPlayerInfo = m_pUsers[iPlayer];
m_pUsers[iPlayer]->bFoundDeviceForPlayer = TRUE;
break;
}
}
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: VerifyAssignment
// Desc:
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::VerifyAssignment()
{
DWORD iPlayer;
DWORD iDevice;
// For each player, make sure that a device was found for this
// player, otherwise return failure.
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
{
if( !m_pUsers[iPlayer]->bFoundDeviceForPlayer )
{
if( GetNumDevices() < m_dwNumUsers )
return E_DIUTILERR_TOOMANYUSERS;
else
{
// Check to see if there's a device that isn't already
// assigned to a player. If there is return
// E_DIUTILERR_PLAYERWITHOUTDEVICE otherwise return
// E_DIUTILERR_DEVICESTAKEN
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
{
if( m_pDeviceList[iDevice].pPlayerInfo == NULL )
return E_DIUTILERR_PLAYERWITHOUTDEVICE;
}
return E_DIUTILERR_DEVICESTAKEN;
}
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: AddAssignedDevices
// Desc: For every device that's assigned to a player, set it action map
// and add it to the game
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::AddAssignedDevices( BOOL bResetMappings )
{
DWORD iDevice;
DWORD iAction;
HRESULT hr = S_OK;
DWORD *pdwAppFixed = NULL;
// If flagged, we'll be remapping the actions to hardware defaults, and in
// the process DirectInput will clear the DIA_APPFIXED flag, so we need
// to make a copy in order to reapply the flag later.
if( bResetMappings )
{
pdwAppFixed = new DWORD[m_pdiaf->dwNumActions];
// Verify memory allocation and collect DIA_APPFIXED settings
if( pdwAppFixed )
{
for( iAction=0; iAction < m_pdiaf->dwNumActions; iAction++ )
pdwAppFixed[iAction] = m_pdiaf->rgoAction[iAction].dwFlags & DIA_APPFIXED;
}
}
// For every device that's assigned to a player,
// set it action map, and add it to the game
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
{
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
PlayerInfo* pPlayerInfo = m_pDeviceList[iDevice].pPlayerInfo;
if( pPlayerInfo != NULL )
{
// Set the device's coop level
hr = pdidDevice->SetCooperativeLevel( m_hWnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND );
if( FAILED(hr) )
break;
// Build and set the action map on this device. This will also remove
// it from DirectInput's internal list of available devices.
DWORD dwBuildFlags = bResetMappings ? DIDBAM_HWDEFAULTS : DIDBAM_DEFAULT;
DWORD dwSetFlags = bResetMappings ? DIDSAM_FORCESAVE : DIDSAM_DEFAULT;
hr = pdidDevice->BuildActionMap( m_pdiaf, pPlayerInfo->strPlayerName, dwBuildFlags );
if( FAILED( hr ) )
{
// just print out a debug message and keep going
DXTRACE_ERR_NOMSGBOX( TEXT("BuildActionMap"), hr );
hr = S_OK;
continue;
}
hr = pdidDevice->SetActionMap( m_pdiaf, pPlayerInfo->strPlayerName, dwSetFlags );
if( FAILED( hr ) )
{
// just print out a debug message and keep going
DXTRACE_ERR_NOMSGBOX( TEXT("SetActionMap"), hr );
hr = S_OK;
continue;
}
// Callback into the app so it can adjust the device and set
// the m_pDeviceList[iDevice].pParam field with a device state struct
if( m_AddDeviceCallback )
m_AddDeviceCallback( pPlayerInfo, &m_pDeviceList[iDevice],
&m_pDeviceList[iDevice].didi, m_AddDeviceCallbackParam );
// Check to see if the device is using relative axis -- sometimes app code
// might want to know this.
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(DIPROPDWORD);
dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dipdw.diph.dwObj = 0;
dipdw.diph.dwHow = DIPH_DEVICE;
dipdw.dwData = 0;
pdidDevice->GetProperty( DIPROP_AXISMODE, &dipdw.diph );
if( dipdw.dwData == DIPROPAXISMODE_REL )
m_pDeviceList[iDevice].bRelativeAxis = TRUE;
// We made it through this iteration without breaking out do to errors
hr = S_OK;
}
else
{
if( FAILED( hr = pdidDevice->BuildActionMap( m_pdiaf, NULL, DIDBAM_DEFAULT ) ) )
{
DXTRACE_ERR_NOMSGBOX( TEXT("BuildActionMap"), hr );
break;
}
if( FAILED( hr = pdidDevice->SetActionMap( m_pdiaf, NULL, DIDSAM_NOUSER ) ) )
{
DXTRACE_ERR_NOMSGBOX( TEXT("SetActionMap"), hr );
break;
}
}
}
// If we stored DIA_APPFIXED flags earlier, we need to reapply those flags and
// free the allocated memory
if( bResetMappings && pdwAppFixed )
{
for( iAction=0; iAction < m_pdiaf->dwNumActions; iAction++ )
m_pdiaf->rgoAction[iAction].dwFlags |= pdwAppFixed[iAction];
delete [] pdwAppFixed;
}
return hr;
}
//-----------------------------------------------------------------------------
// Name: ConfigureDevices
// Desc:
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::ConfigureDevices( HWND hWnd, IUnknown* pSurface,
VOID* ConfigureDevicesCB,
DWORD dwFlags, LPVOID pvCBParam )
{
HRESULT hr;
DWORD iPlayer;
// Determine how large of a string we'll need to hold all user names
DWORD dwNamesSize = 0;
for( iPlayer=0; iPlayer < m_dwNumUsers; iPlayer++ )
dwNamesSize += lstrlen( m_pUsers[iPlayer]->strPlayerName ) +1;
// Build multi-sz list of user names
TCHAR* strUserNames = new TCHAR[dwNamesSize+1];
// Verify allocation and cycle through user names
if( strUserNames )
{
TCHAR* strTemp = strUserNames;
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
{
lstrcpy( strTemp, m_pUsers[iPlayer]->strPlayerName );
strTemp += lstrlen(strTemp) + 1;
}
lstrcpy( strTemp, TEXT("\0") );
}
// Fill in all the params
DICONFIGUREDEVICESPARAMS dicdp;
ZeroMemory(&dicdp, sizeof(dicdp));
dicdp.dwSize = sizeof(dicdp);
dicdp.dwcFormats = 1;
dicdp.lprgFormats = m_pdiaf;
dicdp.hwnd = hWnd;
dicdp.lpUnkDDSTarget = pSurface;
dicdp.dwcUsers = m_dwNumUsers;
dicdp.lptszUserNames = strUserNames;
// Initialize all the colors here
DICOLORSET dics;
ZeroMemory(&dics, sizeof(DICOLORSET));
dics.dwSize = sizeof(DICOLORSET);
// Set UI color scheme (if not specified it uses defaults)
dicdp.dics.dwSize = sizeof(dics);
dicdp.dics.cTextFore = D3DCOLOR_RGBA(255,255,255,255);
dicdp.dics.cTextHighlight = D3DCOLOR_RGBA(60,191,241,255);
dicdp.dics.cCalloutLine = D3DCOLOR_RGBA(255,255,255,128);
dicdp.dics.cCalloutHighlight= D3DCOLOR_RGBA(60,191,241,255);
dicdp.dics.cBorder = D3DCOLOR_RGBA(140,152,140,128);
dicdp.dics.cControlFill = D3DCOLOR_RGBA(113,0,0,128);
dicdp.dics.cHighlightFill = D3DCOLOR_RGBA(0,0,0,128);
dicdp.dics.cAreaFill = D3DCOLOR_RGBA(0,0,0,128);
if( dwFlags & DICD_EDIT )
{
// Re-enum so we can catch any new devices that have been recently attached
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
m_pUsers[iPlayer]->bFoundDeviceForPlayer = FALSE;
if( FAILED( hr = BuildDeviceList() ) )
{
DXTRACE_ERR_NOMSGBOX( TEXT("BuildDeviceList"), hr );
goto LCleanup;
}
}
// Unacquire the devices so that mouse doesn't
// control the game while in control panel
UnacquireDevices();
if( FAILED( hr = m_pDI->ConfigureDevices( (LPDICONFIGUREDEVICESCALLBACK)ConfigureDevicesCB,
&dicdp, dwFlags, pvCBParam ) ) )
{
DXTRACE_ERR_NOMSGBOX( TEXT("ConfigureDevices"), hr );
goto LCleanup;
}
if( dwFlags & DICD_EDIT )
{
// Update the device ownership
if( FAILED( hr = UpdateDeviceOwnership() ) )
{
DXTRACE_ERR_NOMSGBOX( TEXT("UpdateDeviceOwnership"), hr );
goto LCleanup;
}
// Now save the device keys that are assigned players to registry,
if( FAILED( hr = SaveDeviceOwnershipKeys() ) )
{
DXTRACE_ERR_NOMSGBOX( TEXT("SaveDeviceOwnershipKeys"), hr );
goto LCleanup;
}
// Report an error if there is a player that doesn't not
// have a device assigned
if( FAILED( hr = VerifyAssignment() ) )
goto LCleanup;
// Now that every player has at least one device, build and set
// the action map, and use callback into the app to tell the
// app of the device assignment.
if( FAILED( hr = AddAssignedDevices( FALSE ) ) )
{
DXTRACE_ERR_NOMSGBOX( TEXT("AddAssignedDevices"), hr );
goto LCleanup;
}
}
hr = S_OK;
LCleanup:
if( strUserNames )
delete [] strUserNames;
return hr;
}
//-----------------------------------------------------------------------------
// Name: UpdateDeviceOwnership
// Desc:
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::UpdateDeviceOwnership()
{
DWORD iPlayer;
DWORD iDevice;
// Set all players to not have a device yet
for( iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
m_pUsers[iPlayer]->bFoundDeviceForPlayer = FALSE;
// Set all devices as not assigned to a player
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
m_pDeviceList[iDevice].pPlayerInfo = NULL;
UnacquireDevices();
// Update the device ownership by quering the DIPROP_USERNAME property
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
{
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
TCHAR strPlayerName[MAX_PATH];
DIPROPSTRING dips;
dips.diph.dwSize = sizeof(DIPROPSTRING);
dips.diph.dwHeaderSize = sizeof(DIPROPHEADER);
dips.diph.dwObj = 0; // device property
dips.diph.dwHow = DIPH_DEVICE;
pdidDevice->GetProperty( DIPROP_USERNAME, &dips.diph );
DXUtil_ConvertWideStringToGeneric( strPlayerName, dips.wsz );
if( lstrcmp( strPlayerName, TEXT("") ) != 0 )
{
m_pDeviceList[iDevice].pPlayerInfo = LookupPlayer( strPlayerName );
if( m_pDeviceList[iDevice].pPlayerInfo )
m_pDeviceList[iDevice].pPlayerInfo->bFoundDeviceForPlayer = TRUE;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: UnacquireDevices
// Desc:
//-----------------------------------------------------------------------------
VOID CMultiplayerInputDeviceManager::UnacquireDevices()
{
// Unacquire every device
if( m_pDeviceList )
{
// All devices have been assigned a to a user in
// the new array, so clean up the local array
for( DWORD iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
{
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
// Set the device's coop level
pdidDevice->Unacquire();
}
}
}
//-----------------------------------------------------------------------------
// Name: SetFocus
// Desc: Sets the DirectInput focus to a new HWND
//-----------------------------------------------------------------------------
VOID CMultiplayerInputDeviceManager::SetFocus( HWND hWnd )
{
m_hWnd = hWnd;
if( m_pDeviceList )
{
// All devices have been assigned a to a user in
// the new array, so clean up the local array
for( DWORD iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
{
LPDIRECTINPUTDEVICE8 pdidDevice = m_pDeviceList[iDevice].pdidDevice;
// Set the device's coop level
pdidDevice->Unacquire();
pdidDevice->SetCooperativeLevel( m_hWnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND );
}
}
}
//-----------------------------------------------------------------------------
// Name: GetDevices
// Desc: returns an array of DeviceInfo*'s
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::GetDevices( DeviceInfo** ppDeviceInfo,
DWORD* pdwCount )
{
if( NULL==ppDeviceInfo || NULL==pdwCount )
return E_INVALIDARG;
(*ppDeviceInfo) = m_pDeviceList;
(*pdwCount) = m_dwNumDevices;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: LookupPlayer
// Desc: searchs m_pUsers by player name
//-----------------------------------------------------------------------------
CMultiplayerInputDeviceManager::PlayerInfo* CMultiplayerInputDeviceManager::LookupPlayer( TCHAR* strPlayerName )
{
for( DWORD iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
{
PlayerInfo* pCurPlayer = m_pUsers[iPlayer];
if( lstrcmp( pCurPlayer->strPlayerName, strPlayerName ) == 0 )
return pCurPlayer;
}
return NULL;
}
//-----------------------------------------------------------------------------
// Name: SaveDeviceOwnershipKeys
// Desc: For every device that's assigned to a player, save its device key
// and assigned player to registry.
//-----------------------------------------------------------------------------
HRESULT CMultiplayerInputDeviceManager::SaveDeviceOwnershipKeys()
{
TCHAR strDeviceGuid[40];
DWORD iDevice;
for( iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
{
PlayerInfo* pPlayerInfo = m_pDeviceList[iDevice].pPlayerInfo;
DXUtil_ConvertGUIDToString( &m_pDeviceList[iDevice].didi.guidInstance, strDeviceGuid );
if( pPlayerInfo != NULL )
DXUtil_WriteStringRegKey( m_hKey, strDeviceGuid, pPlayerInfo->strPlayerName );
else
RegDeleteValue( m_hKey, strDeviceGuid );
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DeleteDeviceOwnershipKeys
// Desc: Delete all the ownership keys
//-----------------------------------------------------------------------------
VOID CMultiplayerInputDeviceManager::DeleteDeviceOwnershipKeys()
{
HKEY hKey;
TCHAR *strRegKey;
// Prepare strings to delete the key
strRegKey = _tcsdup( m_strKey );
if( strRegKey == NULL )
return;
TCHAR* strTemp = _tcsrchr( strRegKey, TEXT('\\') );
// Unless the registry path string was malformed, we're ready to delete
// and recreate the key
if( strTemp )
{
*strTemp = 0;
strTemp++;
RegCloseKey( m_hKey );
// Delete the reg key
RegOpenKey( HKEY_CURRENT_USER, strRegKey, &hKey );
SHDeleteKey( hKey, strTemp );
RegCloseKey( hKey );
// Create the key again now that all the subkeys have been deleted
RegCreateKeyEx( HKEY_CURRENT_USER, m_strKey, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&m_hKey, NULL );
}
// Clean up memory allocation
free( strRegKey );
}
//-----------------------------------------------------------------------------
// Name: Cleanup
// Desc:
//-----------------------------------------------------------------------------
VOID CMultiplayerInputDeviceManager::Cleanup()
{
CleanupDeviceList();
if( m_pUsers )
{
for( DWORD iPlayer=0; iPlayer<m_dwNumUsers; iPlayer++ )
SAFE_DELETE( m_pUsers[iPlayer] );
SAFE_DELETE( m_pUsers );
}
// Release() base object
SAFE_RELEASE( m_pDI );
}
//-----------------------------------------------------------------------------
// Name: CleanupDeviceList
// Desc: Clean up the device array
//-----------------------------------------------------------------------------
VOID CMultiplayerInputDeviceManager::CleanupDeviceList()
{
for( DWORD iDevice=0; iDevice<m_dwNumDevices; iDevice++ )
SAFE_RELEASE( m_pDeviceList[iDevice].pdidDevice );
free( m_pDeviceList );
m_pDeviceList = NULL;
m_dwMaxDevices = 0;
m_dwNumDevices = 0;
}

View File

@@ -0,0 +1,116 @@
//-----------------------------------------------------------------------------
// File: MultiDI.h
//
// Desc: Multiple user DirectInput support using action mapping
//
// Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
//-----------------------------------------------------------------------------
#ifndef MULTIDI_H
#define MULTIDI_H
#include <dinput.h>
// E_DIUTILERR_PLAYERWITHOUTDEVICE is returned by the manager class after configuring
// device, and there's a player that hasn't been assigned a device.
#define E_DIUTILERR_PLAYERWITHOUTDEVICE MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,997)
// E_DIUTILERR_DEVICESTAKEN is returned by the manager class when one player
// on the machine has enough RECENT devices to prevent other players from
// playing. This return code is needed because this sample attempts to give
// all RECENT devices to that player.
#define E_DIUTILERR_DEVICESTAKEN MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,998)
// E_DIUTILERR_TOOMANYUSERS is returned by the manager class when the number of
// players exceeds the number of devices present on the system. For example,
// if you ask for 4 players on a machine that only has a keyboard and mouse,
// you're 2 short of what you need.
#define E_DIUTILERR_TOOMANYUSERS MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,999)
//-----------------------------------------------------------------------------
// Name: class CMultiplayerInputDeviceManager
// Desc: Input device manager using DX8 action mapping
//-----------------------------------------------------------------------------
class CMultiplayerInputDeviceManager
{
public:
struct PlayerInfo
{
DWORD dwPlayerIndex; // 0-based player number
TCHAR strPlayerName[MAX_PATH]; // player name
DWORD dwMaxDevices; // max number of elements in pDevices array
DWORD dwNumDevices; // current number of elements in pDevices array
BOOL bFoundDeviceForPlayer; // if a device has been found for this player yet
};
struct DeviceInfo
{
LPDIRECTINPUTDEVICE8 pdidDevice; // dinput device pointer
PlayerInfo* pPlayerInfo; // Player who owns this device
BOOL bRelativeAxis; // TRUE if device is using relative axis
BOOL bMapsPri1Actions; // TRUE if device maps pri 1 actions
BOOL bMapsPri2Actions; // TRUE if device maps pri 2 actions
LPVOID pParam; // app defined pointer assoicated with this device
DIDEVICEINSTANCE didi; // device instance info
};
typedef HRESULT (CALLBACK *LPDIMANAGERCALLBACK)(CMultiplayerInputDeviceManager::PlayerInfo* pPlayerInfo, CMultiplayerInputDeviceManager::DeviceInfo* pDeviceInfo, const DIDEVICEINSTANCE* pdidi, LPVOID);
private:
BOOL m_bCleanupCOM;
HWND m_hWnd;
LPDIRECTINPUT8 m_pDI;
DIACTIONFORMAT* m_pdiaf;
PlayerInfo** m_pUsers;
DWORD m_dwNumUsers;
DeviceInfo* m_pDeviceList;
DWORD m_dwNumDevices;
DWORD m_dwMaxDevices;
LPDIMANAGERCALLBACK m_AddDeviceCallback;
LPVOID m_AddDeviceCallbackParam;
TCHAR* m_strKey;
HKEY m_hKey;
public:
static BOOL CALLBACK StaticEnumSuitableDevicesCB( LPCDIDEVICEINSTANCE pdidi, LPDIRECTINPUTDEVICE8 pdidDevice, DWORD dwFlags, DWORD dwRemainingDevices, VOID* pContext );
static BOOL CALLBACK StaticBuildDeviceListCB( LPCDIDEVICEINSTANCE pdidi, VOID* pContext );
// Device control
BOOL EnumDevice( const DIDEVICEINSTANCE* pdidi, LPDIRECTINPUTDEVICE8 pdidDevice, DWORD dwFlags, DWORD dwDeviceRemaining );
BOOL BuildDeviceListCB( LPCDIDEVICEINSTANCE pdidi );
HRESULT AddDevice( DeviceInfo* pDeviceInfo, BOOL bForceReset );
HRESULT GetDevices( DeviceInfo** ppDeviceInfo, DWORD* pdwNumDevices );
HRESULT ConfigureDevices( HWND hWnd, IUnknown* pSurface, VOID* pCallback, DWORD dwFlags, LPVOID pvCBParam );
DWORD GetNumDevices() { return m_dwNumDevices; }
VOID UnacquireDevices();
VOID SetFocus( HWND hWnd );
PlayerInfo* LookupPlayer( TCHAR* strPlayerName );
HRESULT SaveDeviceOwnershipKeys();
VOID DeleteDeviceOwnershipKeys();
HRESULT UpdateDeviceOwnership();
HRESULT AssignDevices();
HRESULT VerifyAssignment();
HRESULT AddAssignedDevices( BOOL bResetMappings );
HRESULT BuildDeviceList();
VOID CleanupDeviceList();
// Construction
HRESULT SetActionFormat( DIACTIONFORMAT* pdiaf, BOOL bReenumerate, BOOL bResetOwnership, BOOL bResetMappings );
HRESULT Create( HWND hWnd, TCHAR* strUserNames[], DWORD dwNumUsers, DIACTIONFORMAT* pdiaf, LPDIMANAGERCALLBACK AddDeviceCallback, LPVOID pCallbackParam, BOOL bResetOwnership, BOOL bResetMappings );
CMultiplayerInputDeviceManager( TCHAR* strRegKey );
~CMultiplayerInputDeviceManager();
VOID Cleanup();
};
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,53 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by MultiMapper.rc
//
#define IDC_RESET_OWNERSHIP 3
#define IDC_RESET_MAPPINGS 4
#define IDI_MAIN_ICON 101
#define IDD_MAIN 101
#define IDI_MAIN 101
#define IDC_UD_AXIS_STATE_P1 1031
#define IDC_LR_AXIS_STATE_P1 1032
#define IDC_BUTTON_STATE_P1 1034
#define IDC_NUM_PLAYERS_COMBO 1035
#define IDC_PLAYER4_GROUP 1036
#define IDC_PLAYER3_GROUP 1037
#define IDC_PLAYER1_GROUP 1038
#define IDC_PLAYER2_GROUP 1039
#define IDC_UD_AXIS_STATE_P2 1040
#define IDC_LR_AXIS_STATE_P2 1041
#define IDC_BUTTON_STATE_P2 1042
#define IDC_UD_AXIS_STATE_P3 1043
#define IDC_LR_AXIS_STATE_P3 1044
#define IDC_BUTTON_STATE_P3 1045
#define IDC_UD_AXIS_STATE_P4 1046
#define IDC_LR_AXIS_STATE_P4 1047
#define IDC_BUTTON_STATE_P4 1048
#define IDC_WORLD_STATE 1049
#define IDC_TEXT1_P2 1050
#define IDC_TEXT2_P2 1051
#define IDC_TEXT3_P2 1052
#define IDC_TEXT1_P3 1053
#define IDC_TEXT1_P4 1054
#define IDC_TEXT2_P3 1055
#define IDC_TEXT2_P4 1056
#define IDC_TEXT3_P3 1057
#define IDC_TEXT3_P4 1058
#define IDC_DEVICE_ASSIGNED_P1 1069
#define IDC_DEVICE_ASSIGNED_P2 1070
#define IDC_DEVICE_ASSIGNED_P3 1071
#define IDC_DEVICE_ASSIGNED_P4 1072
#define IDM_CONFIGINPUT 40011
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 146
#define _APS_NEXT_COMMAND_VALUE 40013
#define _APS_NEXT_CONTROL_VALUE 1070
#define _APS_NEXT_SYMED_VALUE 102
#endif
#endif